diff --git a/Cargo.toml b/Cargo.toml index 9035a5b..0bdeee4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "postgres-derive" version = "0.3.3" +edition = "2018" authors = ["Steven Fackler "] license = "MIT/Apache-2.0" description = "Deriving plugin support for Postgres enum, domain, and composite types" @@ -13,8 +14,9 @@ proc-macro = true test = false [dependencies] +proc-macro2 = "0.3" syn = "0.13" quote = "0.5" [dev-dependencies] -postgres = "0.15.1" +postgres = { git = "https://github.com/sfackler/rust-postgres" } diff --git a/src/accepts.rs b/src/accepts.rs index 04310ee..483d7f0 100644 --- a/src/accepts.rs +++ b/src/accepts.rs @@ -1,9 +1,9 @@ use std::iter; -use syn::Ident; +use syn::{Ident, Lifetime}; use quote::Tokens; -use enums::Variant; -use composites::Field; +use crate::enums::Variant; +use crate::composites::Field; pub fn enum_body(name: &str, variants: &[Variant]) -> Tokens { let num_variants = variants.len(); @@ -34,13 +34,17 @@ pub fn enum_body(name: &str, variants: &[Variant]) -> Tokens { } } -pub fn composite_body(name: &str, trait_: &str, fields: &[Field]) -> Tokens { +pub fn composite_body(name: &str, trait_: &str, lifetime: Option, fields: &[Field]) -> Tokens { let num_fields = fields.len(); let trait_ = Ident::from(trait_); - let traits = iter::repeat(&trait_); let field_names = fields.iter().map(|f| &f.name); let field_types = fields.iter().map(|f| &f.type_); + let trait_tokens = iter::repeat(match lifetime { + Some(lifetime) => quote!{ ::postgres::types::#trait_<#lifetime> }, + None => quote! { ::postgres::types::#trait_ }, + }); + quote! { if type_.name() != #name { return false; @@ -56,7 +60,7 @@ pub fn composite_body(name: &str, trait_: &str, fields: &[Field]) -> Tokens { match f.name() { #( #field_names => { - <#field_types as ::postgres::types::#traits>::accepts(f.type_()) + <#field_types as #trait_tokens>::accepts(f.type_()) } )* _ => false, diff --git a/src/composites.rs b/src/composites.rs index f58cbd9..413b518 100644 --- a/src/composites.rs +++ b/src/composites.rs @@ -1,6 +1,6 @@ use syn::{self, Ident, Type}; -use overrides::Overrides; +use crate::overrides::Overrides; pub struct Field { pub name: String, diff --git a/src/enums.rs b/src/enums.rs index d213e0a..172e378 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -1,6 +1,6 @@ use syn::{self, Ident, Fields}; -use overrides::Overrides; +use crate::overrides::Overrides; pub struct Variant { pub ident: Ident, diff --git a/src/fromsql.rs b/src/fromsql.rs index 40373f3..dd403e5 100644 --- a/src/fromsql.rs +++ b/src/fromsql.rs @@ -1,17 +1,20 @@ +use proc_macro2::Span; use std::iter; -use syn::{self, Ident, DeriveInput, Data, DataStruct, Fields}; +use syn::{self, Ident, DeriveInput, Data, DataStruct, Fields, Lifetime}; use quote::Tokens; -use accepts; -use composites::Field; -use enums::Variant; -use overrides::Overrides; +use crate::accepts; +use crate::composites::Field; +use crate::enums::Variant; +use crate::overrides::Overrides; pub fn expand_derive_fromsql(input: DeriveInput) -> Result { let overrides = Overrides::extract(&input.attrs)?; let name = overrides.name.unwrap_or_else(|| input.ident.to_string()); + let trait_lifetime = Lifetime::new("'from_sql", Span::call_site()); + let (accepts_body, to_sql_body) = match input.data { Data::Enum(ref data) => { let variants = data.variants.iter().map(Variant::parse).collect::, _>>()?; @@ -23,18 +26,18 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { } Data::Struct(DataStruct { fields: Fields::Named(ref fields), .. }) => { let fields = fields.named.iter().map(Field::parse).collect::, _>>()?; - (accepts::composite_body(&name, "FromSql", &fields), - composite_body(&input.ident, &fields)) + (accepts::composite_body(&name, "FromSql", Some(trait_lifetime), &fields), + composite_body(&input.ident, trait_lifetime, &fields)) } _ => { - return Err("#[derive(ToSql)] may only be applied to structs, single field tuple \ + return Err("#[derive(FromSql)] may only be applied to structs, single field tuple \ structs, and enums".to_owned()) } }; let ident = &input.ident; let out = quote! { - impl ::postgres::types::FromSql for #ident { + impl<#trait_lifetime> ::postgres::types::FromSql<#trait_lifetime> for #ident { fn from_sql(_type: &::postgres::types::Type, buf: &[u8]) -> ::std::result::Result<#ident, @@ -85,7 +88,7 @@ fn domain_body(ident: &Ident, field: &syn::Field) -> Tokens { } } -fn composite_body(ident: &Ident, fields: &[Field]) -> Tokens { +fn composite_body(ident: &Ident, lifetime: syn::Lifetime, fields: &[Field]) -> Tokens { let temp_vars = &fields.iter().map(|f| Ident::from(format!("__{}", f.ident))).collect::>(); let field_names = &fields.iter().map(|f| &f.name).collect::>(); let field_idents = &fields.iter().map(|f| &f.ident).collect::>(); @@ -101,13 +104,13 @@ fn composite_body(ident: &Ident, fields: &[Field]) -> Tokens { ::std::result::Result::Ok(num) } - fn read_value(type_: &::postgres::types::Type, - buf: &mut &[u8]) + fn read_value<#lifetime, T>(type_: &::postgres::types::Type, + buf: &#lifetime mut &[u8]) -> ::std::result::Result> - where T: ::postgres::types::FromSql + where T: ::postgres::types::FromSql<#lifetime> { let len = read_be_i32(buf)?; let value = if len < 0 { diff --git a/src/lib.rs b/src/lib.rs index 7f2964a..b163f3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,8 @@ #![recursion_limit = "256"] -extern crate proc_macro; -extern crate syn; #[macro_use] extern crate quote; +extern crate proc_macro; use proc_macro::TokenStream; diff --git a/src/tosql.rs b/src/tosql.rs index 4ea89ab..b2ef4c7 100644 --- a/src/tosql.rs +++ b/src/tosql.rs @@ -2,10 +2,10 @@ use std::iter; use syn::{self, Ident, DeriveInput, Data, DataStruct, Fields}; use quote::Tokens; -use accepts; -use composites::Field; -use enums::Variant; -use overrides::Overrides; +use crate::accepts; +use crate::composites::Field; +use crate::enums::Variant; +use crate::overrides::Overrides; pub fn expand_derive_tosql(input: DeriveInput) -> Result { let overrides = Overrides::extract(&input.attrs)?; @@ -23,7 +23,7 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { } Data::Struct(DataStruct { fields: Fields::Named(ref fields), .. }) => { let fields = fields.named.iter().map(Field::parse).collect::, _>>()?; - (accepts::composite_body(&name, "ToSql", &fields), + (accepts::composite_body(&name, "ToSql", None, &fields), composite_body(&fields)) } _ => { diff --git a/tests/util/mod.rs b/tests/util/mod.rs index f44d98a..9893ae7 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -1,10 +1,10 @@ -use postgres::types::{FromSql, ToSql}; +use postgres::types::{FromSqlOwned, ToSql}; use postgres::Connection; use std::fmt; pub fn test_type(conn: &Connection, sql_type: &str, checks: &[(T, S)]) where - T: PartialEq + FromSql + ToSql, + T: PartialEq + FromSqlOwned + ToSql, S: fmt::Display, { for &(ref val, ref repr) in checks.iter() {