1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens, TokenStreamExt};
3use syn::{GenericParam, Generics, Path, TraitBound, TraitBoundModifier, TypeParamBound};
4
5use crate::codegen::TraitImpl;
6use crate::usage::IdentSet;
7
8/// Wrapper for "outer From" traits, such as `FromDeriveInput`, `FromVariant`, and `FromField`.
9pub trait OuterFromImpl<'a> {
10 /// Gets the path of the trait being implemented.
11 fn trait_path(&self) -> Path;
12
13 fn base(&'a self) -> &'a TraitImpl<'a>;
14
15 fn trait_bound(&self) -> Path {
16 self.trait_path()
17 }
18
19 fn wrap<T: ToTokens>(&'a self, body: T, tokens: &mut TokenStream) {
20 let base = self.base();
21 let trayt = self.trait_path();
22 let ty_ident = base.ident;
23 // The type parameters used in non-skipped, non-magic fields.
24 // These must impl `FromMeta` unless they have custom bounds.
25 let used = base.used_type_params();
26 let generics = compute_impl_bounds(self.trait_bound(), base.generics.clone(), &used);
27 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
28
29 tokens.append_all(quote!(
30 impl #impl_generics #trayt for #ty_ident #ty_generics
31 #where_clause
32 {
33 #body
34 }
35 ));
36 }
37}
38
39fn compute_impl_bounds(bound: Path, mut generics: Generics, applies_to: &IdentSet) -> Generics {
40 if generics.params.is_empty() {
41 return generics;
42 }
43
44 let added_bound: TypeParamBound = TypeParamBound::Trait(TraitBound {
45 paren_token: None,
46 modifier: TraitBoundModifier::None,
47 lifetimes: None,
48 path: bound,
49 });
50
51 for param: &mut GenericParam in generics.params.iter_mut() {
52 if let GenericParam::Type(ref mut typ: &mut TypeParam) = *param {
53 if applies_to.contains(&typ.ident) {
54 typ.bounds.push(added_bound.clone());
55 }
56 }
57 }
58
59 generics
60}
61