Based on https://github.com/serde-rs/serde/blob/0c6a2bbf794abe966a4763f5b7ff23acb535eb7f/serde_derive/src/bound.rs#L94-L314
(
fields: &[syn::Field],
extra_bound_types: Vec<syn::Type>,
generics: &syn::Generics,
bound: &syn::Path,
)
| 33 | |
| 34 | // Based on https://github.com/serde-rs/serde/blob/0c6a2bbf794abe966a4763f5b7ff23acb535eb7f/serde_derive/src/bound.rs#L94-L314 |
| 35 | fn with_bound( |
| 36 | fields: &[syn::Field], |
| 37 | extra_bound_types: Vec<syn::Type>, |
| 38 | generics: &syn::Generics, |
| 39 | bound: &syn::Path, |
| 40 | ) -> syn::Generics { |
| 41 | struct FindTyParams<'ast> { |
| 42 | // Set of all generic type parameters on the current struct (A, B, C in |
| 43 | // the example). Initialized up front. |
| 44 | all_type_params: HashSet<syn::Ident>, |
| 45 | |
| 46 | // Set of generic type parameters used in fields for which filter |
| 47 | // returns true (A and B in the example). Filled in as the visitor sees |
| 48 | // them. |
| 49 | relevant_type_params: HashSet<syn::Ident>, |
| 50 | |
| 51 | // Fields whose type is an associated type of one of the generic type |
| 52 | // parameters. |
| 53 | associated_type_usage: Vec<&'ast syn::TypePath>, |
| 54 | } |
| 55 | |
| 56 | impl<'ast> FindTyParams<'ast> { |
| 57 | fn visit_field(&mut self, field: &'ast syn::Field) { |
| 58 | if let syn::Type::Path(ty) = ungroup(&field.ty) { |
| 59 | if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() { |
| 60 | if self.all_type_params.contains(&t.ident) { |
| 61 | self.associated_type_usage.push(ty); |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | self.visit_type(&field.ty); |
| 66 | } |
| 67 | |
| 68 | fn visit_path(&mut self, path: &'ast syn::Path) { |
| 69 | if let Some(seg) = path.segments.last() { |
| 70 | if seg.ident == "PhantomData" { |
| 71 | // Hardcoded exception, because PhantomData<T> implements |
| 72 | // Serialize and Deserialize whether or not T implements it. |
| 73 | return; |
| 74 | } |
| 75 | } |
| 76 | if path.leading_colon.is_none() && path.segments.len() == 1 { |
| 77 | let id = &path.segments[0].ident; |
| 78 | if self.all_type_params.contains(id) { |
| 79 | self.relevant_type_params.insert(id.clone()); |
| 80 | } |
| 81 | } |
| 82 | for segment in &path.segments { |
| 83 | self.visit_path_segment(segment); |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | // Everything below is simply traversing the syntax tree. |
| 88 | |
| 89 | fn visit_type(&mut self, ty: &'ast syn::Type) { |
| 90 | match ty { |
| 91 | syn::Type::Array(ty) => self.visit_type(&ty.elem), |
| 92 | syn::Type::BareFn(ty) => { |
no test coverage detected