Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add derive macros for Encode, Decode and HasSqlType for Transparent types, weak/strong enums and structs #97

Closed
wants to merge 12 commits into from

Conversation

Freax13
Copy link
Contributor

@Freax13 Freax13 commented Jan 29, 2020

this is an implementation for the ideas in #76

@Freax13 Freax13 requested review from mehcode and abonander and removed request for mehcode January 29, 2020 20:16
@abonander
Copy link
Collaborator

I'm haven't gone through this in detail yet but it's looking pretty good so far, especially if it's passing CI!

However, I'd like to see sqlx-macros/src/derives.rs broken up into files for each derive since it's getting pretty long here:

  • sqlx-macros/src/derives/mod.rs: any shared code for derives (we'd prefer derives/mod.rs over keeping derives.rs since we're all more used to the former from the 2015 edition)
  • sqlx-mcaros/src/derives/encode.rs
  • sqlx-mcaros/src/derives/decode.rs
  • sqlx-mcaros/src/derives/has_sql_type.rs

@thedodd
Copy link
Contributor

thedodd commented Jan 30, 2020

Looked through everything except the sqlx-macros/src/derives.rs module. I'll try to give that module a proper review tomorrow :).

@mehcode
Copy link
Member

mehcode commented Feb 1, 2020

From a quick glance, this looks aweomse @Freax13. I don't have time to give it an in-depth review and play test but I just want to check-in and let you know that we haven't forgotten about it. The plan is to get this in for 0.3.

@mehcode mehcode added this to the 0.3 milestone Feb 1, 2020
Copy link
Collaborator

@abonander abonander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good so far, a few nits though. In general you're using Vec a lot where I think iterator chains would suffice, which introduces intermediate allocations that are probably unnecessary. In some places it's clear you're trying to avoid iterating something twice but that's probably going to be faster than allocation in the general case anyway (since we're dealing with such small datasets).

I'm wary of landing an interface leaning this heavily on OIDs though, even as an initial prototype, and especially without support for migrations. Type mismatches could give some really weird errors that would be a nightmare to debug. I could easily add a query for mapping type names to OIDs in #108 (I'm already doing the inverse there).

sqlx-macros/src/derives/decode.rs Show resolved Hide resolved
let id = &v.ident;
parse_quote!(_ if (#ident :: #id as #repr) == val => Ok(#ident :: #id),)
})
.collect::<Vec<Arm>>();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You actually don't need to .collect() here, quote!() can consume the iterator directly.

let name = id.to_string();
value_arms.push(quote!(#name => Ok(#ident :: #id),));
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this code not work as an iterator chain?

names.push(id.clone().unwrap());
let ty = &field.ty;
reads.push(parse_quote!(
if buf.len() < 8 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The missing indentation really threw me off here. I guess cargo fmt didn't catch it because it's in a macro invocation.

let mut names: Vec<Ident> = Vec::new();
for field in fields {
let id = &field.ident;
names.push(id.clone().unwrap());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can make names a Vec<&Ident> so you don't have to clone here. The references should be able to live long enough.

}
))
}
Ok(tts)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you and @mehcode already discuss what this should do if the postgres feature isn't activated? I would think this should error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, we did not discuss that yet

sqlx-macros/src/derives/encode.rs Show resolved Hide resolved
let size = end - start;

// replaces zeros with actual length
buf[start-4..start].copy_from_slice(&(size as u32).to_be_bytes());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the same thing here as with decode_struct_field().

#(#writes)*
}
fn size_hint(&self) -> usize {
4 + #column_count * (4 + 4) + #(#sizes)+*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like a comment here explaining this arithmetic, for posterity.

sqlx-macros/src/derives/has_sql_type.rs Show resolved Hide resolved
@Freax13 Freax13 requested a review from abonander February 11, 2020 10:54
Copy link
Collaborator

@abonander abonander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, we've been putting a lot of effort into #111.

A few nits and then we'll rebase and merge this into develop.

@@ -32,6 +33,10 @@ impl PgTypeInfo {
pub fn with_oid(oid: u32) -> Self {
Self { id: TypeId(oid) }
}

pub fn oid(&self) -> u32 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd probably rather not expose this in the public API if possible (with custom types we may not always have an OID so this will need to be changed to Option<u32>). Either pub(crate) or #[doc(hidden)].

input,
"structs with zero or more than one unnamed field are not supported",
)),
Data::Struct(DataStruct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to sort all the Data::Struct arms together, then Data::Enum and then Data::Union.

input,
"structs with zero or more than one unnamed field are not supported",
)),
Data::Struct(DataStruct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing re: match arm sorting now.

input,
"structs with zero or more than one unnamed field are not supported",
)),
Data::Struct(DataStruct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: match arm sorting.

@mehcode mehcode mentioned this pull request Mar 17, 2020
6 tasks
@mehcode
Copy link
Member

mehcode commented Mar 18, 2020

Merged in with #134. Thanks again for the awesome contribution.

@mehcode mehcode closed this Mar 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants