Skip to content

Commit 092aa73

Browse files
committed
Abstracted function adding associated (de)serialization types bounds
1 parent 1ff325e commit 092aa73

File tree

1 file changed

+84
-111
lines changed

1 file changed

+84
-111
lines changed

epserde-derive/src/lib.rs

Lines changed: 84 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,77 @@ fn is_phantom_deser_data(ty: &syn::Type) -> bool {
220220
false
221221
}
222222

223+
/// Add trait bounds for associated (de)serialization types based on bounds on
224+
/// type parameters.
225+
fn add_ser_deser_bounds<T: quote::ToTokens>(
226+
derive_input: &DeriveInput,
227+
types_with_generics: &[T],
228+
where_clause_ser: &mut WhereClause,
229+
where_clause_des: &mut WhereClause,
230+
) {
231+
// If there are bounded type parameters which are fields of the
232+
// struct, we need to impose the same bounds on the SerType and on
233+
// the DeserType.
234+
derive_input.generics.params.iter().for_each(|param| {
235+
if let syn::GenericParam::Type(t) = param {
236+
let ty = &t.ident;
237+
238+
// We are just interested in types with bounds that are
239+
// types of fields of the struct.
240+
//
241+
// Note that types_with_generics contains also field types
242+
// *containing* a type parameter, but that just slows down
243+
// the search.
244+
if !t.bounds.is_empty()
245+
&& types_with_generics
246+
.iter()
247+
.any(|x| *ty == x.to_token_stream().to_string())
248+
{
249+
// Add a lifetime so we express bounds on DeserType
250+
let mut lifetimes = Punctuated::new();
251+
lifetimes.push(GenericParam::Lifetime(LifetimeParam {
252+
attrs: vec![],
253+
lifetime: syn::Lifetime::new(
254+
"'epserde_desertype",
255+
proc_macro2::Span::call_site(),
256+
),
257+
colon_token: None,
258+
bounds: Punctuated::new(),
259+
}));
260+
261+
// Add the type bounds to the DeserType
262+
where_clause_des
263+
.predicates
264+
.push(WherePredicate::Type(PredicateType {
265+
lifetimes: Some(BoundLifetimes {
266+
for_token: token::For::default(),
267+
lt_token: token::Lt::default(),
268+
lifetimes,
269+
gt_token: token::Gt::default(),
270+
}),
271+
bounded_ty: syn::parse_quote!(
272+
<#ty as epserde::deser::DeserializeInner>::DeserType<'epserde_desertype>
273+
),
274+
colon_token: token::Colon::default(),
275+
bounds: t.bounds.clone(),
276+
}));
277+
278+
// Add the type bounds to the SerType
279+
where_clause_ser
280+
.predicates
281+
.push(WherePredicate::Type(PredicateType {
282+
lifetimes: None,
283+
bounded_ty: syn::parse_quote!(
284+
<#ty as epserde::ser::SerializeInner>::SerType
285+
),
286+
colon_token: token::Colon::default(),
287+
bounds: t.bounds.clone(),
288+
}));
289+
}
290+
}
291+
});
292+
}
293+
223294
/// Generate an ε-serde implementation for custom types.
224295
///
225296
/// It generates implementations for the traits `CopyType`,
@@ -265,7 +336,7 @@ pub fn epserde_derive(input: TokenStream) -> TokenStream {
265336
..
266337
} = CommonDeriveInput::new(derive_input.clone(), vec![]);
267338

