1 //! This crate provides helper types for matching against enum variants, and
2 //! extracting bindings to each of the fields in the deriving Struct or Enum in
3 //! a generic way.
4 //!
5 //! If you are writing a `#[derive]` which needs to perform some operation on
6 //! every field, then you have come to the right place!
7 //!
8 //! # Example: `WalkFields`
9 //! ### Trait Implementation
10 //! ```
11 //! pub trait WalkFields: std::any::Any {
12 //!     fn walk_fields(&self, walk: &mut FnMut(&WalkFields));
13 //! }
14 //! impl WalkFields for i32 {
15 //!     fn walk_fields(&self, _walk: &mut FnMut(&WalkFields)) {}
16 //! }
17 //! ```
18 //!
19 //! ### Custom Derive
20 //! ```
21 //! #[macro_use]
22 //! extern crate synstructure;
23 //! #[macro_use]
24 //! extern crate quote;
25 //!
26 //! fn walkfields_derive(s: synstructure::Structure) -> quote::Tokens {
27 //!     let body = s.each(|bi| quote!{
28 //!         walk(#bi)
29 //!     });
30 //!
31 //!     s.bound_impl(quote!(synstructure_test_traits::WalkFields), quote!{
32 //!         fn walk_fields(&self, walk: &mut FnMut(&synstructure_test_traits::WalkFields)) {
33 //!             match *self { #body }
34 //!         }
35 //!     })
36 //! }
37 //! # const _IGNORE: &'static str = stringify!(
38 //! decl_derive!([WalkFields] => walkfields_derive);
39 //! # );
40 //!
41 //! /*
42 //!  * Test Case
43 //!  */
44 //! fn main() {
45 //!     test_derive! {
46 //!         walkfields_derive {
47 //!             enum A<T> {
48 //!                 B(i32, T),
49 //!                 C(i32),
50 //!             }
51 //!         }
52 //!         expands to {
53 //!             #[allow(non_upper_case_globals)]
54 //!             const _DERIVE_synstructure_test_traits_WalkFields_FOR_A: () = {
55 //!                 extern crate synstructure_test_traits;
56 //!                 impl<T> synstructure_test_traits::WalkFields for A<T>
57 //!                     where T: synstructure_test_traits::WalkFields
58 //!                 {
59 //!                     fn walk_fields(&self, walk: &mut FnMut(&synstructure_test_traits::WalkFields)) {
60 //!                         match *self {
61 //!                             A::B(ref __binding_0, ref __binding_1,) => {
62 //!                                 { walk(__binding_0) }
63 //!                                 { walk(__binding_1) }
64 //!                             }
65 //!                             A::C(ref __binding_0,) => {
66 //!                                 { walk(__binding_0) }
67 //!                             }
68 //!                         }
69 //!                     }
70 //!                 }
71 //!             };
72 //!         }
73 //!     }
74 //! }
75 //! ```
76 //!
77 //! # Example: `Interest`
78 //! ### Trait Implementation
79 //! ```
80 //! pub trait Interest {
81 //!     fn interesting(&self) -> bool;
82 //! }
83 //! impl Interest for i32 {
84 //!     fn interesting(&self) -> bool { *self > 0 }
85 //! }
86 //! ```
87 //!
88 //! ### Custom Derive
89 //! ```
90 //! #[macro_use]
91 //! extern crate synstructure;
92 //! #[macro_use]
93 //! extern crate quote;
94 //!
95 //! fn interest_derive(mut s: synstructure::Structure) -> quote::Tokens {
96 //!     let body = s.fold(false, |acc, bi| quote!{
97 //!         #acc || synstructure_test_traits::Interest::interesting(#bi)
98 //!     });
99 //!
100 //!     s.bound_impl(quote!(synstructure_test_traits::Interest), quote!{
101 //!         fn interesting(&self) -> bool {
102 //!             match *self {
103 //!                 #body
104 //!             }
105 //!         }
106 //!     })
107 //! }
108 //! # const _IGNORE: &'static str = stringify!(
109 //! decl_derive!([Interest] => interest_derive);
110 //! # );
111 //!
112 //! /*
113 //!  * Test Case
114 //!  */
115 //! fn main() {
116 //!     test_derive!{
117 //!         interest_derive {
118 //!             enum A<T> {
119 //!                 B(i32, T),
120 //!                 C(i32),
121 //!             }
122 //!         }
123 //!         expands to {
124 //!             #[allow(non_upper_case_globals)]
125 //!             const _DERIVE_synstructure_test_traits_Interest_FOR_A: () = {
126 //!                 extern crate synstructure_test_traits;
127 //!                 impl<T> synstructure_test_traits::Interest for A<T>
128 //!                     where T: synstructure_test_traits::Interest
129 //!                 {
130 //!                     fn interesting(&self) -> bool {
131 //!                         match *self {
132 //!                             A::B(ref __binding_0, ref __binding_1,) => {
133 //!                                 false ||
134 //!                                     synstructure_test_traits::Interest::interesting(__binding_0) ||
135 //!                                     synstructure_test_traits::Interest::interesting(__binding_1)
136 //!                             }
137 //!                             A::C(ref __binding_0,) => {
138 //!                                 false ||
139 //!                                     synstructure_test_traits::Interest::interesting(__binding_0)
140 //!                             }
141 //!                         }
142 //!                     }
143 //!                 }
144 //!             };
145 //!         }
146 //!     }
147 //! }
148 //! ```
149 //!
150 //! For more example usage, consider investigating the `abomonation_derive` crate,
151 //! which makes use of this crate, and is fairly simple.
152 
153 extern crate proc_macro;
154 extern crate proc_macro2;
155 #[macro_use]
156 extern crate quote;
157 extern crate syn;
158 extern crate unicode_xid;
159 
160 use std::collections::HashSet;
161 
162 use syn::{
163     Generics, Ident, Attribute, Field, Fields, Expr, DeriveInput,
164     TraitBound, WhereClause, GenericParam, Data, WherePredicate,
165     TypeParamBound, Type, TypeMacro, FieldsUnnamed, FieldsNamed,
166     PredicateType, TypePath, token, punctuated,
167 };
168 use syn::visit::{self, Visit};
169 
170 use quote::{ToTokens, Tokens};
171 
172 use unicode_xid::UnicodeXID;
173 
174 use proc_macro2::Span;
175 
176 // NOTE: This module has documentation hidden, as it only exports macros (which
177 // always appear in the root of the crate) and helper methods / re-exports used
178 // in the implementation of those macros.
179 #[doc(hidden)]
180 pub mod macros;
181 
182 /// The type of binding to use when generating a pattern.
183 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
184 pub enum BindStyle {
185     /// `x`
186     Move,
187     /// `mut x`
188     MoveMut,
189     /// `ref x`
190     Ref,
191     /// `ref mut x`
192     RefMut,
193 }
194 
195 impl ToTokens for BindStyle {
to_tokens(&self, tokens: &mut Tokens)196     fn to_tokens(&self, tokens: &mut Tokens) {
197         match *self {
198             BindStyle::Move => {}
199             BindStyle::MoveMut => quote_spanned!(Span::call_site() => mut).to_tokens(tokens),
200             BindStyle::Ref => quote_spanned!(Span::call_site() => ref).to_tokens(tokens),
201             BindStyle::RefMut => quote_spanned!(Span::call_site() => ref mut).to_tokens(tokens),
202         }
203     }
204 }
205 
206 // Internal method for merging seen_generics arrays together.
generics_fuse(res: &mut Vec<bool>, new: &[bool])207 fn generics_fuse(res: &mut Vec<bool>, new: &[bool]) {
208     for (i, &flag) in new.iter().enumerate() {
209         if i == res.len() {
210             res.push(false);
211         }
212         if flag {
213             res[i] = true;
214         }
215     }
216 }
217 
218 // Internal method for extracting the set of generics which have been matched
fetch_generics<'a>(set: &[bool], generics: &'a Generics) -> Vec<&'a Ident>219 fn fetch_generics<'a>(set: &[bool], generics: &'a Generics) -> Vec<&'a Ident> {
220     let mut tys = vec![];
221     for (&seen, param) in set.iter().zip(generics.params.iter()) {
222         if seen {
223             match *param {
224                 GenericParam::Type(ref tparam) => tys.push(&tparam.ident),
225                 _ => {}
226             }
227         }
228     }
229     tys
230 }
231 
232 // Internal method for sanitizing an identifier for hygiene purposes.
sanitize_ident(s: &str) -> Ident233 fn sanitize_ident(s: &str) -> Ident {
234     let mut res = String::with_capacity(s.len());
235     for mut c in s.chars() {
236         if ! UnicodeXID::is_xid_continue(c) { c = '_' }
237         // Deduplicate consecutive _ characters.
238         if res.ends_with('_') && c == '_' { continue }
239         res.push(c);
240     }
241     Ident::new(&res, Span::def_site())
242 }
243 
244 /// Information about a specific binding. This contains both an `Ident`
245 /// reference to the given field, and the syn `&'a Field` descriptor for that
246 /// field.
247 ///
248 /// This type supports `quote::ToTokens`, so can be directly used within the
249 /// `quote!` macro. It expands to a reference to the matched field.
250 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
251 pub struct BindingInfo<'a> {
252     /// The name which this BindingInfo will bind to.
253     pub binding: Ident,
254 
255     /// The type of binding which this BindingInfo will create.
256     pub style: BindStyle,
257 
258     field: &'a Field,
259 
260     // These are used to determine which type parameters are avaliable.
261     generics: &'a Generics,
262     seen_generics: Vec<bool>,
263 }
264 
265 impl<'a> ToTokens for BindingInfo<'a> {
to_tokens(&self, tokens: &mut Tokens)266     fn to_tokens(&self, tokens: &mut Tokens) {
267         self.binding.to_tokens(tokens);
268     }
269 }
270 
271 impl<'a> BindingInfo<'a> {
272     /// Returns a reference to the underlying `syn` AST node which this
273     /// `BindingInfo` references
ast(&self) -> &'a Field274     pub fn ast(&self) -> &'a Field {
275         self.field
276     }
277 
278     /// Generates the pattern fragment for this field binding.
279     ///
280     /// # Example
281     /// ```
282     /// # #[macro_use] extern crate quote;
283     /// # extern crate synstructure;
284     /// # #[macro_use] extern crate syn;
285     /// # use synstructure::*;
286     /// # fn main() {
287     /// let di: syn::DeriveInput = parse_quote! {
288     ///     enum A {
289     ///         B{ a: i32, b: i32 },
290     ///         C(u32),
291     ///     }
292     /// };
293     /// let s = Structure::new(&di);
294     ///
295     /// assert_eq!(
296     ///     s.variants()[0].bindings()[0].pat(),
297     ///     quote! {
298     ///         ref __binding_0
299     ///     }
300     /// );
301     /// # }
302     /// ```
pat(&self) -> Tokens303     pub fn pat(&self) -> Tokens {
304         let BindingInfo {
305             ref binding,
306             ref style,
307             ..
308         } = *self;
309         quote!(#style #binding)
310     }
311 
312     /// Returns a list of the type parameters which are referenced in this
313     /// field's type.
314     ///
315     /// # Caveat
316     ///
317     /// If the field contains any macros in type position, all parameters will
318     /// be considered bound. This is because we cannot determine which type
319     /// parameters are bound by type macros.
320     ///
321     /// # Example
322     /// ```
323     /// # #[macro_use] extern crate quote;
324     /// # extern crate synstructure;
325     /// # #[macro_use] extern crate syn;
326     /// # use synstructure::*;
327     /// # fn main() {
328     /// let di: syn::DeriveInput = parse_quote! {
329     ///     struct A<T, U> {
330     ///         a: Option<T>,
331     ///         b: U,
332     ///     }
333     /// };
334     /// let mut s = Structure::new(&di);
335     ///
336     /// assert_eq!(
337     ///     s.variants()[0].bindings()[0].referenced_ty_params(),
338     ///     &[&(syn::Ident::from("T"))]
339     /// );
340     /// # }
341     /// ```
referenced_ty_params(&self) -> Vec<&'a Ident>342     pub fn referenced_ty_params(&self) -> Vec<&'a Ident> {
343         fetch_generics(&self.seen_generics, self.generics)
344     }
345 }
346 
347 /// This type is similar to `syn`'s `Variant` type, however each of the fields
348 /// are references rather than owned. When this is used as the AST for a real
349 /// variant, this struct simply borrows the fields of the `syn::Variant`,
350 /// however this type may also be used as the sole variant for a struct.
351 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
352 pub struct VariantAst<'a> {
353     pub attrs: &'a [Attribute],
354     pub ident: &'a Ident,
355     pub fields: &'a Fields,
356     pub discriminant: &'a Option<(token::Eq, Expr)>,
357 }
358 
359 /// A wrapper around a `syn::DeriveInput`'s variant which provides utilities
360 /// for destructuring `Variant`s with `match` expressions.
361 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
362 pub struct VariantInfo<'a> {
363     pub prefix: Option<&'a Ident>,
364     bindings: Vec<BindingInfo<'a>>,
365     omitted_fields: bool,
366     ast: VariantAst<'a>,
367     generics: &'a Generics,
368 }
369 
370 /// Helper function used by the VariantInfo constructor. Walks all of the types
371 /// in `field` and returns a list of the type parameters from `ty_params` which
372 /// are referenced in the field.
get_ty_params<'a>(field: &Field, generics: &Generics) -> Vec<bool>373 fn get_ty_params<'a>(field: &Field, generics: &Generics) -> Vec<bool> {
374     // Helper type. Discovers all identifiers inside of the visited type,
375     // and calls a callback with them.
376     struct BoundTypeLocator<'a> {
377         result: Vec<bool>,
378         generics: &'a Generics,
379     }
380 
381     impl<'a> Visit<'a> for BoundTypeLocator<'a> {
382         // XXX: This also (intentionally) captures paths like T::SomeType. Is
383         // this desirable?
384         fn visit_ident(&mut self, id: &Ident) {
385             for (idx, i) in self.generics.params.iter().enumerate() {
386                 if let GenericParam::Type(ref tparam) = *i {
387                     if tparam.ident == id {
388                         self.result[idx] = true;
389                     }
390                 }
391             }
392         }
393 
394         fn visit_type_macro(&mut self, x: &'a TypeMacro) {
395             // If we see a type_mac declaration, then we can't know what type parameters
396             // it might be binding, so we presume it binds all of them.
397             for r in &mut self.result {
398                 *r = true;
399             }
400             visit::visit_type_macro(self, x)
401         }
402     }
403 
404     let mut btl = BoundTypeLocator {
405         result: vec![false; generics.params.len()],
406         generics: generics,
407     };
408 
409     btl.visit_type(&field.ty);
410 
411     btl.result
412 }
413 
414 impl<'a> VariantInfo<'a> {
new(ast: VariantAst<'a>, prefix: Option<&'a Ident>, generics: &'a Generics) -> Self415     fn new(ast: VariantAst<'a>, prefix: Option<&'a Ident>, generics: &'a Generics) -> Self {
416         let bindings = match *ast.fields {
417             Fields::Unit => vec![],
418             Fields::Unnamed(FieldsUnnamed { unnamed: ref fields, .. }) |
419             Fields::Named(FieldsNamed { named: ref fields, .. }) => {
420                 fields.into_iter()
421                     .enumerate()
422                     .map(|(i, field)| {
423                         BindingInfo {
424                             // XXX: This has to be call_site to avoid privacy
425                             // when deriving on private fields.
426                             binding: Ident::new(
427                                 &format!("__binding_{}", i),
428                                 Span::call_site(),
429                             ),
430                             style: BindStyle::Ref,
431                             field: field,
432                             generics: generics,
433                             seen_generics: get_ty_params(field, generics),
434                         }
435                     })
436                     .collect::<Vec<_>>()
437             }
438         };
439 
440         VariantInfo {
441             prefix: prefix,
442             bindings: bindings,
443             omitted_fields: false,
444             ast: ast,
445             generics: generics,
446         }
447     }
448 
449     /// Returns a slice of the bindings in this Variant.
bindings(&self) -> &[BindingInfo<'a>]450     pub fn bindings(&self) -> &[BindingInfo<'a>] {
451         &self.bindings
452     }
453 
454     /// Returns a mut slice of the bindings in this Variant.
bindings_mut(&mut self) -> &mut [BindingInfo<'a>]455     pub fn bindings_mut(&mut self) -> &mut [BindingInfo<'a>] {
456         &mut self.bindings
457     }
458 
459     /// Returns a `VariantAst` object which contains references to the
460     /// underlying `syn` AST node which this `Variant` was created from.
ast(&self) -> VariantAst<'a>461     pub fn ast(&self) -> VariantAst<'a> {
462         self.ast
463     }
464 
465     /// True if any bindings were omitted due to a `filter` call.
omitted_bindings(&self) -> bool466     pub fn omitted_bindings(&self) -> bool {
467         self.omitted_fields
468     }
469 
470     /// Generates the match-arm pattern which could be used to match against this Variant.
471     ///
472     /// # Example
473     /// ```
474     /// # #[macro_use] extern crate quote;
475     /// # extern crate synstructure;
476     /// # #[macro_use] extern crate syn;
477     /// # use synstructure::*;
478     /// # fn main() {
479     /// let di: syn::DeriveInput = parse_quote! {
480     ///     enum A {
481     ///         B(i32, i32),
482     ///         C(u32),
483     ///     }
484     /// };
485     /// let s = Structure::new(&di);
486     ///
487     /// assert_eq!(
488     ///     s.variants()[0].pat(),
489     ///     quote!{
490     ///         A::B(ref __binding_0, ref __binding_1,)
491     ///     }
492     /// );
493     /// # }
494     /// ```
pat(&self) -> Tokens495     pub fn pat(&self) -> Tokens {
496         let mut t = Tokens::new();
497         if let Some(prefix) = self.prefix {
498             prefix.to_tokens(&mut t);
499             quote!(::).to_tokens(&mut t);
500         }
501         self.ast.ident.to_tokens(&mut t);
502         match *self.ast.fields {
503             Fields::Unit => {
504                 assert!(self.bindings.len() == 0);
505             }
506             Fields::Unnamed(..) => {
507                 token::Paren(Span::call_site()).surround(&mut t, |t| {
508                     for binding in &self.bindings {
509                         binding.pat().to_tokens(t);
510                         quote!(,).to_tokens(t);
511                     }
512                     if self.omitted_fields {
513                         quote!(..).to_tokens(t);
514                     }
515                 })
516             }
517             Fields::Named(..) => {
518                 token::Brace(Span::call_site()).surround(&mut t, |t| {
519                     for binding in &self.bindings {
520                         binding.field.ident.to_tokens(t);
521                         quote!(:).to_tokens(t);
522                         binding.pat().to_tokens(t);
523                         quote!(,).to_tokens(t);
524                     }
525                     if self.omitted_fields {
526                         quote!(..).to_tokens(t);
527                     }
528                 })
529             }
530         }
531         t
532     }
533 
534     /// Generates the token stream required to construct the current variant.
535     ///
536     /// The init array initializes each of the fields in the order they are
537     /// written in `variant.ast().fields`.
538     ///
539     /// # Example
540     /// ```
541     /// # #[macro_use] extern crate quote;
542     /// # extern crate synstructure;
543     /// # #[macro_use] extern crate syn;
544     /// # use synstructure::*;
545     /// # fn main() {
546     /// let di: syn::DeriveInput = parse_quote! {
547     ///     enum A {
548     ///         B(usize, usize),
549     ///         C{ v: usize },
550     ///     }
551     /// };
552     /// let s = Structure::new(&di);
553     ///
554     /// assert_eq!(
555     ///     s.variants()[0].construct(|_, i| quote!(#i)),
556     ///
557     ///     quote!{
558     ///         A::B(0usize, 1usize,)
559     ///     }
560     /// );
561     ///
562     /// assert_eq!(
563     ///     s.variants()[1].construct(|_, i| quote!(#i)),
564     ///
565     ///     quote!{
566     ///         A::C{ v: 0usize, }
567     ///     }
568     /// );
569     /// # }
570     /// ```
construct<F, T>(&self, mut func: F) -> Tokens where F: FnMut(&Field, usize) -> T, T: ToTokens,571     pub fn construct<F, T>(&self, mut func: F) -> Tokens
572     where
573         F: FnMut(&Field, usize) -> T,
574         T: ToTokens,
575     {
576         let mut t = Tokens::new();
577         if let Some(prefix) = self.prefix {
578             quote!(#prefix ::).to_tokens(&mut t);
579         }
580         self.ast.ident.to_tokens(&mut t);
581 
582         match *self.ast.fields {
583             Fields::Unit => (),
584             Fields::Unnamed(FieldsUnnamed { ref unnamed, .. }) => {
585                 token::Paren::default().surround(&mut t, |t| {
586                     for (i, field) in unnamed.into_iter().enumerate() {
587                         func(field, i).to_tokens(t);
588                         quote!(,).to_tokens(t);
589                     }
590                 })
591             }
592             Fields::Named(FieldsNamed { ref named, .. }) => {
593                 token::Brace::default().surround(&mut t, |t| {
594                     for (i, field) in named.into_iter().enumerate() {
595                         field.ident.to_tokens(t);
596                         quote!(:).to_tokens(t);
597                         func(field, i).to_tokens(t);
598                         quote!(,).to_tokens(t);
599                     }
600                 })
601             }
602         }
603         t
604     }
605 
606     /// Runs the passed-in function once for each bound field, passing in a `BindingInfo`.
607     /// and generating a `match` arm which evaluates the returned tokens.
608     ///
609     /// This method will ignore fields which are ignored through the `filter`
610     /// method.
611     ///
612     /// # Example
613     /// ```
614     /// # #[macro_use] extern crate quote;
615     /// # extern crate synstructure;
616     /// # #[macro_use] extern crate syn;
617     /// # use synstructure::*;
618     /// # fn main() {
619     /// let di: syn::DeriveInput = parse_quote! {
620     ///     enum A {
621     ///         B(i32, i32),
622     ///         C(u32),
623     ///     }
624     /// };
625     /// let s = Structure::new(&di);
626     ///
627     /// assert_eq!(
628     ///     s.variants()[0].each(|bi| quote!(println!("{:?}", #bi))),
629     ///
630     ///     quote!{
631     ///         A::B(ref __binding_0, ref __binding_1,) => {
632     ///             { println!("{:?}", __binding_0) }
633     ///             { println!("{:?}", __binding_1) }
634     ///         }
635     ///     }
636     /// );
637     /// # }
638     /// ```
each<F, R>(&self, mut f: F) -> Tokens where F: FnMut(&BindingInfo) -> R, R: ToTokens,639     pub fn each<F, R>(&self, mut f: F) -> Tokens
640     where
641         F: FnMut(&BindingInfo) -> R,
642         R: ToTokens,
643     {
644         let pat = self.pat();
645         let mut body = Tokens::new();
646         for binding in &self.bindings {
647             token::Brace::default().surround(&mut body, |body| {
648                 f(binding).to_tokens(body);
649             });
650         }
651         quote!(#pat => { #body })
652     }
653 
654     /// Runs the passed-in function once for each bound field, passing in the
655     /// result of the previous call, and a `BindingInfo`. generating a `match`
656     /// arm which evaluates to the resulting tokens.
657     ///
658     /// This method will ignore fields which are ignored through the `filter`
659     /// method.
660     ///
661     /// # Example
662     /// ```
663     /// # #[macro_use] extern crate quote;
664     /// # extern crate synstructure;
665     /// # #[macro_use] extern crate syn;
666     /// # use synstructure::*;
667     /// # fn main() {
668     /// let di: syn::DeriveInput = parse_quote! {
669     ///     enum A {
670     ///         B(i32, i32),
671     ///         C(u32),
672     ///     }
673     /// };
674     /// let s = Structure::new(&di);
675     ///
676     /// assert_eq!(
677     ///     s.variants()[0].fold(quote!(0), |acc, bi| quote!(#acc + #bi)),
678     ///
679     ///     quote!{
680     ///         A::B(ref __binding_0, ref __binding_1,) => {
681     ///             0 + __binding_0 + __binding_1
682     ///         }
683     ///     }
684     /// );
685     /// # }
686     /// ```
fold<F, I, R>(&self, init: I, mut f: F) -> Tokens where F: FnMut(Tokens, &BindingInfo) -> R, I: ToTokens, R: ToTokens,687     pub fn fold<F, I, R>(&self, init: I, mut f: F) -> Tokens
688     where
689         F: FnMut(Tokens, &BindingInfo) -> R,
690         I: ToTokens,
691         R: ToTokens,
692     {
693         let pat = self.pat();
694         let body = self.bindings.iter().fold(quote!(#init), |i, bi| {
695             let r = f(i, bi);
696             quote!(#r)
697         });
698         quote!(#pat => { #body })
699     }
700 
701     /// Filter the bindings created by this `Variant` object. This has 2 effects:
702     ///
703     /// * The bindings will no longer appear in match arms generated by methods
704     ///   on this `Variant` or its subobjects.
705     ///
706     /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl`
707     ///   method only consider type parameters referenced in the types of
708     ///   non-filtered fields.
709     ///
710     /// # Example
711     /// ```
712     /// # #[macro_use] extern crate quote;
713     /// # extern crate synstructure;
714     /// # #[macro_use] extern crate syn;
715     /// # use synstructure::*;
716     /// # fn main() {
717     /// let di: syn::DeriveInput = parse_quote! {
718     ///     enum A {
719     ///         B{ a: i32, b: i32 },
720     ///         C{ a: u32 },
721     ///     }
722     /// };
723     /// let mut s = Structure::new(&di);
724     ///
725     /// s.variants_mut()[0].filter(|bi| {
726     ///     bi.ast().ident == Some("b".into())
727     /// });
728     ///
729     /// assert_eq!(
730     ///     s.each(|bi| quote!(println!("{:?}", #bi))),
731     ///
732     ///     quote!{
733     ///         A::B{ b: ref __binding_1, .. } => {
734     ///             { println!("{:?}", __binding_1) }
735     ///         }
736     ///         A::C{ a: ref __binding_0, } => {
737     ///             { println!("{:?}", __binding_0) }
738     ///         }
739     ///     }
740     /// );
741     /// # }
742     /// ```
filter<F>(&mut self, f: F) -> &mut Self where F: FnMut(&BindingInfo) -> bool,743     pub fn filter<F>(&mut self, f: F) -> &mut Self
744     where
745         F: FnMut(&BindingInfo) -> bool,
746     {
747         let before_len = self.bindings.len();
748         self.bindings.retain(f);
749         if self.bindings.len() != before_len {
750             self.omitted_fields = true;
751         }
752         self
753     }
754 
755     /// Remove the binding at the given index.
756     ///
757     /// # Panics
758     ///
759     /// Panics if the index is out of range.
remove_binding(&mut self, idx: usize) -> &mut Self760     pub fn remove_binding(&mut self, idx: usize) -> &mut Self {
761         self.bindings.remove(idx);
762         self.omitted_fields = true;
763         self
764     }
765 
766     /// Updates the `BindStyle` for each of the passed-in fields by calling the
767     /// passed-in function for each `BindingInfo`.
768     ///
769     /// # Example
770     /// ```
771     /// # #[macro_use] extern crate quote;
772     /// # extern crate synstructure;
773     /// # #[macro_use] extern crate syn;
774     /// # use synstructure::*;
775     /// # fn main() {
776     /// let di: syn::DeriveInput = parse_quote! {
777     ///     enum A {
778     ///         B(i32, i32),
779     ///         C(u32),
780     ///     }
781     /// };
782     /// let mut s = Structure::new(&di);
783     ///
784     /// s.variants_mut()[0].bind_with(|bi| BindStyle::RefMut);
785     ///
786     /// assert_eq!(
787     ///     s.each(|bi| quote!(println!("{:?}", #bi))),
788     ///
789     ///     quote!{
790     ///         A::B(ref mut __binding_0, ref mut __binding_1,) => {
791     ///             { println!("{:?}", __binding_0) }
792     ///             { println!("{:?}", __binding_1) }
793     ///         }
794     ///         A::C(ref __binding_0,) => {
795     ///             { println!("{:?}", __binding_0) }
796     ///         }
797     ///     }
798     /// );
799     /// # }
800     /// ```
bind_with<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&BindingInfo) -> BindStyle,801     pub fn bind_with<F>(&mut self, mut f: F) -> &mut Self
802     where
803         F: FnMut(&BindingInfo) -> BindStyle,
804     {
805         for binding in &mut self.bindings {
806             binding.style = f(&binding);
807         }
808         self
809     }
810 
811     /// Updates the binding name for each fo the passed-in fields by calling the
812     /// passed-in function for each `BindingInfo`.
813     ///
814     /// The function will be called with the `BindingInfo` and its index in the
815     /// enclosing variant.
816     ///
817     /// The default name is `__binding_{}` where `{}` is replaced with an
818     /// increasing number.
819     ///
820     /// # Example
821     /// ```
822     /// # #[macro_use] extern crate quote;
823     /// # extern crate synstructure;
824     /// # #[macro_use] extern crate syn;
825     /// # use synstructure::*;
826     /// # fn main() {
827     /// let di: syn::DeriveInput = parse_quote! {
828     ///     enum A {
829     ///         B{ a: i32, b: i32 },
830     ///         C{ a: u32 },
831     ///     }
832     /// };
833     /// let mut s = Structure::new(&di);
834     ///
835     /// s.variants_mut()[0].binding_name(|bi, i| bi.ident.clone().unwrap());
836     ///
837     /// assert_eq!(
838     ///     s.each(|bi| quote!(println!("{:?}", #bi))),
839     ///
840     ///     quote!{
841     ///         A::B{ a: ref a, b: ref b, } => {
842     ///             { println!("{:?}", a) }
843     ///             { println!("{:?}", b) }
844     ///         }
845     ///         A::C{ a: ref __binding_0, } => {
846     ///             { println!("{:?}", __binding_0) }
847     ///         }
848     ///     }
849     /// );
850     /// # }
851     /// ```
binding_name<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&Field, usize) -> Ident,852     pub fn binding_name<F>(&mut self, mut f: F) -> &mut Self
853     where
854         F: FnMut(&Field, usize) -> Ident,
855     {
856         for (it, binding) in self.bindings.iter_mut().enumerate() {
857             binding.binding = f(binding.field, it);
858         }
859         self
860     }
861 
862     /// Returns a list of the type parameters which are referenced in this
863     /// field's type.
864     ///
865     /// # Caveat
866     ///
867     /// If the field contains any macros in type position, all parameters will
868     /// be considered bound. This is because we cannot determine which type
869     /// parameters are bound by type macros.
870     ///
871     /// # Example
872     /// ```
873     /// # #[macro_use] extern crate quote;
874     /// # extern crate synstructure;
875     /// # #[macro_use] extern crate syn;
876     /// # use synstructure::*;
877     /// # fn main() {
878     /// let di: syn::DeriveInput = parse_quote! {
879     ///     struct A<T, U> {
880     ///         a: Option<T>,
881     ///         b: U,
882     ///     }
883     /// };
884     /// let mut s = Structure::new(&di);
885     ///
886     /// assert_eq!(
887     ///     s.variants()[0].bindings()[0].referenced_ty_params(),
888     ///     &[&(syn::Ident::from("T"))]
889     /// );
890     /// # }
891     /// ```
referenced_ty_params(&self) -> Vec<&'a Ident>892     pub fn referenced_ty_params(&self) -> Vec<&'a Ident> {
893         let mut flags = Vec::new();
894         for binding in &self.bindings {
895             generics_fuse(&mut flags, &binding.seen_generics);
896         }
897         fetch_generics(&flags, self.generics)
898     }
899 }
900 
901 /// A wrapper around a `syn::DeriveInput` which provides utilities for creating
902 /// custom derive trait implementations.
903 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
904 pub struct Structure<'a> {
905     variants: Vec<VariantInfo<'a>>,
906     omitted_variants: bool,
907     ast: &'a DeriveInput,
908 }
909 
910 impl<'a> Structure<'a> {
911     /// Create a new `Structure` with the variants and fields from the passed-in
912     /// `DeriveInput`.
new(ast: &'a DeriveInput) -> Self913     pub fn new(ast: &'a DeriveInput) -> Self {
914         let variants = match ast.data {
915             Data::Enum(ref data) => {
916                 (&data.variants).into_iter()
917                     .map(|v| {
918                         VariantInfo::new(
919                             VariantAst {
920                                 attrs: &v.attrs,
921                                 ident: &v.ident,
922                                 fields: &v.fields,
923                                 discriminant: &v.discriminant
924                             },
925                             Some(&ast.ident),
926                             &ast.generics,
927                         )
928                     })
929                     .collect::<Vec<_>>()
930             }
931             Data::Struct(ref data) => {
932                 // SAFETY NOTE: Normally putting an `Expr` in static storage
933                 // wouldn't be safe, because it could contain `Term` objects
934                 // which use thread-local interning. However, this static always
935                 // contains the value `None`. Thus, it will never contain any
936                 // unsafe values.
937                 struct UnsafeMakeSync(Option<(token::Eq, Expr)>);
938                 unsafe impl Sync for UnsafeMakeSync {}
939                 static NONE_DISCRIMINANT: UnsafeMakeSync = UnsafeMakeSync(None);
940 
941                 vec![
942                     VariantInfo::new(
943                         VariantAst {
944                             attrs: &ast.attrs,
945                             ident: &ast.ident,
946                             fields: &data.fields,
947                             discriminant: &NONE_DISCRIMINANT.0,
948                         },
949                         None,
950                         &ast.generics,
951                     ),
952                 ]
953             }
954             Data::Union(_) => {
955                 panic!("synstructure does not handle untagged unions \
956                     (https://github.com/mystor/synstructure/issues/6)");
957             }
958         };
959 
960         Structure {
961             variants: variants,
962             omitted_variants: false,
963             ast: ast,
964         }
965     }
966 
967     /// Returns a slice of the variants in this Structure.
variants(&self) -> &[VariantInfo<'a>]968     pub fn variants(&self) -> &[VariantInfo<'a>] {
969         &self.variants
970     }
971 
972     /// Returns a mut slice of the variants in this Structure.
variants_mut(&mut self) -> &mut [VariantInfo<'a>]973     pub fn variants_mut(&mut self) -> &mut [VariantInfo<'a>] {
974         &mut self.variants
975     }
976 
977     /// Returns a reference to the underlying `syn` AST node which this
978     /// `Structure` was created from.
ast(&self) -> &'a DeriveInput979     pub fn ast(&self) -> &'a DeriveInput {
980         self.ast
981     }
982 
983     /// True if any variants were omitted due to a `filter_variants` call.
omitted_variants(&self) -> bool984     pub fn omitted_variants(&self) -> bool {
985         self.omitted_variants
986     }
987 
988     /// Runs the passed-in function once for each bound field, passing in a `BindingInfo`.
989     /// and generating `match` arms which evaluate the returned tokens.
990     ///
991     /// This method will ignore variants or fields which are ignored through the
992     /// `filter` and `filter_variant` methods.
993     ///
994     /// # Example
995     /// ```
996     /// # #[macro_use] extern crate quote;
997     /// # extern crate synstructure;
998     /// # #[macro_use] extern crate syn;
999     /// # use synstructure::*;
1000     /// # fn main() {
1001     /// let di: syn::DeriveInput = parse_quote! {
1002     ///     enum A {
1003     ///         B(i32, i32),
1004     ///         C(u32),
1005     ///     }
1006     /// };
1007     /// let s = Structure::new(&di);
1008     ///
1009     /// assert_eq!(
1010     ///     s.each(|bi| quote!(println!("{:?}", #bi))),
1011     ///
1012     ///     quote!{
1013     ///         A::B(ref __binding_0, ref __binding_1,) => {
1014     ///             { println!("{:?}", __binding_0) }
1015     ///             { println!("{:?}", __binding_1) }
1016     ///         }
1017     ///         A::C(ref __binding_0,) => {
1018     ///             { println!("{:?}", __binding_0) }
1019     ///         }
1020     ///     }
1021     /// );
1022     /// # }
1023     /// ```
each<F, R>(&self, mut f: F) -> Tokens where F: FnMut(&BindingInfo) -> R, R: ToTokens,1024     pub fn each<F, R>(&self, mut f: F) -> Tokens
1025     where
1026         F: FnMut(&BindingInfo) -> R,
1027         R: ToTokens,
1028     {
1029         let mut t = Tokens::new();
1030         for variant in &self.variants {
1031             variant.each(&mut f).to_tokens(&mut t);
1032         }
1033         if self.omitted_variants {
1034             quote!(_ => {}).to_tokens(&mut t);
1035         }
1036         t
1037     }
1038 
1039     /// Runs the passed-in function once for each bound field, passing in the
1040     /// result of the previous call, and a `BindingInfo`. generating `match`
1041     /// arms which evaluate to the resulting tokens.
1042     ///
1043     /// This method will ignore variants or fields which are ignored through the
1044     /// `filter` and `filter_variant` methods.
1045     ///
1046     /// If a variant has been ignored, it will return the `init` value.
1047     ///
1048     /// # Example
1049     /// ```
1050     /// # #[macro_use] extern crate quote;
1051     /// # extern crate synstructure;
1052     /// # #[macro_use] extern crate syn;
1053     /// # use synstructure::*;
1054     /// # fn main() {
1055     /// let di: syn::DeriveInput = parse_quote! {
1056     ///     enum A {
1057     ///         B(i32, i32),
1058     ///         C(u32),
1059     ///     }
1060     /// };
1061     /// let s = Structure::new(&di);
1062     ///
1063     /// assert_eq!(
1064     ///     s.fold(quote!(0), |acc, bi| quote!(#acc + #bi)),
1065     ///
1066     ///     quote!{
1067     ///         A::B(ref __binding_0, ref __binding_1,) => {
1068     ///             0 + __binding_0 + __binding_1
1069     ///         }
1070     ///         A::C(ref __binding_0,) => {
1071     ///             0 + __binding_0
1072     ///         }
1073     ///     }
1074     /// );
1075     /// # }
1076     /// ```
fold<F, I, R>(&self, init: I, mut f: F) -> Tokens where F: FnMut(Tokens, &BindingInfo) -> R, I: ToTokens, R: ToTokens,1077     pub fn fold<F, I, R>(&self, init: I, mut f: F) -> Tokens
1078     where
1079         F: FnMut(Tokens, &BindingInfo) -> R,
1080         I: ToTokens,
1081         R: ToTokens,
1082     {
1083         let mut t = Tokens::new();
1084         for variant in &self.variants {
1085             variant.fold(&init, &mut f).to_tokens(&mut t);
1086         }
1087         if self.omitted_variants {
1088             quote!(_ => { #init }).to_tokens(&mut t);
1089         }
1090         t
1091     }
1092 
1093     /// Runs the passed-in function once for each variant, passing in a
1094     /// `VariantInfo`. and generating `match` arms which evaluate the returned
1095     /// tokens.
1096     ///
1097     /// This method will ignore variants and not bind fields which are ignored
1098     /// through the `filter` and `filter_variant` methods.
1099     ///
1100     /// # Example
1101     /// ```
1102     /// # #[macro_use] extern crate quote;
1103     /// # extern crate synstructure;
1104     /// # #[macro_use] extern crate syn;
1105     /// # use synstructure::*;
1106     /// # fn main() {
1107     /// let di: syn::DeriveInput = parse_quote! {
1108     ///     enum A {
1109     ///         B(i32, i32),
1110     ///         C(u32),
1111     ///     }
1112     /// };
1113     /// let s = Structure::new(&di);
1114     ///
1115     /// assert_eq!(
1116     ///     s.each_variant(|v| {
1117     ///         let name = &v.ast().ident;
1118     ///         quote!(println!(stringify!(#name)))
1119     ///     }),
1120     ///
1121     ///     quote!{
1122     ///         A::B(ref __binding_0, ref __binding_1,) => {
1123     ///             println!(stringify!(B))
1124     ///         }
1125     ///         A::C(ref __binding_0,) => {
1126     ///             println!(stringify!(C))
1127     ///         }
1128     ///     }
1129     /// );
1130     /// # }
1131     /// ```
each_variant<F, R>(&self, mut f: F) -> Tokens where F: FnMut(&VariantInfo) -> R, R: ToTokens,1132     pub fn each_variant<F, R>(&self, mut f: F) -> Tokens
1133     where
1134         F: FnMut(&VariantInfo) -> R,
1135         R: ToTokens,
1136     {
1137         let mut t = Tokens::new();
1138         for variant in &self.variants {
1139             let pat = variant.pat();
1140             let body = f(variant);
1141             quote!(#pat => { #body }).to_tokens(&mut t);
1142         }
1143         if self.omitted_variants {
1144             quote!(_ => {}).to_tokens(&mut t);
1145         }
1146         t
1147     }
1148 
1149     /// Filter the bindings created by this `Structure` object. This has 2 effects:
1150     ///
1151     /// * The bindings will no longer appear in match arms generated by methods
1152     ///   on this `Structure` or its subobjects.
1153     ///
1154     /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl`
1155     ///   method only consider type parameters referenced in the types of
1156     ///   non-filtered fields.
1157     ///
1158     /// # Example
1159     /// ```
1160     /// # #[macro_use] extern crate quote;
1161     /// # extern crate synstructure;
1162     /// # #[macro_use] extern crate syn;
1163     /// # use synstructure::*;
1164     /// # fn main() {
1165     /// let di: syn::DeriveInput = parse_quote! {
1166     ///     enum A {
1167     ///         B{ a: i32, b: i32 },
1168     ///         C{ a: u32 },
1169     ///     }
1170     /// };
1171     /// let mut s = Structure::new(&di);
1172     ///
1173     /// s.filter(|bi| { bi.ast().ident == Some("a".into()) });
1174     ///
1175     /// assert_eq!(
1176     ///     s.each(|bi| quote!(println!("{:?}", #bi))),
1177     ///
1178     ///     quote!{
1179     ///         A::B{ a: ref __binding_0, .. } => {
1180     ///             { println!("{:?}", __binding_0) }
1181     ///         }
1182     ///         A::C{ a: ref __binding_0, } => {
1183     ///             { println!("{:?}", __binding_0) }
1184     ///         }
1185     ///     }
1186     /// );
1187     /// # }
1188     /// ```
filter<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&BindingInfo) -> bool,1189     pub fn filter<F>(&mut self, mut f: F) -> &mut Self
1190     where
1191         F: FnMut(&BindingInfo) -> bool,
1192     {
1193         for variant in &mut self.variants {
1194             variant.filter(&mut f);
1195         }
1196         self
1197     }
1198 
1199     /// Filter the variants matched by this `Structure` object. This has 2 effects:
1200     ///
1201     /// * Match arms destructuring these variants will no longer be generated by
1202     ///   methods on this `Structure`
1203     ///
1204     /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl`
1205     ///   method only consider type parameters referenced in the types of
1206     ///   fields in non-fitered variants.
1207     ///
1208     /// # Example
1209     /// ```
1210     /// # #[macro_use] extern crate quote;
1211     /// # extern crate synstructure;
1212     /// # #[macro_use] extern crate syn;
1213     /// # use synstructure::*;
1214     /// # fn main() {
1215     /// let di: syn::DeriveInput = parse_quote! {
1216     ///     enum A {
1217     ///         B(i32, i32),
1218     ///         C(u32),
1219     ///     }
1220     /// };
1221     ///
1222     /// let mut s = Structure::new(&di);
1223     ///
1224     /// s.filter_variants(|v| v.ast().ident != "B");
1225     ///
1226     /// assert_eq!(
1227     ///     s.each(|bi| quote!(println!("{:?}", #bi))),
1228     ///
1229     ///     quote!{
1230     ///         A::C(ref __binding_0,) => {
1231     ///             { println!("{:?}", __binding_0) }
1232     ///         }
1233     ///         _ => {}
1234     ///     }
1235     /// );
1236     /// # }
1237     /// ```
filter_variants<F>(&mut self, f: F) -> &mut Self where F: FnMut(&VariantInfo) -> bool,1238     pub fn filter_variants<F>(&mut self, f: F) -> &mut Self
1239     where
1240         F: FnMut(&VariantInfo) -> bool,
1241     {
1242         let before_len = self.variants.len();
1243         self.variants.retain(f);
1244         if self.variants.len() != before_len {
1245             self.omitted_variants = true;
1246         }
1247         self
1248     }
1249 
1250     /// Remove the variant at the given index.
1251     ///
1252     /// # Panics
1253     ///
1254     /// Panics if the index is out of range.
remove_variant(&mut self, idx: usize) -> &mut Self1255     pub fn remove_variant(&mut self, idx: usize) -> &mut Self {
1256         self.variants.remove(idx);
1257         self.omitted_variants = true;
1258         self
1259     }
1260 
1261     /// Updates the `BindStyle` for each of the passed-in fields by calling the
1262     /// passed-in function for each `BindingInfo`.
1263     ///
1264     /// # Example
1265     /// ```
1266     /// # #[macro_use] extern crate quote;
1267     /// # extern crate synstructure;
1268     /// # #[macro_use] extern crate syn;
1269     /// # use synstructure::*;
1270     /// # fn main() {
1271     /// let di: syn::DeriveInput = parse_quote! {
1272     ///     enum A {
1273     ///         B(i32, i32),
1274     ///         C(u32),
1275     ///     }
1276     /// };
1277     /// let mut s = Structure::new(&di);
1278     ///
1279     /// s.bind_with(|bi| BindStyle::RefMut);
1280     ///
1281     /// assert_eq!(
1282     ///     s.each(|bi| quote!(println!("{:?}", #bi))),
1283     ///
1284     ///     quote!{
1285     ///         A::B(ref mut __binding_0, ref mut __binding_1,) => {
1286     ///             { println!("{:?}", __binding_0) }
1287     ///             { println!("{:?}", __binding_1) }
1288     ///         }
1289     ///         A::C(ref mut __binding_0,) => {
1290     ///             { println!("{:?}", __binding_0) }
1291     ///         }
1292     ///     }
1293     /// );
1294     /// # }
1295     /// ```
bind_with<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&BindingInfo) -> BindStyle,1296     pub fn bind_with<F>(&mut self, mut f: F) -> &mut Self
1297     where
1298         F: FnMut(&BindingInfo) -> BindStyle,
1299     {
1300         for variant in &mut self.variants {
1301             variant.bind_with(&mut f);
1302         }
1303         self
1304     }
1305 
1306     /// Updates the binding name for each fo the passed-in fields by calling the
1307     /// passed-in function for each `BindingInfo`.
1308     ///
1309     /// The function will be called with the `BindingInfo` and its index in the
1310     /// enclosing variant.
1311     ///
1312     /// The default name is `__binding_{}` where `{}` is replaced with an
1313     /// increasing number.
1314     ///
1315     /// # Example
1316     /// ```
1317     /// # #[macro_use] extern crate quote;
1318     /// # extern crate synstructure;
1319     /// # #[macro_use] extern crate syn;
1320     /// # use synstructure::*;
1321     /// # fn main() {
1322     /// let di: syn::DeriveInput = parse_quote! {
1323     ///     enum A {
1324     ///         B{ a: i32, b: i32 },
1325     ///         C{ a: u32 },
1326     ///     }
1327     /// };
1328     /// let mut s = Structure::new(&di);
1329     ///
1330     /// s.binding_name(|bi, i| bi.ident.clone().unwrap());
1331     ///
1332     /// assert_eq!(
1333     ///     s.each(|bi| quote!(println!("{:?}", #bi))),
1334     ///
1335     ///     quote!{
1336     ///         A::B{ a: ref a, b: ref b, } => {
1337     ///             { println!("{:?}", a) }
1338     ///             { println!("{:?}", b) }
1339     ///         }
1340     ///         A::C{ a: ref a, } => {
1341     ///             { println!("{:?}", a) }
1342     ///         }
1343     ///     }
1344     /// );
1345     /// # }
1346     /// ```
binding_name<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&Field, usize) -> Ident,1347     pub fn binding_name<F>(&mut self, mut f: F) -> &mut Self
1348     where
1349         F: FnMut(&Field, usize) -> Ident,
1350     {
1351         for variant in &mut self.variants {
1352             variant.binding_name(&mut f);
1353         }
1354         self
1355     }
1356 
1357     /// Returns a list of the type parameters which are refrenced in the types
1358     /// of non-filtered fields / variants.
1359     ///
1360     /// # Caveat
1361     ///
1362     /// If the struct contains any macros in type position, all parameters will
1363     /// be considered bound. This is because we cannot determine which type
1364     /// parameters are bound by type macros.
1365     ///
1366     /// # Example
1367     /// ```
1368     /// # #[macro_use] extern crate quote;
1369     /// # extern crate synstructure;
1370     /// # #[macro_use] extern crate syn;
1371     /// # use synstructure::*;
1372     /// # fn main() {
1373     /// let di: syn::DeriveInput = parse_quote! {
1374     ///     enum A<T, U> {
1375     ///         B(T, i32),
1376     ///         C(Option<U>),
1377     ///     }
1378     /// };
1379     /// let mut s = Structure::new(&di);
1380     ///
1381     /// s.filter_variants(|v| v.ast().ident != "C");
1382     ///
1383     /// assert_eq!(
1384     ///     s.referenced_ty_params(),
1385     ///     &[&(syn::Ident::from("T"))]
1386     /// );
1387     /// # }
1388     /// ```
referenced_ty_params(&self) -> Vec<&'a Ident>1389     pub fn referenced_ty_params(&self) -> Vec<&'a Ident> {
1390         let mut flags = Vec::new();
1391         for variant in &self.variants {
1392             for binding in &variant.bindings {
1393                 generics_fuse(&mut flags, &binding.seen_generics);
1394             }
1395         }
1396         fetch_generics(&flags, &self.ast.generics)
1397     }
1398 
1399     /// Add trait bounds for a trait with the given path for each type parmaeter
1400     /// referenced in the types of non-filtered fields.
1401     ///
1402     /// # Caveat
1403     ///
1404     /// If the method contains any macros in type position, all parameters will
1405     /// be considered bound. This is because we cannot determine which type
1406     /// parameters are bound by type macros.
add_trait_bounds(&self, bound: &TraitBound, where_clause: &mut Option<WhereClause>)1407     pub fn add_trait_bounds(&self, bound: &TraitBound, where_clause: &mut Option<WhereClause>) {
1408         let mut seen = HashSet::new();
1409         let mut pred = |ty: Type| if !seen.contains(&ty) {
1410             seen.insert(ty.clone());
1411 
1412             // Ensure we have a where clause, because we need to use it. We
1413             // can't use `get_or_insert_with`, because it isn't supported on all
1414             // rustc versions we support.
1415             if where_clause.is_none() {
1416                 *where_clause = Some(WhereClause {
1417                     where_token: Default::default(),
1418                     predicates: punctuated::Punctuated::new(),
1419                 });
1420             }
1421             let clause = where_clause.as_mut().unwrap();
1422 
1423             // Add a predicate.
1424             clause.predicates.push(WherePredicate::Type(PredicateType {
1425                 lifetimes: None,
1426                 bounded_ty: ty,
1427                 colon_token: Default::default(),
1428                 bounds: Some(punctuated::Pair::End(TypeParamBound::Trait(bound.clone())))
1429                     .into_iter()
1430                     .collect(),
1431             }));
1432         };
1433 
1434         for variant in &self.variants {
1435             for binding in &variant.bindings {
1436                 for &seen in &binding.seen_generics {
1437                     if seen {
1438                         pred(binding.ast().ty.clone());
1439                         break;
1440                     }
1441                 }
1442 
1443                 for param in binding.referenced_ty_params() {
1444                     pred(Type::Path(TypePath {
1445                         qself: None,
1446                         path: (*param).clone().into(),
1447                     }));
1448                 }
1449             }
1450         }
1451     }
1452 
1453     /// Creates an `impl` block with the required generic type fields filled in
1454     /// to implement the trait `path`.
1455     ///
1456     /// This method also adds where clauses to the impl requiring that all
1457     /// referenced type parmaeters implement the trait `path`.
1458     ///
1459     /// # Hygiene and Paths
1460     ///
1461     /// This method wraps the impl block inside of a `const` (see the example
1462     /// below). In this scope, the first segment of the passed-in path is
1463     /// `extern crate`-ed in. If you don't want to generate that `extern crate`
1464     /// item, use a global path.
1465     ///
1466     /// This means that if you are implementing `my_crate::Trait`, you simply
1467     /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the
1468     /// entirety of the definition, you can refer to your crate as `my_crate`.
1469     ///
1470     /// # Caveat
1471     ///
1472     /// If the method contains any macros in type position, all parameters will
1473     /// be considered bound. This is because we cannot determine which type
1474     /// parameters are bound by type macros.
1475     ///
1476     /// # Panics
1477     ///
1478     /// Panics if the path string parameter is not a valid `TraitBound`.
1479     ///
1480     /// # Example
1481     /// ```
1482     /// # #[macro_use] extern crate quote;
1483     /// # extern crate synstructure;
1484     /// # #[macro_use] extern crate syn;
1485     /// # use synstructure::*;
1486     /// # fn main() {
1487     /// let di: syn::DeriveInput = parse_quote! {
1488     ///     enum A<T, U> {
1489     ///         B(T),
1490     ///         C(Option<U>),
1491     ///     }
1492     /// };
1493     /// let mut s = Structure::new(&di);
1494     ///
1495     /// s.filter_variants(|v| v.ast().ident != "B");
1496     ///
1497     /// assert_eq!(
1498     ///     s.bound_impl(quote!(krate::Trait), quote!{
1499     ///         fn a() {}
1500     ///     }),
1501     ///     quote!{
1502     ///         #[allow(non_upper_case_globals)]
1503     ///         const _DERIVE_krate_Trait_FOR_A: () = {
1504     ///             extern crate krate;
1505     ///             impl<T, U> krate::Trait for A<T, U>
1506     ///                 where Option<U>: krate::Trait,
1507     ///                       U: krate::Trait
1508     ///             {
1509     ///                 fn a() {}
1510     ///             }
1511     ///         };
1512     ///     }
1513     /// );
1514     /// # }
1515     /// ```
bound_impl<P: ToTokens,B: ToTokens>(&self, path: P, body: B) -> Tokens1516     pub fn bound_impl<P: ToTokens,B: ToTokens>(&self, path: P, body: B) -> Tokens {
1517         self.impl_internal(
1518             path.into_tokens(),
1519             body.into_tokens(),
1520             quote!(),
1521             true,
1522         )
1523     }
1524 
1525     /// Creates an `impl` block with the required generic type fields filled in
1526     /// to implement the unsafe trait `path`.
1527     ///
1528     /// This method also adds where clauses to the impl requiring that all
1529     /// referenced type parmaeters implement the trait `path`.
1530     ///
1531     /// # Hygiene and Paths
1532     ///
1533     /// This method wraps the impl block inside of a `const` (see the example
1534     /// below). In this scope, the first segment of the passed-in path is
1535     /// `extern crate`-ed in. If you don't want to generate that `extern crate`
1536     /// item, use a global path.
1537     ///
1538     /// This means that if you are implementing `my_crate::Trait`, you simply
1539     /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the
1540     /// entirety of the definition, you can refer to your crate as `my_crate`.
1541     ///
1542     /// # Caveat
1543     ///
1544     /// If the method contains any macros in type position, all parameters will
1545     /// be considered bound. This is because we cannot determine which type
1546     /// parameters are bound by type macros.
1547     ///
1548     /// # Panics
1549     ///
1550     /// Panics if the path string parameter is not a valid `TraitBound`.
1551     ///
1552     /// # Example
1553     /// ```
1554     /// # #[macro_use] extern crate quote;
1555     /// # extern crate synstructure;
1556     /// # #[macro_use] extern crate syn;
1557     /// # use synstructure::*;
1558     /// # fn main() {
1559     /// let di: syn::DeriveInput = parse_quote! {
1560     ///     enum A<T, U> {
1561     ///         B(T),
1562     ///         C(Option<U>),
1563     ///     }
1564     /// };
1565     /// let mut s = Structure::new(&di);
1566     ///
1567     /// s.filter_variants(|v| v.ast().ident != "B");
1568     ///
1569     /// assert_eq!(
1570     ///     s.unsafe_bound_impl(quote!(krate::Trait), quote!{
1571     ///         fn a() {}
1572     ///     }),
1573     ///     quote!{
1574     ///         #[allow(non_upper_case_globals)]
1575     ///         const _DERIVE_krate_Trait_FOR_A: () = {
1576     ///             extern crate krate;
1577     ///             unsafe impl<T, U> krate::Trait for A<T, U>
1578     ///                 where Option<U>: krate::Trait,
1579     ///                       U: krate::Trait
1580     ///             {
1581     ///                 fn a() {}
1582     ///             }
1583     ///         };
1584     ///     }
1585     /// );
1586     /// # }
1587     /// ```
unsafe_bound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> Tokens1588     pub fn unsafe_bound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> Tokens {
1589         self.impl_internal(
1590             path.into_tokens(),
1591             body.into_tokens(),
1592             quote!(unsafe),
1593             true,
1594         )
1595     }
1596 
1597     /// Creates an `impl` block with the required generic type fields filled in
1598     /// to implement the trait `path`.
1599     ///
1600     /// This method will not add any where clauses to the impl.
1601     ///
1602     /// # Hygiene and Paths
1603     ///
1604     /// This method wraps the impl block inside of a `const` (see the example
1605     /// below). In this scope, the first segment of the passed-in path is
1606     /// `extern crate`-ed in. If you don't want to generate that `extern crate`
1607     /// item, use a global path.
1608     ///
1609     /// This means that if you are implementing `my_crate::Trait`, you simply
1610     /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the
1611     /// entirety of the definition, you can refer to your crate as `my_crate`.
1612     ///
1613     /// # Panics
1614     ///
1615     /// Panics if the path string parameter is not a valid `TraitBound`.
1616     ///
1617     /// # Example
1618     /// ```
1619     /// # #[macro_use] extern crate quote;
1620     /// # extern crate synstructure;
1621     /// # #[macro_use] extern crate syn;
1622     /// # use synstructure::*;
1623     /// # fn main() {
1624     /// let di: syn::DeriveInput = parse_quote! {
1625     ///     enum A<T, U> {
1626     ///         B(T),
1627     ///         C(Option<U>),
1628     ///     }
1629     /// };
1630     /// let mut s = Structure::new(&di);
1631     ///
1632     /// s.filter_variants(|v| v.ast().ident != "B");
1633     ///
1634     /// assert_eq!(
1635     ///     s.unbound_impl(quote!(krate::Trait), quote!{
1636     ///         fn a() {}
1637     ///     }),
1638     ///     quote!{
1639     ///         #[allow(non_upper_case_globals)]
1640     ///         const _DERIVE_krate_Trait_FOR_A: () = {
1641     ///             extern crate krate;
1642     ///             impl<T, U> krate::Trait for A<T, U> {
1643     ///                 fn a() {}
1644     ///             }
1645     ///         };
1646     ///     }
1647     /// );
1648     /// # }
1649     /// ```
unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> Tokens1650     pub fn unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> Tokens {
1651         self.impl_internal(
1652             path.into_tokens(),
1653             body.into_tokens(),
1654             quote!(),
1655             false,
1656         )
1657     }
1658 
1659     /// Creates an `impl` block with the required generic type fields filled in
1660     /// to implement the unsafe trait `path`.
1661     ///
1662     /// This method will not add any where clauses to the impl.
1663     ///
1664     /// # Hygiene and Paths
1665     ///
1666     /// This method wraps the impl block inside of a `const` (see the example
1667     /// below). In this scope, the first segment of the passed-in path is
1668     /// `extern crate`-ed in. If you don't want to generate that `extern crate`
1669     /// item, use a global path.
1670     ///
1671     /// This means that if you are implementing `my_crate::Trait`, you simply
1672     /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the
1673     /// entirety of the definition, you can refer to your crate as `my_crate`.
1674     ///
1675     /// # Panics
1676     ///
1677     /// Panics if the path string parameter is not a valid `TraitBound`.
1678     ///
1679     /// # Example
1680     /// ```
1681     /// # #[macro_use] extern crate quote;
1682     /// # extern crate synstructure;
1683     /// # #[macro_use] extern crate syn;
1684     /// # use synstructure::*;
1685     /// # fn main() {
1686     /// let di: syn::DeriveInput = parse_quote! {
1687     ///     enum A<T, U> {
1688     ///         B(T),
1689     ///         C(Option<U>),
1690     ///     }
1691     /// };
1692     /// let mut s = Structure::new(&di);
1693     ///
1694     /// s.filter_variants(|v| v.ast().ident != "B");
1695     ///
1696     /// assert_eq!(
1697     ///     s.unsafe_unbound_impl(quote!(krate::Trait), quote!{
1698     ///         fn a() {}
1699     ///     }),
1700     ///     quote!{
1701     ///         #[allow(non_upper_case_globals)]
1702     ///         const _DERIVE_krate_Trait_FOR_A: () = {
1703     ///             extern crate krate;
1704     ///             unsafe impl<T, U> krate::Trait for A<T, U> {
1705     ///                 fn a() {}
1706     ///             }
1707     ///         };
1708     ///     }
1709     /// );
1710     /// # }
1711     /// ```
unsafe_unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> Tokens1712     pub fn unsafe_unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> Tokens {
1713         self.impl_internal(
1714             path.into_tokens(),
1715             body.into_tokens(),
1716             quote!(unsafe),
1717             false,
1718         )
1719     }
1720 
impl_internal( &self, path: Tokens, body: Tokens, safety: Tokens, add_bounds: bool, ) -> Tokens1721     fn impl_internal(
1722         &self,
1723         path: Tokens,
1724         body: Tokens,
1725         safety: Tokens,
1726         add_bounds: bool,
1727     ) -> Tokens {
1728         let name = &self.ast.ident;
1729         let (impl_generics, ty_generics, where_clause) = self.ast.generics.split_for_impl();
1730 
1731         let bound = syn::parse2::<TraitBound>(path.into())
1732             .expect("`path` argument must be a valid rust trait bound");
1733 
1734         let mut where_clause = where_clause.cloned();
1735         if add_bounds {
1736             self.add_trait_bounds(&bound, &mut where_clause);
1737         }
1738 
1739         let dummy_const: Ident = sanitize_ident(&format!(
1740             "_DERIVE_{}_FOR_{}",
1741             (&bound).into_tokens(),
1742             name.into_tokens(),
1743         ));
1744 
1745         // This function is smart. If a global path is passed, no extern crate
1746         // statement will be generated, however, a relative path will cause the
1747         // crate which it is relative to to be imported within the current
1748         // scope.
1749         let mut extern_crate = quote!();
1750         if bound.path.leading_colon.is_none() {
1751             if let Some(ref seg) = bound.path.segments.first() {
1752                 let seg = seg.value();
1753                 extern_crate = quote! { extern crate #seg; };
1754             }
1755         }
1756 
1757         quote! {
1758             #[allow(non_upper_case_globals)]
1759             const #dummy_const: () = {
1760                 #extern_crate
1761                 #safety impl #impl_generics #bound for #name #ty_generics #where_clause {
1762                     #body
1763                 }
1764             };
1765         }
1766     }
1767 }
1768