• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::TokenStream;
2 use quote::{quote, ToTokens, TokenStreamExt};
3 use syn::{GenericParam, Generics, Path, TraitBound, TraitBoundModifier, TypeParamBound};
4 
5 use crate::codegen::TraitImpl;
6 use crate::usage::IdentSet;
7 
8 /// Wrapper for "outer From" traits, such as `FromDeriveInput`, `FromVariant`, and `FromField`.
9 pub trait OuterFromImpl<'a> {
10     /// Gets the path of the trait being implemented.
trait_path(&self) -> Path11     fn trait_path(&self) -> Path;
12 
base(&'a self) -> &'a TraitImpl<'a>13     fn base(&'a self) -> &'a TraitImpl<'a>;
14 
trait_bound(&self) -> Path15     fn trait_bound(&self) -> Path {
16         self.trait_path()
17     }
18 
wrap<T: ToTokens>(&'a self, body: T, tokens: &mut TokenStream)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             #[automatically_derived]
31             #[allow(clippy::manual_unwrap_or_default)]
32             impl #impl_generics #trayt for #ty_ident #ty_generics
33                 #where_clause
34             {
35                 #body
36             }
37         ));
38     }
39 }
40 
compute_impl_bounds(bound: Path, mut generics: Generics, applies_to: &IdentSet) -> Generics41 fn compute_impl_bounds(bound: Path, mut generics: Generics, applies_to: &IdentSet) -> Generics {
42     if generics.params.is_empty() {
43         return generics;
44     }
45 
46     let added_bound = TypeParamBound::Trait(TraitBound {
47         paren_token: None,
48         modifier: TraitBoundModifier::None,
49         lifetimes: None,
50         path: bound,
51     });
52 
53     for param in generics.params.iter_mut() {
54         if let GenericParam::Type(ref mut typ) = *param {
55             if applies_to.contains(&typ.ident) {
56                 typ.bounds.push(added_bound.clone());
57             }
58         }
59     }
60 
61     generics
62 }
63