|
1 |
| -use proc_macro2::TokenStream; |
| 1 | +use proc_macro2::{Span, TokenStream}; |
2 | 2 | use quote::{format_ident, quote};
|
3 | 3 | use std::iter;
|
4 |
| -use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident}; |
| 4 | +use syn::{ |
| 5 | + punctuated::Punctuated, token, AngleBracketedGenericArguments, Data, DataStruct, DeriveInput, |
| 6 | + Error, Fields, GenericArgument, GenericParam, Generics, Ident, Lifetime, LifetimeDef, |
| 7 | + PathArguments, PathSegment, |
| 8 | +}; |
| 9 | +use syn::{TraitBound, TraitBoundModifier, TypeParamBound}; |
5 | 10 |
|
6 | 11 | use crate::accepts;
|
7 | 12 | use crate::composites::Field;
|
| 13 | +use crate::composites::{append_generic_bound, new_derive_path}; |
8 | 14 | use crate::enums::Variant;
|
9 | 15 | use crate::overrides::Overrides;
|
10 | 16 |
|
@@ -86,10 +92,13 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result<TokenStream, Error> {
|
86 | 92 | };
|
87 | 93 |
|
88 | 94 | let ident = &input.ident;
|
| 95 | + let (generics, lifetime) = build_generics(&input.generics); |
| 96 | + let (impl_generics, _, _) = generics.split_for_impl(); |
| 97 | + let (_, ty_generics, where_clause) = input.generics.split_for_impl(); |
89 | 98 | let out = quote! {
|
90 |
| - impl<'a> postgres_types::FromSql<'a> for #ident { |
91 |
| - fn from_sql(_type: &postgres_types::Type, buf: &'a [u8]) |
92 |
| - -> std::result::Result<#ident, |
| 99 | + impl#impl_generics postgres_types::FromSql<#lifetime> for #ident#ty_generics #where_clause { |
| 100 | + fn from_sql(_type: &postgres_types::Type, buf: &#lifetime [u8]) |
| 101 | + -> std::result::Result<#ident#ty_generics, |
93 | 102 | std::boxed::Box<dyn std::error::Error +
|
94 | 103 | std::marker::Sync +
|
95 | 104 | std::marker::Send>> {
|
@@ -200,3 +209,35 @@ fn composite_body(ident: &Ident, fields: &[Field]) -> TokenStream {
|
200 | 209 | })
|
201 | 210 | }
|
202 | 211 | }
|
| 212 | + |
| 213 | +fn build_generics(source: &Generics) -> (Generics, Lifetime) { |
| 214 | + // don't worry about lifetime name collisions, it doesn't make sense to derive FromSql on a struct with a lifetime |
| 215 | + let lifetime = Lifetime::new("'a", Span::call_site()); |
| 216 | + |
| 217 | + let mut out = append_generic_bound(source.to_owned(), &new_fromsql_bound(&lifetime)); |
| 218 | + out.params.insert( |
| 219 | + 0, |
| 220 | + GenericParam::Lifetime(LifetimeDef::new(lifetime.to_owned())), |
| 221 | + ); |
| 222 | + |
| 223 | + (out, lifetime) |
| 224 | +} |
| 225 | + |
| 226 | +fn new_fromsql_bound(lifetime: &Lifetime) -> TypeParamBound { |
| 227 | + let mut path_segment: PathSegment = Ident::new("FromSql", Span::call_site()).into(); |
| 228 | + let mut seg_args = Punctuated::new(); |
| 229 | + seg_args.push(GenericArgument::Lifetime(lifetime.to_owned())); |
| 230 | + path_segment.arguments = PathArguments::AngleBracketed(AngleBracketedGenericArguments { |
| 231 | + colon2_token: None, |
| 232 | + lt_token: token::Lt::default(), |
| 233 | + args: seg_args, |
| 234 | + gt_token: token::Gt::default(), |
| 235 | + }); |
| 236 | + |
| 237 | + TypeParamBound::Trait(TraitBound { |
| 238 | + lifetimes: None, |
| 239 | + modifier: TraitBoundModifier::None, |
| 240 | + paren_token: None, |
| 241 | + path: new_derive_path(path_segment), |
| 242 | + }) |
| 243 | +} |
0 commit comments