268-
let out = match derive_input.data {
339+
let out = match &derive_input.data {
269340
Data::Struct(s) => {
270341
let mut fields_types = vec![];
271342
let mut fields_names = vec![];
@@ -434,61 +505,12 @@ pub fn epserde_derive(input: TokenStream) -> TokenStream {
434505
}
435506
}
436507
} else {
437-
// If there are bounded type parameters which are fields of the
438-
// struct, we need to impose the same bounds on the SerType and on
439-
// the DeserType.
440-
derive_input.generics.params.iter().for_each(|param| {
441-
if let GenericParam::Type(t) = param {
442-
let ty = &t.ident;
443-
444-
// We are just interested in types with bounds that are
445-
// types of fields of the struct.
446-
//
447-
// Note that types_with_generics contains also field types
448-
// *containing* a type parameter, but that just slows down
449-
// the search.
450-
if ! t.bounds.is_empty() &&
451-
types_with_generics.iter().any(|x| *ty == x.to_token_stream().to_string()) {
452-
453-
let mut lifetimes = Punctuated::new();
454-
// Add a lifetime so we express bounds on DeserType
455-
lifetimes.push(GenericParam::Lifetime(LifetimeParam {
456-
attrs: vec![],
457-
lifetime: syn::Lifetime::new("'epserde_desertype", proc_macro2::Span::call_site()),
458-
colon_token: None,
459-
bounds: Punctuated::new(),
460-
}));
461-
// Add the type bounds to the DeserType
462-
where_clause_des
463-
.predicates
464-
.push(WherePredicate::Type(PredicateType {
465-
lifetimes: Some(BoundLifetimes {
466-
for_token: token::For::default(),
467-
lt_token: token::Lt::default(),
468-
lifetimes,
469-
gt_token: token::Gt::default(),
470-
}),
471-
bounded_ty: syn::parse_quote!(
472-
<#ty as epserde::deser::DeserializeInner>::DeserType<'epserde_desertype>
473-
),
474-
colon_token: token::Colon::default(),
475-
bounds: t.bounds.clone(),
476-
}));
477-
478-
// Add the type bounds to the SerType
479-
where_clause_ser
480-
.predicates
481-
.push(WherePredicate::Type(PredicateType {
482-
lifetimes: None,
483-
bounded_ty: syn::parse_quote!(
484-
<#ty as epserde::ser::SerializeInner>::SerType
485-
),
486-
colon_token: token::Colon::default(),
487-
bounds: t.bounds.clone(),
488-
}));
489-
}
490-
}
491-
});
508+
add_ser_deser_bounds(
509+
&derive_input,
510+
&types_with_generics,
511+
&mut where_clause_ser,
512+
&mut where_clause_des,
513+
);
492514

493515
quote! {
494516
#[automatically_derived]
@@ -817,61 +839,12 @@ pub fn epserde_derive(input: TokenStream) -> TokenStream {
817839
}
818840
}
819841
} else {
820-
// If there are bounded type parameters which are fields of the
821-
// struct, we need to impose the same bounds on the SerType and on
822-
// the DeserType.
823-
derive_input.generics.params.iter().for_each(|param| {
824-
if let GenericParam::Type(t) = param {
825-
let ty = &t.ident;
826-
827-
// We are just interested in types with bounds that are
828-
// types of fields of the struct.
829-
//
830-
// Note that types_with_generics contains also field types
831-
// *containing* a type parameter, but that just slows down
832-
// the search.
833-
if ! t.bounds.is_empty() &&
834-
types_with_generics.iter().any(|x| *ty == x.to_token_stream().to_string()) {
835-
836-
let mut lifetimes = Punctuated::new();
837-
// Add a lifetime so we express bounds on DeserType
838-
lifetimes.push(GenericParam::Lifetime(LifetimeParam {
839-
attrs: vec![],
840-
lifetime: syn::Lifetime::new("'epserde_desertype", proc_macro2::Span::call_site()),
841-
colon_token: None,
842-
bounds: Punctuated::new(),
843-
}));
844-
// Add the type bounds to the DeserType
845-
where_clause_des
846-
.predicates
847-
.push(WherePredicate::Type(PredicateType {
848-
lifetimes: Some(BoundLifetimes {
849-
for_token: token::For::default(),
850-
lt_token: token::Lt::default(),
851-
lifetimes,
852-
gt_token: token::Gt::default(),
853-
}),
854-
bounded_ty: syn::parse_quote!(
855-
<#ty as epserde::deser::DeserializeInner>::DeserType<'epserde_desertype>
856-
),
857-
colon_token: token::Colon::default(),
858-
bounds: t.bounds.clone(),
859-
}));
860-
861-
// Add the type bounds to the SerType
862-
where_clause_ser
863-
.predicates
864-
.push(WherePredicate::Type(PredicateType {
865-
lifetimes: None,
866-
bounded_ty: syn::parse_quote!(
867-
<#ty as epserde::ser::SerializeInner>::SerType
868-
),
869-
colon_token: token::Colon::default(),
870-
bounds: t.bounds.clone(),
871-
}));
872-
}
873-
}
874-
});
842+
add_ser_deser_bounds(
843+
&derive_input,
844+
&types_with_generics,
845+
&mut where_clause_ser,
846+
&mut where_clause_des,
847+
);
875848

876849
quote! {
877850
#[automatically_derived]

0 commit comments

Comments
 (0)