Skip to content

Commit 3827b2e

Browse files
committed
derive bounds on generics
1 parent ed05675 commit 3827b2e

File tree

4 files changed

+73
-12
lines changed

4 files changed

+73
-12
lines changed

postgres-derive-test/src/composites.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{test_type, test_type_asymmetric};
22
use postgres::{Client, NoTls};
3-
use postgres_types::{FromSql, FromSqlOwned, ToSql, WrongType};
3+
use postgres_types::{FromSql, ToSql, WrongType};
44
use std::error::Error;
55

66
#[test]
@@ -242,9 +242,9 @@ fn raw_ident_field() {
242242
#[test]
243243
fn generics() {
244244
#[derive(FromSql, Debug, PartialEq)]
245-
struct InventoryItem<T: FromSqlOwned, U>
245+
struct InventoryItem<T: Clone, U>
246246
where
247-
U: FromSqlOwned,
247+
U: Clone,
248248
{
249249
name: String,
250250
supplier_id: T,
@@ -254,9 +254,9 @@ fn generics() {
254254
// doesn't make sense to implement derived FromSql on a type with borrows
255255
#[derive(ToSql, Debug, PartialEq)]
256256
#[postgres(name = "InventoryItem")]
257-
struct InventoryItemRef<'a, T: 'a + ToSql, U>
257+
struct InventoryItemRef<'a, T: 'a + Clone, U>
258258
where
259-
U: 'a + ToSql,
259+
U: 'a + Clone,
260260
{
261261
name: &'a str,
262262
supplier_id: &'a T,

postgres-derive/src/composites.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use syn::{Error, Ident, Type};
1+
use proc_macro2::Span;
2+
use syn::{
3+
punctuated::Punctuated, Error, GenericParam, Generics, Ident, Path, PathSegment, Type,
4+
TypeParamBound,
5+
};
26

37
use crate::overrides::Overrides;
48

@@ -26,3 +30,23 @@ impl Field {
2630
})
2731
}
2832
}
33+
34+
pub(crate) fn append_generic_bound(mut generics: Generics, bound: &TypeParamBound) -> Generics {
35+
for param in &mut generics.params {
36+
if let GenericParam::Type(param) = param {
37+
param.bounds.push(bound.to_owned())
38+
}
39+
}
40+
generics
41+
}
42+
43+
pub(crate) fn new_derive_path(last: PathSegment) -> Path {
44+
let mut path = Path {
45+
leading_colon: None,
46+
segments: Punctuated::new(),
47+
};
48+
path.segments
49+
.push(Ident::new("postgres_types", Span::call_site()).into());
50+
path.segments.push(last);
51+
path
52+
}

postgres-derive/src/fromsql.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ use proc_macro2::{Span, TokenStream};
22
use quote::{format_ident, quote};
33
use std::iter;
44
use syn::{
5-
Data, DataStruct, DeriveInput, Error, Fields, GenericParam, Generics, Ident, Lifetime,
6-
LifetimeDef,
5+
punctuated::Punctuated, token, AngleBracketedGenericArguments, Data, DataStruct, DeriveInput,
6+
Error, Fields, GenericArgument, GenericParam, Generics, Ident, Lifetime, LifetimeDef,
7+
PathArguments, PathSegment,
78
};
9+
use syn::{TraitBound, TraitBoundModifier, TypeParamBound};
810

911
use crate::accepts;
1012
use crate::composites::Field;
13+
use crate::composites::{append_generic_bound, new_derive_path};
1114
use crate::enums::Variant;
1215
use crate::overrides::Overrides;
1316

@@ -208,13 +211,33 @@ fn composite_body(ident: &Ident, fields: &[Field]) -> TokenStream {
208211
}
209212

210213
fn build_generics(source: &Generics) -> (Generics, Lifetime) {
211-
let mut out = source.to_owned();
212214
// don't worry about lifetime name collisions, it doesn't make sense to derive FromSql on a struct with a lifetime
213215
let lifetime = Lifetime::new("'a", Span::call_site());
216+
217+
let mut out = append_generic_bound(source.to_owned(), &new_fromsql_bound(&lifetime));
214218
out.params.insert(
215219
0,
216220
GenericParam::Lifetime(LifetimeDef::new(lifetime.to_owned())),
217221
);
218222

219223
(out, lifetime)
220224
}
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+
}

postgres-derive/src/tosql.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
use proc_macro2::TokenStream;
1+
use proc_macro2::{Span, TokenStream};
22
use quote::quote;
33
use std::iter;
4-
use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident};
4+
use syn::{
5+
Data, DataStruct, DeriveInput, Error, Fields, Ident, TraitBound, TraitBoundModifier,
6+
TypeParamBound,
7+
};
58

69
use crate::accepts;
710
use crate::composites::Field;
11+
use crate::composites::{append_generic_bound, new_derive_path};
812
use crate::enums::Variant;
913
use crate::overrides::Overrides;
1014

@@ -82,7 +86,8 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result<TokenStream, Error> {
8286
};
8387

8488
let ident = &input.ident;
85-
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
89+
let generics = append_generic_bound(input.generics.to_owned(), &new_tosql_bound());
90+
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
8691
let out = quote! {
8792
impl#impl_generics postgres_types::ToSql for #ident#ty_generics #where_clause {
8893
fn to_sql(&self,
@@ -182,3 +187,12 @@ fn composite_body(fields: &[Field]) -> TokenStream {
182187
std::result::Result::Ok(postgres_types::IsNull::No)
183188
}
184189
}
190+
191+
fn new_tosql_bound() -> TypeParamBound {
192+
TypeParamBound::Trait(TraitBound {
193+
lifetimes: None,
194+
modifier: TraitBoundModifier::None,
195+
paren_token: None,
196+
path: new_derive_path(Ident::new("ToSql", Span::call_site()).into()),
197+
})
198+
}

0 commit comments

Comments
 (0)