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