derive bounds on generics
This commit is contained in:
parent
ed05675888
commit
3827b2e442
@ -1,6 +1,6 @@
|
||||
use crate::{test_type, test_type_asymmetric};
|
||||
use postgres::{Client, NoTls};
|
||||
use postgres_types::{FromSql, FromSqlOwned, ToSql, WrongType};
|
||||
use postgres_types::{FromSql, ToSql, WrongType};
|
||||
use std::error::Error;
|
||||
|
||||
#[test]
|
||||
@ -242,9 +242,9 @@ fn raw_ident_field() {
|
||||
#[test]
|
||||
fn generics() {
|
||||
#[derive(FromSql, Debug, PartialEq)]
|
||||
struct InventoryItem<T: FromSqlOwned, U>
|
||||
struct InventoryItem<T: Clone, U>
|
||||
where
|
||||
U: FromSqlOwned,
|
||||
U: Clone,
|
||||
{
|
||||
name: String,
|
||||
supplier_id: T,
|
||||
@ -254,9 +254,9 @@ fn generics() {
|
||||
// doesn't make sense to implement derived FromSql on a type with borrows
|
||||
#[derive(ToSql, Debug, PartialEq)]
|
||||
#[postgres(name = "InventoryItem")]
|
||||
struct InventoryItemRef<'a, T: 'a + ToSql, U>
|
||||
struct InventoryItemRef<'a, T: 'a + Clone, U>
|
||||
where
|
||||
U: 'a + ToSql,
|
||||
U: 'a + Clone,
|
||||
{
|
||||
name: &'a str,
|
||||
supplier_id: &'a T,
|
||||
|
@ -1,4 +1,8 @@
|
||||
use syn::{Error, Ident, Type};
|
||||
use proc_macro2::Span;
|
||||
use syn::{
|
||||
punctuated::Punctuated, Error, GenericParam, Generics, Ident, Path, PathSegment, Type,
|
||||
TypeParamBound,
|
||||
};
|
||||
|
||||
use crate::overrides::Overrides;
|
||||
|
||||
@ -26,3 +30,23 @@ impl Field {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn append_generic_bound(mut generics: Generics, bound: &TypeParamBound) -> Generics {
|
||||
for param in &mut generics.params {
|
||||
if let GenericParam::Type(param) = param {
|
||||
param.bounds.push(bound.to_owned())
|
||||
}
|
||||
}
|
||||
generics
|
||||
}
|
||||
|
||||
pub(crate) fn new_derive_path(last: PathSegment) -> Path {
|
||||
let mut path = Path {
|
||||
leading_colon: None,
|
||||
segments: Punctuated::new(),
|
||||
};
|
||||
path.segments
|
||||
.push(Ident::new("postgres_types", Span::call_site()).into());
|
||||
path.segments.push(last);
|
||||
path
|
||||
}
|
||||
|
@ -2,12 +2,15 @@ use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use std::iter;
|
||||
use syn::{
|
||||
Data, DataStruct, DeriveInput, Error, Fields, GenericParam, Generics, Ident, Lifetime,
|
||||
LifetimeDef,
|
||||
punctuated::Punctuated, token, AngleBracketedGenericArguments, Data, DataStruct, DeriveInput,
|
||||
Error, Fields, GenericArgument, GenericParam, Generics, Ident, Lifetime, LifetimeDef,
|
||||
PathArguments, PathSegment,
|
||||
};
|
||||
use syn::{TraitBound, TraitBoundModifier, TypeParamBound};
|
||||
|
||||
use crate::accepts;
|
||||
use crate::composites::Field;
|
||||
use crate::composites::{append_generic_bound, new_derive_path};
|
||||
use crate::enums::Variant;
|
||||
use crate::overrides::Overrides;
|
||||
|
||||
@ -208,9 +211,10 @@ fn composite_body(ident: &Ident, fields: &[Field]) -> TokenStream {
|
||||
}
|
||||
|
||||
fn build_generics(source: &Generics) -> (Generics, Lifetime) {
|
||||
let mut out = source.to_owned();
|
||||
// don't worry about lifetime name collisions, it doesn't make sense to derive FromSql on a struct with a lifetime
|
||||
let lifetime = Lifetime::new("'a", Span::call_site());
|
||||
|
||||
let mut out = append_generic_bound(source.to_owned(), &new_fromsql_bound(&lifetime));
|
||||
out.params.insert(
|
||||
0,
|
||||
GenericParam::Lifetime(LifetimeDef::new(lifetime.to_owned())),
|
||||
@ -218,3 +222,22 @@ fn build_generics(source: &Generics) -> (Generics, Lifetime) {
|
||||
|
||||
(out, lifetime)
|
||||
}
|
||||
|
||||
fn new_fromsql_bound(lifetime: &Lifetime) -> TypeParamBound {
|
||||
let mut path_segment: PathSegment = Ident::new("FromSql", Span::call_site()).into();
|
||||
let mut seg_args = Punctuated::new();
|
||||
seg_args.push(GenericArgument::Lifetime(lifetime.to_owned()));
|
||||
path_segment.arguments = PathArguments::AngleBracketed(AngleBracketedGenericArguments {
|
||||
colon2_token: None,
|
||||
lt_token: token::Lt::default(),
|
||||
args: seg_args,
|
||||
gt_token: token::Gt::default(),
|
||||
});
|
||||
|
||||
TypeParamBound::Trait(TraitBound {
|
||||
lifetimes: None,
|
||||
modifier: TraitBoundModifier::None,
|
||||
paren_token: None,
|
||||
path: new_derive_path(path_segment),
|
||||
})
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use std::iter;
|
||||
use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident};
|
||||
use syn::{
|
||||
Data, DataStruct, DeriveInput, Error, Fields, Ident, TraitBound, TraitBoundModifier,
|
||||
TypeParamBound,
|
||||
};
|
||||
|
||||
use crate::accepts;
|
||||
use crate::composites::Field;
|
||||
use crate::composites::{append_generic_bound, new_derive_path};
|
||||
use crate::enums::Variant;
|
||||
use crate::overrides::Overrides;
|
||||
|
||||
@ -82,7 +86,8 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result<TokenStream, Error> {
|
||||
};
|
||||
|
||||
let ident = &input.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let generics = append_generic_bound(input.generics.to_owned(), &new_tosql_bound());
|
||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||
let out = quote! {
|
||||
impl#impl_generics postgres_types::ToSql for #ident#ty_generics #where_clause {
|
||||
fn to_sql(&self,
|
||||
@ -182,3 +187,12 @@ fn composite_body(fields: &[Field]) -> TokenStream {
|
||||
std::result::Result::Ok(postgres_types::IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
fn new_tosql_bound() -> TypeParamBound {
|
||||
TypeParamBound::Trait(TraitBound {
|
||||
lifetimes: None,
|
||||
modifier: TraitBoundModifier::None,
|
||||
paren_token: None,
|
||||
path: new_derive_path(Ident::new("ToSql", Span::call_site()).into()),
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user