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 //! # use quote::quote;
22 //! fn walkfields_derive(s: synstructure::Structure) -> proc_macro2::TokenStream {
23 //! let body = s.each(|bi| quote!{
24 //! walk(#bi)
25 //! });
26 //!
27 //! s.gen_impl(quote! {
28 //! extern crate synstructure_test_traits;
29 //!
30 //! gen impl synstructure_test_traits::WalkFields for @Self {
31 //! fn walk_fields(&self, walk: &mut FnMut(&synstructure_test_traits::WalkFields)) {
32 //! match *self { #body }
33 //! }
34 //! }
35 //! })
36 //! }
37 //! # const _IGNORE: &'static str = stringify!(
38 //! synstructure::decl_derive!([WalkFields] => walkfields_derive);
39 //! # );
40 //!
41 //! /*
42 //! * Test Case
43 //! */
44 //! fn main() {
45 //! synstructure::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 //! # use quote::quote;
91 //! fn interest_derive(mut s: synstructure::Structure) -> proc_macro2::TokenStream {
92 //! let body = s.fold(false, |acc, bi| quote!{
93 //! #acc || synstructure_test_traits::Interest::interesting(#bi)
94 //! });
95 //!
96 //! s.gen_impl(quote! {
97 //! extern crate synstructure_test_traits;
98 //! gen impl synstructure_test_traits::Interest for @Self {
99 //! fn interesting(&self) -> bool {
100 //! match *self {
101 //! #body
102 //! }
103 //! }
104 //! }
105 //! })
106 //! }
107 //! # const _IGNORE: &'static str = stringify!(
108 //! synstructure::decl_derive!([Interest] => interest_derive);
109 //! # );
110 //!
111 //! /*
112 //! * Test Case
113 //! */
114 //! fn main() {
115 //! synstructure::test_derive!{
116 //! interest_derive {
117 //! enum A<T> {
118 //! B(i32, T),
119 //! C(i32),
120 //! }
121 //! }
122 //! expands to {
123 //! #[allow(non_upper_case_globals)]
124 //! const _DERIVE_synstructure_test_traits_Interest_FOR_A: () = {
125 //! extern crate synstructure_test_traits;
126 //! impl<T> synstructure_test_traits::Interest for A<T>
127 //! where T: synstructure_test_traits::Interest
128 //! {
129 //! fn interesting(&self) -> bool {
130 //! match *self {
131 //! A::B(ref __binding_0, ref __binding_1,) => {
132 //! false ||
133 //! synstructure_test_traits::Interest::interesting(__binding_0) ||
134 //! synstructure_test_traits::Interest::interesting(__binding_1)
135 //! }
136 //! A::C(ref __binding_0,) => {
137 //! false ||
138 //! synstructure_test_traits::Interest::interesting(__binding_0)
139 //! }
140 //! }
141 //! }
142 //! }
143 //! };
144 //! }
145 //! }
146 //! }
147 //! ```
148 //!
149 //! For more example usage, consider investigating the `abomonation_derive` crate,
150 //! which makes use of this crate, and is fairly simple.
151
152 #[cfg(all(
153 not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
154 feature = "proc-macro"
155 ))]
156 extern crate proc_macro;
157
158 use std::collections::HashSet;
159
160 use syn::parse::{ParseStream, Parser};
161 use syn::visit::{self, Visit};
162 use syn::{
163 braced, punctuated, token, Attribute, Data, DeriveInput, Error, Expr, Field, Fields,
164 FieldsNamed, FieldsUnnamed, GenericParam, Generics, Ident, PredicateType, Result, Token,
165 TraitBound, Type, TypeMacro, TypeParamBound, TypePath, WhereClause, WherePredicate,
166 };
167
168 use quote::{format_ident, quote_spanned, ToTokens};
169 // re-export the quote! macro so we can depend on it being around in our macro's
170 // implementations.
171 #[doc(hidden)]
172 pub use quote::quote;
173
174 use unicode_xid::UnicodeXID;
175
176 use proc_macro2::{Span, TokenStream, TokenTree};
177
178 // NOTE: This module has documentation hidden, as it only exports macros (which
179 // always appear in the root of the crate) and helper methods / re-exports used
180 // in the implementation of those macros.
181 #[doc(hidden)]
182 pub mod macros;
183
184 /// Changes how bounds are added
185 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
186 pub enum AddBounds {
187 /// Add for fields and generics
188 Both,
189 /// Fields only
190 Fields,
191 /// Generics only
192 Generics,
193 /// None
194 None,
195 #[doc(hidden)]
196 __Nonexhaustive,
197 }
198
199 /// The type of binding to use when generating a pattern.
200 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
201 pub enum BindStyle {
202 /// `x`
203 Move,
204 /// `mut x`
205 MoveMut,
206 /// `ref x`
207 Ref,
208 /// `ref mut x`
209 RefMut,
210 }
211
212 impl ToTokens for BindStyle {
to_tokens(&self, tokens: &mut TokenStream)213 fn to_tokens(&self, tokens: &mut TokenStream) {
214 match self {
215 BindStyle::Move => {}
216 BindStyle::MoveMut => quote_spanned!(Span::call_site() => mut).to_tokens(tokens),
217 BindStyle::Ref => quote_spanned!(Span::call_site() => ref).to_tokens(tokens),
218 BindStyle::RefMut => quote_spanned!(Span::call_site() => ref mut).to_tokens(tokens),
219 }
220 }
221 }
222
223 // Internal method for merging seen_generics arrays together.
generics_fuse(res: &mut Vec<bool>, new: &[bool])224 fn generics_fuse(res: &mut Vec<bool>, new: &[bool]) {
225 for (i, &flag) in new.iter().enumerate() {
226 if i == res.len() {
227 res.push(false);
228 }
229 if flag {
230 res[i] = true;
231 }
232 }
233 }
234
235 // Internal method for extracting the set of generics which have been matched.
fetch_generics<'a>(set: &[bool], generics: &'a Generics) -> Vec<&'a Ident>236 fn fetch_generics<'a>(set: &[bool], generics: &'a Generics) -> Vec<&'a Ident> {
237 let mut tys = vec![];
238 for (&seen, param) in set.iter().zip(generics.params.iter()) {
239 if seen {
240 if let GenericParam::Type(tparam) = param {
241 tys.push(&tparam.ident)
242 }
243 }
244 }
245 tys
246 }
247
248 // Internal method for sanitizing an identifier for hygiene purposes.
sanitize_ident(s: &str) -> Ident249 fn sanitize_ident(s: &str) -> Ident {
250 let mut res = String::with_capacity(s.len());
251 for mut c in s.chars() {
252 if !UnicodeXID::is_xid_continue(c) {
253 c = '_'
254 }
255 // Deduplicate consecutive _ characters.
256 if res.ends_with('_') && c == '_' {
257 continue;
258 }
259 res.push(c);
260 }
261 Ident::new(&res, Span::call_site())
262 }
263
264 // Internal method to merge two Generics objects together intelligently.
merge_generics(into: &mut Generics, from: &Generics) -> Result<()>265 fn merge_generics(into: &mut Generics, from: &Generics) -> Result<()> {
266 // Try to add the param into `into`, and merge parmas with identical names.
267 for p in &from.params {
268 for op in &into.params {
269 match (op, p) {
270 (GenericParam::Type(otp), GenericParam::Type(tp)) => {
271 // NOTE: This is only OK because syn ignores the span for equality purposes.
272 if otp.ident == tp.ident {
273 return Err(Error::new_spanned(
274 p,
275 format!(
276 "Attempted to merge conflicting generic parameters: {} and {}",
277 quote!(#op),
278 quote!(#p)
279 ),
280 ));
281 }
282 }
283 (GenericParam::Lifetime(olp), GenericParam::Lifetime(lp)) => {
284 // NOTE: This is only OK because syn ignores the span for equality purposes.
285 if olp.lifetime == lp.lifetime {
286 return Err(Error::new_spanned(
287 p,
288 format!(
289 "Attempted to merge conflicting generic parameters: {} and {}",
290 quote!(#op),
291 quote!(#p)
292 ),
293 ));
294 }
295 }
296 // We don't support merging Const parameters, because that wouldn't make much sense.
297 _ => (),
298 }
299 }
300 into.params.push(p.clone());
301 }
302
303 // Add any where clauses from the input generics object.
304 if let Some(from_clause) = &from.where_clause {
305 into.make_where_clause()
306 .predicates
307 .extend(from_clause.predicates.iter().cloned());
308 }
309
310 Ok(())
311 }
312
313 /// Helper method which does the same thing as rustc 1.20's
314 /// `Option::get_or_insert_with`. This method is used to keep backwards
315 /// compatibility with rustc 1.15.
get_or_insert_with<T, F>(opt: &mut Option<T>, f: F) -> &mut T where F: FnOnce() -> T,316 fn get_or_insert_with<T, F>(opt: &mut Option<T>, f: F) -> &mut T
317 where
318 F: FnOnce() -> T,
319 {
320 if opt.is_none() {
321 *opt = Some(f());
322 }
323
324 match opt {
325 Some(v) => v,
326 None => unreachable!(),
327 }
328 }
329
330 /// Information about a specific binding. This contains both an `Ident`
331 /// reference to the given field, and the syn `&'a Field` descriptor for that
332 /// field.
333 ///
334 /// This type supports `quote::ToTokens`, so can be directly used within the
335 /// `quote!` macro. It expands to a reference to the matched field.
336 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
337 pub struct BindingInfo<'a> {
338 /// The name which this BindingInfo will bind to.
339 pub binding: Ident,
340
341 /// The type of binding which this BindingInfo will create.
342 pub style: BindStyle,
343
344 field: &'a Field,
345
346 // These are used to determine which type parameters are avaliable.
347 generics: &'a Generics,
348 seen_generics: Vec<bool>,
349 }
350
351 impl<'a> ToTokens for BindingInfo<'a> {
to_tokens(&self, tokens: &mut TokenStream)352 fn to_tokens(&self, tokens: &mut TokenStream) {
353 self.binding.to_tokens(tokens);
354 }
355 }
356
357 impl<'a> BindingInfo<'a> {
358 /// Returns a reference to the underlying `syn` AST node which this
359 /// `BindingInfo` references
ast(&self) -> &'a Field360 pub fn ast(&self) -> &'a Field {
361 self.field
362 }
363
364 /// Generates the pattern fragment for this field binding.
365 ///
366 /// # Example
367 /// ```
368 /// # use synstructure::*;
369 /// let di: syn::DeriveInput = syn::parse_quote! {
370 /// enum A {
371 /// B{ a: i32, b: i32 },
372 /// C(u32),
373 /// }
374 /// };
375 /// let s = Structure::new(&di);
376 ///
377 /// assert_eq!(
378 /// s.variants()[0].bindings()[0].pat().to_string(),
379 /// quote! {
380 /// ref __binding_0
381 /// }.to_string()
382 /// );
383 /// ```
pat(&self) -> TokenStream384 pub fn pat(&self) -> TokenStream {
385 let BindingInfo { binding, style, .. } = self;
386 quote!(#style #binding)
387 }
388
389 /// Returns a list of the type parameters which are referenced in this
390 /// field's type.
391 ///
392 /// # Caveat
393 ///
394 /// If the field contains any macros in type position, all parameters will
395 /// be considered bound. This is because we cannot determine which type
396 /// parameters are bound by type macros.
397 ///
398 /// # Example
399 /// ```
400 /// # use synstructure::*;
401 /// let di: syn::DeriveInput = syn::parse_quote! {
402 /// struct A<T, U> {
403 /// a: Option<T>,
404 /// b: U,
405 /// }
406 /// };
407 /// let mut s = Structure::new(&di);
408 ///
409 /// assert_eq!(
410 /// s.variants()[0].bindings()[0].referenced_ty_params(),
411 /// &["e::format_ident!("T")]
412 /// );
413 /// ```
referenced_ty_params(&self) -> Vec<&'a Ident>414 pub fn referenced_ty_params(&self) -> Vec<&'a Ident> {
415 fetch_generics(&self.seen_generics, self.generics)
416 }
417 }
418
419 /// This type is similar to `syn`'s `Variant` type, however each of the fields
420 /// are references rather than owned. When this is used as the AST for a real
421 /// variant, this struct simply borrows the fields of the `syn::Variant`,
422 /// however this type may also be used as the sole variant for a struct.
423 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
424 pub struct VariantAst<'a> {
425 pub attrs: &'a [Attribute],
426 pub ident: &'a Ident,
427 pub fields: &'a Fields,
428 pub discriminant: &'a Option<(token::Eq, Expr)>,
429 }
430
431 /// A wrapper around a `syn::DeriveInput`'s variant which provides utilities
432 /// for destructuring `Variant`s with `match` expressions.
433 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
434 pub struct VariantInfo<'a> {
435 pub prefix: Option<&'a Ident>,
436 bindings: Vec<BindingInfo<'a>>,
437 omitted_fields: bool,
438 ast: VariantAst<'a>,
439 generics: &'a Generics,
440 }
441
442 /// Helper function used by the VariantInfo constructor. Walks all of the types
443 /// in `field` and returns a list of the type parameters from `ty_params` which
444 /// are referenced in the field.
get_ty_params(field: &Field, generics: &Generics) -> Vec<bool>445 fn get_ty_params(field: &Field, generics: &Generics) -> Vec<bool> {
446 // Helper type. Discovers all identifiers inside of the visited type,
447 // and calls a callback with them.
448 struct BoundTypeLocator<'a> {
449 result: Vec<bool>,
450 generics: &'a Generics,
451 }
452
453 impl<'a> Visit<'a> for BoundTypeLocator<'a> {
454 // XXX: This also (intentionally) captures paths like T::SomeType. Is
455 // this desirable?
456 fn visit_ident(&mut self, id: &Ident) {
457 for (idx, i) in self.generics.params.iter().enumerate() {
458 if let GenericParam::Type(tparam) = i {
459 if tparam.ident == *id {
460 self.result[idx] = true;
461 }
462 }
463 }
464 }
465
466 fn visit_type_macro(&mut self, x: &'a TypeMacro) {
467 // If we see a type_mac declaration, then we can't know what type parameters
468 // it might be binding, so we presume it binds all of them.
469 for r in &mut self.result {
470 *r = true;
471 }
472 visit::visit_type_macro(self, x)
473 }
474 }
475
476 let mut btl = BoundTypeLocator {
477 result: vec![false; generics.params.len()],
478 generics,
479 };
480
481 btl.visit_type(&field.ty);
482
483 btl.result
484 }
485
486 impl<'a> VariantInfo<'a> {
new(ast: VariantAst<'a>, prefix: Option<&'a Ident>, generics: &'a Generics) -> Self487 fn new(ast: VariantAst<'a>, prefix: Option<&'a Ident>, generics: &'a Generics) -> Self {
488 let bindings = match ast.fields {
489 Fields::Unit => vec![],
490 Fields::Unnamed(FieldsUnnamed {
491 unnamed: fields, ..
492 })
493 | Fields::Named(FieldsNamed { named: fields, .. }) => {
494 fields
495 .into_iter()
496 .enumerate()
497 .map(|(i, field)| {
498 BindingInfo {
499 // XXX: This has to be call_site to avoid privacy
500 // when deriving on private fields.
501 binding: format_ident!("__binding_{}", i),
502 style: BindStyle::Ref,
503 field,
504 generics,
505 seen_generics: get_ty_params(field, generics),
506 }
507 })
508 .collect::<Vec<_>>()
509 }
510 };
511
512 VariantInfo {
513 prefix,
514 bindings,
515 omitted_fields: false,
516 ast,
517 generics,
518 }
519 }
520
521 /// Returns a slice of the bindings in this Variant.
bindings(&self) -> &[BindingInfo<'a>]522 pub fn bindings(&self) -> &[BindingInfo<'a>] {
523 &self.bindings
524 }
525
526 /// Returns a mut slice of the bindings in this Variant.
bindings_mut(&mut self) -> &mut [BindingInfo<'a>]527 pub fn bindings_mut(&mut self) -> &mut [BindingInfo<'a>] {
528 &mut self.bindings
529 }
530
531 /// Returns a `VariantAst` object which contains references to the
532 /// underlying `syn` AST node which this `Variant` was created from.
ast(&self) -> VariantAst<'a>533 pub fn ast(&self) -> VariantAst<'a> {
534 self.ast
535 }
536
537 /// True if any bindings were omitted due to a `filter` call.
omitted_bindings(&self) -> bool538 pub fn omitted_bindings(&self) -> bool {
539 self.omitted_fields
540 }
541
542 /// Generates the match-arm pattern which could be used to match against this Variant.
543 ///
544 /// # Example
545 /// ```
546 /// # use synstructure::*;
547 /// let di: syn::DeriveInput = syn::parse_quote! {
548 /// enum A {
549 /// B(i32, i32),
550 /// C(u32),
551 /// }
552 /// };
553 /// let s = Structure::new(&di);
554 ///
555 /// assert_eq!(
556 /// s.variants()[0].pat().to_string(),
557 /// quote!{
558 /// A::B(ref __binding_0, ref __binding_1,)
559 /// }.to_string()
560 /// );
561 /// ```
pat(&self) -> TokenStream562 pub fn pat(&self) -> TokenStream {
563 let mut t = TokenStream::new();
564 if let Some(prefix) = self.prefix {
565 prefix.to_tokens(&mut t);
566 quote!(::).to_tokens(&mut t);
567 }
568 self.ast.ident.to_tokens(&mut t);
569 match self.ast.fields {
570 Fields::Unit => {
571 assert!(self.bindings.is_empty());
572 }
573 Fields::Unnamed(..) => token::Paren(Span::call_site()).surround(&mut t, |t| {
574 for binding in &self.bindings {
575 binding.pat().to_tokens(t);
576 quote!(,).to_tokens(t);
577 }
578 if self.omitted_fields {
579 quote!(..).to_tokens(t);
580 }
581 }),
582 Fields::Named(..) => token::Brace(Span::call_site()).surround(&mut t, |t| {
583 for binding in &self.bindings {
584 binding.field.ident.to_tokens(t);
585 quote!(:).to_tokens(t);
586 binding.pat().to_tokens(t);
587 quote!(,).to_tokens(t);
588 }
589 if self.omitted_fields {
590 quote!(..).to_tokens(t);
591 }
592 }),
593 }
594 t
595 }
596
597 /// Generates the token stream required to construct the current variant.
598 ///
599 /// The init array initializes each of the fields in the order they are
600 /// written in `variant.ast().fields`.
601 ///
602 /// # Example
603 /// ```
604 /// # use synstructure::*;
605 /// let di: syn::DeriveInput = syn::parse_quote! {
606 /// enum A {
607 /// B(usize, usize),
608 /// C{ v: usize },
609 /// }
610 /// };
611 /// let s = Structure::new(&di);
612 ///
613 /// assert_eq!(
614 /// s.variants()[0].construct(|_, i| quote!(#i)).to_string(),
615 ///
616 /// quote!{
617 /// A::B(0usize, 1usize,)
618 /// }.to_string()
619 /// );
620 ///
621 /// assert_eq!(
622 /// s.variants()[1].construct(|_, i| quote!(#i)).to_string(),
623 ///
624 /// quote!{
625 /// A::C{ v: 0usize, }
626 /// }.to_string()
627 /// );
628 /// ```
construct<F, T>(&self, mut func: F) -> TokenStream where F: FnMut(&Field, usize) -> T, T: ToTokens,629 pub fn construct<F, T>(&self, mut func: F) -> TokenStream
630 where
631 F: FnMut(&Field, usize) -> T,
632 T: ToTokens,
633 {
634 let mut t = TokenStream::new();
635 if let Some(prefix) = self.prefix {
636 quote!(#prefix ::).to_tokens(&mut t);
637 }
638 self.ast.ident.to_tokens(&mut t);
639
640 match &self.ast.fields {
641 Fields::Unit => (),
642 Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
643 token::Paren::default().surround(&mut t, |t| {
644 for (i, field) in unnamed.into_iter().enumerate() {
645 func(field, i).to_tokens(t);
646 quote!(,).to_tokens(t);
647 }
648 })
649 }
650 Fields::Named(FieldsNamed { named, .. }) => {
651 token::Brace::default().surround(&mut t, |t| {
652 for (i, field) in named.into_iter().enumerate() {
653 field.ident.to_tokens(t);
654 quote!(:).to_tokens(t);
655 func(field, i).to_tokens(t);
656 quote!(,).to_tokens(t);
657 }
658 })
659 }
660 }
661 t
662 }
663
664 /// Runs the passed-in function once for each bound field, passing in a `BindingInfo`.
665 /// and generating a `match` arm which evaluates the returned tokens.
666 ///
667 /// This method will ignore fields which are ignored through the `filter`
668 /// method.
669 ///
670 /// # Example
671 /// ```
672 /// # use synstructure::*;
673 /// let di: syn::DeriveInput = syn::parse_quote! {
674 /// enum A {
675 /// B(i32, i32),
676 /// C(u32),
677 /// }
678 /// };
679 /// let s = Structure::new(&di);
680 ///
681 /// assert_eq!(
682 /// s.variants()[0].each(|bi| quote!(println!("{:?}", #bi))).to_string(),
683 ///
684 /// quote!{
685 /// A::B(ref __binding_0, ref __binding_1,) => {
686 /// { println!("{:?}", __binding_0) }
687 /// { println!("{:?}", __binding_1) }
688 /// }
689 /// }.to_string()
690 /// );
691 /// ```
each<F, R>(&self, mut f: F) -> TokenStream where F: FnMut(&BindingInfo<'_>) -> R, R: ToTokens,692 pub fn each<F, R>(&self, mut f: F) -> TokenStream
693 where
694 F: FnMut(&BindingInfo<'_>) -> R,
695 R: ToTokens,
696 {
697 let pat = self.pat();
698 let mut body = TokenStream::new();
699 for binding in &self.bindings {
700 token::Brace::default().surround(&mut body, |body| {
701 f(binding).to_tokens(body);
702 });
703 }
704 quote!(#pat => { #body })
705 }
706
707 /// Runs the passed-in function once for each bound field, passing in the
708 /// result of the previous call, and a `BindingInfo`. generating a `match`
709 /// arm which evaluates to the resulting tokens.
710 ///
711 /// This method will ignore fields which are ignored through the `filter`
712 /// method.
713 ///
714 /// # Example
715 /// ```
716 /// # use synstructure::*;
717 /// let di: syn::DeriveInput = syn::parse_quote! {
718 /// enum A {
719 /// B(i32, i32),
720 /// C(u32),
721 /// }
722 /// };
723 /// let s = Structure::new(&di);
724 ///
725 /// assert_eq!(
726 /// s.variants()[0].fold(quote!(0), |acc, bi| quote!(#acc + #bi)).to_string(),
727 ///
728 /// quote!{
729 /// A::B(ref __binding_0, ref __binding_1,) => {
730 /// 0 + __binding_0 + __binding_1
731 /// }
732 /// }.to_string()
733 /// );
734 /// ```
fold<F, I, R>(&self, init: I, mut f: F) -> TokenStream where F: FnMut(TokenStream, &BindingInfo<'_>) -> R, I: ToTokens, R: ToTokens,735 pub fn fold<F, I, R>(&self, init: I, mut f: F) -> TokenStream
736 where
737 F: FnMut(TokenStream, &BindingInfo<'_>) -> R,
738 I: ToTokens,
739 R: ToTokens,
740 {
741 let pat = self.pat();
742 let body = self.bindings.iter().fold(quote!(#init), |i, bi| {
743 let r = f(i, bi);
744 quote!(#r)
745 });
746 quote!(#pat => { #body })
747 }
748
749 /// Filter the bindings created by this `Variant` object. This has 2 effects:
750 ///
751 /// * The bindings will no longer appear in match arms generated by methods
752 /// on this `Variant` or its subobjects.
753 ///
754 /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl`
755 /// method only consider type parameters referenced in the types of
756 /// non-filtered fields.
757 ///
758 /// # Example
759 /// ```
760 /// # use synstructure::*;
761 /// let di: syn::DeriveInput = syn::parse_quote! {
762 /// enum A {
763 /// B{ a: i32, b: i32 },
764 /// C{ a: u32 },
765 /// }
766 /// };
767 /// let mut s = Structure::new(&di);
768 ///
769 /// s.variants_mut()[0].filter(|bi| {
770 /// bi.ast().ident == Some(quote::format_ident!("b"))
771 /// });
772 ///
773 /// assert_eq!(
774 /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(),
775 ///
776 /// quote!{
777 /// A::B{ b: ref __binding_1, .. } => {
778 /// { println!("{:?}", __binding_1) }
779 /// }
780 /// A::C{ a: ref __binding_0, } => {
781 /// { println!("{:?}", __binding_0) }
782 /// }
783 /// }.to_string()
784 /// );
785 /// ```
filter<F>(&mut self, f: F) -> &mut Self where F: FnMut(&BindingInfo<'_>) -> bool,786 pub fn filter<F>(&mut self, f: F) -> &mut Self
787 where
788 F: FnMut(&BindingInfo<'_>) -> bool,
789 {
790 let before_len = self.bindings.len();
791 self.bindings.retain(f);
792 if self.bindings.len() != before_len {
793 self.omitted_fields = true;
794 }
795 self
796 }
797
798 /// Remove the binding at the given index.
799 ///
800 /// # Panics
801 ///
802 /// Panics if the index is out of range.
remove_binding(&mut self, idx: usize) -> &mut Self803 pub fn remove_binding(&mut self, idx: usize) -> &mut Self {
804 self.bindings.remove(idx);
805 self.omitted_fields = true;
806 self
807 }
808
809 /// Updates the `BindStyle` for each of the passed-in fields by calling the
810 /// passed-in function for each `BindingInfo`.
811 ///
812 /// # Example
813 /// ```
814 /// # use synstructure::*;
815 /// let di: syn::DeriveInput = syn::parse_quote! {
816 /// enum A {
817 /// B(i32, i32),
818 /// C(u32),
819 /// }
820 /// };
821 /// let mut s = Structure::new(&di);
822 ///
823 /// s.variants_mut()[0].bind_with(|bi| BindStyle::RefMut);
824 ///
825 /// assert_eq!(
826 /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(),
827 ///
828 /// quote!{
829 /// A::B(ref mut __binding_0, ref mut __binding_1,) => {
830 /// { println!("{:?}", __binding_0) }
831 /// { println!("{:?}", __binding_1) }
832 /// }
833 /// A::C(ref __binding_0,) => {
834 /// { println!("{:?}", __binding_0) }
835 /// }
836 /// }.to_string()
837 /// );
838 /// ```
bind_with<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&BindingInfo<'_>) -> BindStyle,839 pub fn bind_with<F>(&mut self, mut f: F) -> &mut Self
840 where
841 F: FnMut(&BindingInfo<'_>) -> BindStyle,
842 {
843 for binding in &mut self.bindings {
844 binding.style = f(&binding);
845 }
846 self
847 }
848
849 /// Updates the binding name for each fo the passed-in fields by calling the
850 /// passed-in function for each `BindingInfo`.
851 ///
852 /// The function will be called with the `BindingInfo` and its index in the
853 /// enclosing variant.
854 ///
855 /// The default name is `__binding_{}` where `{}` is replaced with an
856 /// increasing number.
857 ///
858 /// # Example
859 /// ```
860 /// # use synstructure::*;
861 /// let di: syn::DeriveInput = syn::parse_quote! {
862 /// enum A {
863 /// B{ a: i32, b: i32 },
864 /// C{ a: u32 },
865 /// }
866 /// };
867 /// let mut s = Structure::new(&di);
868 ///
869 /// s.variants_mut()[0].binding_name(|bi, i| bi.ident.clone().unwrap());
870 ///
871 /// assert_eq!(
872 /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(),
873 ///
874 /// quote!{
875 /// A::B{ a: ref a, b: ref b, } => {
876 /// { println!("{:?}", a) }
877 /// { println!("{:?}", b) }
878 /// }
879 /// A::C{ a: ref __binding_0, } => {
880 /// { println!("{:?}", __binding_0) }
881 /// }
882 /// }.to_string()
883 /// );
884 /// ```
binding_name<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&Field, usize) -> Ident,885 pub fn binding_name<F>(&mut self, mut f: F) -> &mut Self
886 where
887 F: FnMut(&Field, usize) -> Ident,
888 {
889 for (it, binding) in self.bindings.iter_mut().enumerate() {
890 binding.binding = f(binding.field, it);
891 }
892 self
893 }
894
895 /// Returns a list of the type parameters which are referenced in this
896 /// field's type.
897 ///
898 /// # Caveat
899 ///
900 /// If the field contains any macros in type position, all parameters will
901 /// be considered bound. This is because we cannot determine which type
902 /// parameters are bound by type macros.
903 ///
904 /// # Example
905 /// ```
906 /// # use synstructure::*;
907 /// let di: syn::DeriveInput = syn::parse_quote! {
908 /// struct A<T, U> {
909 /// a: Option<T>,
910 /// b: U,
911 /// }
912 /// };
913 /// let mut s = Structure::new(&di);
914 ///
915 /// assert_eq!(
916 /// s.variants()[0].bindings()[0].referenced_ty_params(),
917 /// &["e::format_ident!("T")]
918 /// );
919 /// ```
referenced_ty_params(&self) -> Vec<&'a Ident>920 pub fn referenced_ty_params(&self) -> Vec<&'a Ident> {
921 let mut flags = Vec::new();
922 for binding in &self.bindings {
923 generics_fuse(&mut flags, &binding.seen_generics);
924 }
925 fetch_generics(&flags, self.generics)
926 }
927 }
928
929 /// A wrapper around a `syn::DeriveInput` which provides utilities for creating
930 /// custom derive trait implementations.
931 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
932 pub struct Structure<'a> {
933 variants: Vec<VariantInfo<'a>>,
934 omitted_variants: bool,
935 ast: &'a DeriveInput,
936 extra_impl: Vec<GenericParam>,
937 extra_predicates: Vec<WherePredicate>,
938 add_bounds: AddBounds,
939 }
940
941 impl<'a> Structure<'a> {
942 /// Create a new `Structure` with the variants and fields from the passed-in
943 /// `DeriveInput`.
944 ///
945 /// # Panics
946 ///
947 /// This method will panic if the provided AST node represents an untagged
948 /// union.
new(ast: &'a DeriveInput) -> Self949 pub fn new(ast: &'a DeriveInput) -> Self {
950 Self::try_new(ast).expect("Unable to create synstructure::Structure")
951 }
952
953 /// Create a new `Structure` with the variants and fields from the passed-in
954 /// `DeriveInput`.
955 ///
956 /// Unlike `Structure::new`, this method does not panic if the provided AST
957 /// node represents an untagged union.
try_new(ast: &'a DeriveInput) -> Result<Self>958 pub fn try_new(ast: &'a DeriveInput) -> Result<Self> {
959 let variants = match &ast.data {
960 Data::Enum(data) => (&data.variants)
961 .into_iter()
962 .map(|v| {
963 VariantInfo::new(
964 VariantAst {
965 attrs: &v.attrs,
966 ident: &v.ident,
967 fields: &v.fields,
968 discriminant: &v.discriminant,
969 },
970 Some(&ast.ident),
971 &ast.generics,
972 )
973 })
974 .collect::<Vec<_>>(),
975 Data::Struct(data) => {
976 // SAFETY NOTE: Normally putting an `Expr` in static storage
977 // wouldn't be safe, because it could contain `Term` objects
978 // which use thread-local interning. However, this static always
979 // contains the value `None`. Thus, it will never contain any
980 // unsafe values.
981 struct UnsafeMakeSync(Option<(token::Eq, Expr)>);
982 unsafe impl Sync for UnsafeMakeSync {}
983 static NONE_DISCRIMINANT: UnsafeMakeSync = UnsafeMakeSync(None);
984
985 vec![VariantInfo::new(
986 VariantAst {
987 attrs: &ast.attrs,
988 ident: &ast.ident,
989 fields: &data.fields,
990 discriminant: &NONE_DISCRIMINANT.0,
991 },
992 None,
993 &ast.generics,
994 )]
995 }
996 Data::Union(_) => {
997 return Err(Error::new_spanned(
998 ast,
999 "unexpected unsupported untagged union",
1000 ));
1001 }
1002 };
1003
1004 Ok(Structure {
1005 variants,
1006 omitted_variants: false,
1007 ast,
1008 extra_impl: vec![],
1009 extra_predicates: vec![],
1010 add_bounds: AddBounds::Both,
1011 })
1012 }
1013
1014 /// Returns a slice of the variants in this Structure.
variants(&self) -> &[VariantInfo<'a>]1015 pub fn variants(&self) -> &[VariantInfo<'a>] {
1016 &self.variants
1017 }
1018
1019 /// Returns a mut slice of the variants in this Structure.
variants_mut(&mut self) -> &mut [VariantInfo<'a>]1020 pub fn variants_mut(&mut self) -> &mut [VariantInfo<'a>] {
1021 &mut self.variants
1022 }
1023
1024 /// Returns a reference to the underlying `syn` AST node which this
1025 /// `Structure` was created from.
ast(&self) -> &'a DeriveInput1026 pub fn ast(&self) -> &'a DeriveInput {
1027 self.ast
1028 }
1029
1030 /// True if any variants were omitted due to a `filter_variants` call.
omitted_variants(&self) -> bool1031 pub fn omitted_variants(&self) -> bool {
1032 self.omitted_variants
1033 }
1034
1035 /// Runs the passed-in function once for each bound field, passing in a `BindingInfo`.
1036 /// and generating `match` arms which evaluate the returned tokens.
1037 ///
1038 /// This method will ignore variants or fields which are ignored through the
1039 /// `filter` and `filter_variant` methods.
1040 ///
1041 /// # Example
1042 /// ```
1043 /// # use synstructure::*;
1044 /// let di: syn::DeriveInput = syn::parse_quote! {
1045 /// enum A {
1046 /// B(i32, i32),
1047 /// C(u32),
1048 /// }
1049 /// };
1050 /// let s = Structure::new(&di);
1051 ///
1052 /// assert_eq!(
1053 /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(),
1054 ///
1055 /// quote!{
1056 /// A::B(ref __binding_0, ref __binding_1,) => {
1057 /// { println!("{:?}", __binding_0) }
1058 /// { println!("{:?}", __binding_1) }
1059 /// }
1060 /// A::C(ref __binding_0,) => {
1061 /// { println!("{:?}", __binding_0) }
1062 /// }
1063 /// }.to_string()
1064 /// );
1065 /// ```
each<F, R>(&self, mut f: F) -> TokenStream where F: FnMut(&BindingInfo<'_>) -> R, R: ToTokens,1066 pub fn each<F, R>(&self, mut f: F) -> TokenStream
1067 where
1068 F: FnMut(&BindingInfo<'_>) -> R,
1069 R: ToTokens,
1070 {
1071 let mut t = TokenStream::new();
1072 for variant in &self.variants {
1073 variant.each(&mut f).to_tokens(&mut t);
1074 }
1075 if self.omitted_variants {
1076 quote!(_ => {}).to_tokens(&mut t);
1077 }
1078 t
1079 }
1080
1081 /// Runs the passed-in function once for each bound field, passing in the
1082 /// result of the previous call, and a `BindingInfo`. generating `match`
1083 /// arms which evaluate to the resulting tokens.
1084 ///
1085 /// This method will ignore variants or fields which are ignored through the
1086 /// `filter` and `filter_variant` methods.
1087 ///
1088 /// If a variant has been ignored, it will return the `init` value.
1089 ///
1090 /// # Example
1091 /// ```
1092 /// # use synstructure::*;
1093 /// let di: syn::DeriveInput = syn::parse_quote! {
1094 /// enum A {
1095 /// B(i32, i32),
1096 /// C(u32),
1097 /// }
1098 /// };
1099 /// let s = Structure::new(&di);
1100 ///
1101 /// assert_eq!(
1102 /// s.fold(quote!(0), |acc, bi| quote!(#acc + #bi)).to_string(),
1103 ///
1104 /// quote!{
1105 /// A::B(ref __binding_0, ref __binding_1,) => {
1106 /// 0 + __binding_0 + __binding_1
1107 /// }
1108 /// A::C(ref __binding_0,) => {
1109 /// 0 + __binding_0
1110 /// }
1111 /// }.to_string()
1112 /// );
1113 /// ```
fold<F, I, R>(&self, init: I, mut f: F) -> TokenStream where F: FnMut(TokenStream, &BindingInfo<'_>) -> R, I: ToTokens, R: ToTokens,1114 pub fn fold<F, I, R>(&self, init: I, mut f: F) -> TokenStream
1115 where
1116 F: FnMut(TokenStream, &BindingInfo<'_>) -> R,
1117 I: ToTokens,
1118 R: ToTokens,
1119 {
1120 let mut t = TokenStream::new();
1121 for variant in &self.variants {
1122 variant.fold(&init, &mut f).to_tokens(&mut t);
1123 }
1124 if self.omitted_variants {
1125 quote!(_ => { #init }).to_tokens(&mut t);
1126 }
1127 t
1128 }
1129
1130 /// Runs the passed-in function once for each variant, passing in a
1131 /// `VariantInfo`. and generating `match` arms which evaluate the returned
1132 /// tokens.
1133 ///
1134 /// This method will ignore variants and not bind fields which are ignored
1135 /// through the `filter` and `filter_variant` methods.
1136 ///
1137 /// # Example
1138 /// ```
1139 /// # use synstructure::*;
1140 /// let di: syn::DeriveInput = syn::parse_quote! {
1141 /// enum A {
1142 /// B(i32, i32),
1143 /// C(u32),
1144 /// }
1145 /// };
1146 /// let s = Structure::new(&di);
1147 ///
1148 /// assert_eq!(
1149 /// s.each_variant(|v| {
1150 /// let name = &v.ast().ident;
1151 /// quote!(println!(stringify!(#name)))
1152 /// }).to_string(),
1153 ///
1154 /// quote!{
1155 /// A::B(ref __binding_0, ref __binding_1,) => {
1156 /// println!(stringify!(B))
1157 /// }
1158 /// A::C(ref __binding_0,) => {
1159 /// println!(stringify!(C))
1160 /// }
1161 /// }.to_string()
1162 /// );
1163 /// ```
each_variant<F, R>(&self, mut f: F) -> TokenStream where F: FnMut(&VariantInfo<'_>) -> R, R: ToTokens,1164 pub fn each_variant<F, R>(&self, mut f: F) -> TokenStream
1165 where
1166 F: FnMut(&VariantInfo<'_>) -> R,
1167 R: ToTokens,
1168 {
1169 let mut t = TokenStream::new();
1170 for variant in &self.variants {
1171 let pat = variant.pat();
1172 let body = f(variant);
1173 quote!(#pat => { #body }).to_tokens(&mut t);
1174 }
1175 if self.omitted_variants {
1176 quote!(_ => {}).to_tokens(&mut t);
1177 }
1178 t
1179 }
1180
1181 /// Filter the bindings created by this `Structure` object. This has 2 effects:
1182 ///
1183 /// * The bindings will no longer appear in match arms generated by methods
1184 /// on this `Structure` or its subobjects.
1185 ///
1186 /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl`
1187 /// method only consider type parameters referenced in the types of
1188 /// non-filtered fields.
1189 ///
1190 /// # Example
1191 /// ```
1192 /// # use synstructure::*;
1193 /// let di: syn::DeriveInput = syn::parse_quote! {
1194 /// enum A {
1195 /// B{ a: i32, b: i32 },
1196 /// C{ a: u32 },
1197 /// }
1198 /// };
1199 /// let mut s = Structure::new(&di);
1200 ///
1201 /// s.filter(|bi| {
1202 /// bi.ast().ident == Some(quote::format_ident!("a"))
1203 /// });
1204 ///
1205 /// assert_eq!(
1206 /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(),
1207 ///
1208 /// quote!{
1209 /// A::B{ a: ref __binding_0, .. } => {
1210 /// { println!("{:?}", __binding_0) }
1211 /// }
1212 /// A::C{ a: ref __binding_0, } => {
1213 /// { println!("{:?}", __binding_0) }
1214 /// }
1215 /// }.to_string()
1216 /// );
1217 /// ```
filter<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&BindingInfo<'_>) -> bool,1218 pub fn filter<F>(&mut self, mut f: F) -> &mut Self
1219 where
1220 F: FnMut(&BindingInfo<'_>) -> bool,
1221 {
1222 for variant in &mut self.variants {
1223 variant.filter(&mut f);
1224 }
1225 self
1226 }
1227
1228 /// Specify additional where predicate bounds which should be generated by
1229 /// impl-generating functions such as `gen_impl`, `bound_impl`, and
1230 /// `unsafe_bound_impl`.
1231 ///
1232 /// # Example
1233 /// ```
1234 /// # use synstructure::*;
1235 /// let di: syn::DeriveInput = syn::parse_quote! {
1236 /// enum A<T, U> {
1237 /// B(T),
1238 /// C(Option<U>),
1239 /// }
1240 /// };
1241 /// let mut s = Structure::new(&di);
1242 ///
1243 /// // Add an additional where predicate.
1244 /// s.add_where_predicate(syn::parse_quote!(T: std::fmt::Display));
1245 ///
1246 /// assert_eq!(
1247 /// s.bound_impl(quote!(krate::Trait), quote!{
1248 /// fn a() {}
1249 /// }).to_string(),
1250 /// quote!{
1251 /// #[allow(non_upper_case_globals)]
1252 /// #[doc(hidden)]
1253 /// const _DERIVE_krate_Trait_FOR_A: () = {
1254 /// extern crate krate;
1255 /// impl<T, U> krate::Trait for A<T, U>
1256 /// where T: std::fmt::Display,
1257 /// T: krate::Trait,
1258 /// Option<U>: krate::Trait,
1259 /// U: krate::Trait
1260 /// {
1261 /// fn a() {}
1262 /// }
1263 /// };
1264 /// }.to_string()
1265 /// );
1266 /// ```
add_where_predicate(&mut self, pred: WherePredicate) -> &mut Self1267 pub fn add_where_predicate(&mut self, pred: WherePredicate) -> &mut Self {
1268 self.extra_predicates.push(pred);
1269 self
1270 }
1271
1272 /// Specify which bounds should be generated by impl-generating functions
1273 /// such as `gen_impl`, `bound_impl`, and `unsafe_bound_impl`.
1274 ///
1275 /// The default behaviour is to generate both field and generic bounds from
1276 /// type parameters.
1277 ///
1278 /// # Example
1279 /// ```
1280 /// # use synstructure::*;
1281 /// let di: syn::DeriveInput = syn::parse_quote! {
1282 /// enum A<T, U> {
1283 /// B(T),
1284 /// C(Option<U>),
1285 /// }
1286 /// };
1287 /// let mut s = Structure::new(&di);
1288 ///
1289 /// // Limit bounds to only generics.
1290 /// s.add_bounds(AddBounds::Generics);
1291 ///
1292 /// assert_eq!(
1293 /// s.bound_impl(quote!(krate::Trait), quote!{
1294 /// fn a() {}
1295 /// }).to_string(),
1296 /// quote!{
1297 /// #[allow(non_upper_case_globals)]
1298 /// #[doc(hidden)]
1299 /// const _DERIVE_krate_Trait_FOR_A: () = {
1300 /// extern crate krate;
1301 /// impl<T, U> krate::Trait for A<T, U>
1302 /// where T: krate::Trait,
1303 /// U: krate::Trait
1304 /// {
1305 /// fn a() {}
1306 /// }
1307 /// };
1308 /// }.to_string()
1309 /// );
1310 /// ```
add_bounds(&mut self, mode: AddBounds) -> &mut Self1311 pub fn add_bounds(&mut self, mode: AddBounds) -> &mut Self {
1312 self.add_bounds = mode;
1313 self
1314 }
1315
1316 /// Filter the variants matched by this `Structure` object. This has 2 effects:
1317 ///
1318 /// * Match arms destructuring these variants will no longer be generated by
1319 /// methods on this `Structure`
1320 ///
1321 /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl`
1322 /// method only consider type parameters referenced in the types of
1323 /// fields in non-fitered variants.
1324 ///
1325 /// # Example
1326 /// ```
1327 /// # use synstructure::*;
1328 /// let di: syn::DeriveInput = syn::parse_quote! {
1329 /// enum A {
1330 /// B(i32, i32),
1331 /// C(u32),
1332 /// }
1333 /// };
1334 ///
1335 /// let mut s = Structure::new(&di);
1336 ///
1337 /// s.filter_variants(|v| v.ast().ident != "B");
1338 ///
1339 /// assert_eq!(
1340 /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(),
1341 ///
1342 /// quote!{
1343 /// A::C(ref __binding_0,) => {
1344 /// { println!("{:?}", __binding_0) }
1345 /// }
1346 /// _ => {}
1347 /// }.to_string()
1348 /// );
1349 /// ```
filter_variants<F>(&mut self, f: F) -> &mut Self where F: FnMut(&VariantInfo<'_>) -> bool,1350 pub fn filter_variants<F>(&mut self, f: F) -> &mut Self
1351 where
1352 F: FnMut(&VariantInfo<'_>) -> bool,
1353 {
1354 let before_len = self.variants.len();
1355 self.variants.retain(f);
1356 if self.variants.len() != before_len {
1357 self.omitted_variants = true;
1358 }
1359 self
1360 }
1361
1362 /// Remove the variant at the given index.
1363 ///
1364 /// # Panics
1365 ///
1366 /// Panics if the index is out of range.
remove_variant(&mut self, idx: usize) -> &mut Self1367 pub fn remove_variant(&mut self, idx: usize) -> &mut Self {
1368 self.variants.remove(idx);
1369 self.omitted_variants = true;
1370 self
1371 }
1372
1373 /// Updates the `BindStyle` for each of the passed-in fields by calling the
1374 /// passed-in function for each `BindingInfo`.
1375 ///
1376 /// # Example
1377 /// ```
1378 /// # use synstructure::*;
1379 /// let di: syn::DeriveInput = syn::parse_quote! {
1380 /// enum A {
1381 /// B(i32, i32),
1382 /// C(u32),
1383 /// }
1384 /// };
1385 /// let mut s = Structure::new(&di);
1386 ///
1387 /// s.bind_with(|bi| BindStyle::RefMut);
1388 ///
1389 /// assert_eq!(
1390 /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(),
1391 ///
1392 /// quote!{
1393 /// A::B(ref mut __binding_0, ref mut __binding_1,) => {
1394 /// { println!("{:?}", __binding_0) }
1395 /// { println!("{:?}", __binding_1) }
1396 /// }
1397 /// A::C(ref mut __binding_0,) => {
1398 /// { println!("{:?}", __binding_0) }
1399 /// }
1400 /// }.to_string()
1401 /// );
1402 /// ```
bind_with<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&BindingInfo<'_>) -> BindStyle,1403 pub fn bind_with<F>(&mut self, mut f: F) -> &mut Self
1404 where
1405 F: FnMut(&BindingInfo<'_>) -> BindStyle,
1406 {
1407 for variant in &mut self.variants {
1408 variant.bind_with(&mut f);
1409 }
1410 self
1411 }
1412
1413 /// Updates the binding name for each fo the passed-in fields by calling the
1414 /// passed-in function for each `BindingInfo`.
1415 ///
1416 /// The function will be called with the `BindingInfo` and its index in the
1417 /// enclosing variant.
1418 ///
1419 /// The default name is `__binding_{}` where `{}` is replaced with an
1420 /// increasing number.
1421 ///
1422 /// # Example
1423 /// ```
1424 /// # use synstructure::*;
1425 /// let di: syn::DeriveInput = syn::parse_quote! {
1426 /// enum A {
1427 /// B{ a: i32, b: i32 },
1428 /// C{ a: u32 },
1429 /// }
1430 /// };
1431 /// let mut s = Structure::new(&di);
1432 ///
1433 /// s.binding_name(|bi, i| bi.ident.clone().unwrap());
1434 ///
1435 /// assert_eq!(
1436 /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(),
1437 ///
1438 /// quote!{
1439 /// A::B{ a: ref a, b: ref b, } => {
1440 /// { println!("{:?}", a) }
1441 /// { println!("{:?}", b) }
1442 /// }
1443 /// A::C{ a: ref a, } => {
1444 /// { println!("{:?}", a) }
1445 /// }
1446 /// }.to_string()
1447 /// );
1448 /// ```
binding_name<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&Field, usize) -> Ident,1449 pub fn binding_name<F>(&mut self, mut f: F) -> &mut Self
1450 where
1451 F: FnMut(&Field, usize) -> Ident,
1452 {
1453 for variant in &mut self.variants {
1454 variant.binding_name(&mut f);
1455 }
1456 self
1457 }
1458
1459 /// Returns a list of the type parameters which are refrenced in the types
1460 /// of non-filtered fields / variants.
1461 ///
1462 /// # Caveat
1463 ///
1464 /// If the struct contains any macros in type position, all parameters will
1465 /// be considered bound. This is because we cannot determine which type
1466 /// parameters are bound by type macros.
1467 ///
1468 /// # Example
1469 /// ```
1470 /// # use synstructure::*;
1471 /// let di: syn::DeriveInput = syn::parse_quote! {
1472 /// enum A<T, U> {
1473 /// B(T, i32),
1474 /// C(Option<U>),
1475 /// }
1476 /// };
1477 /// let mut s = Structure::new(&di);
1478 ///
1479 /// s.filter_variants(|v| v.ast().ident != "C");
1480 ///
1481 /// assert_eq!(
1482 /// s.referenced_ty_params(),
1483 /// &["e::format_ident!("T")]
1484 /// );
1485 /// ```
referenced_ty_params(&self) -> Vec<&'a Ident>1486 pub fn referenced_ty_params(&self) -> Vec<&'a Ident> {
1487 let mut flags = Vec::new();
1488 for variant in &self.variants {
1489 for binding in &variant.bindings {
1490 generics_fuse(&mut flags, &binding.seen_generics);
1491 }
1492 }
1493 fetch_generics(&flags, &self.ast.generics)
1494 }
1495
1496 /// Adds an `impl<>` generic parameter.
1497 /// This can be used when the trait to be derived needs some extra generic parameters.
1498 ///
1499 /// # Example
1500 /// ```
1501 /// # use synstructure::*;
1502 /// let di: syn::DeriveInput = syn::parse_quote! {
1503 /// enum A<T, U> {
1504 /// B(T),
1505 /// C(Option<U>),
1506 /// }
1507 /// };
1508 /// let mut s = Structure::new(&di);
1509 /// let generic: syn::GenericParam = syn::parse_quote!(X: krate::AnotherTrait);
1510 ///
1511 /// assert_eq!(
1512 /// s.add_impl_generic(generic)
1513 /// .bound_impl(quote!(krate::Trait<X>),
1514 /// quote!{
1515 /// fn a() {}
1516 /// }
1517 /// ).to_string(),
1518 /// quote!{
1519 /// #[allow(non_upper_case_globals)]
1520 /// #[doc(hidden)]
1521 /// const _DERIVE_krate_Trait_X_FOR_A: () = {
1522 /// extern crate krate;
1523 /// impl<T, U, X: krate::AnotherTrait> krate::Trait<X> for A<T, U>
1524 /// where T : krate :: Trait < X >,
1525 /// Option<U>: krate::Trait<X>,
1526 /// U: krate::Trait<X>
1527 /// {
1528 /// fn a() {}
1529 /// }
1530 /// };
1531 /// }.to_string()
1532 /// );
1533 /// ```
add_impl_generic(&mut self, param: GenericParam) -> &mut Self1534 pub fn add_impl_generic(&mut self, param: GenericParam) -> &mut Self {
1535 self.extra_impl.push(param);
1536 self
1537 }
1538
1539 /// Add trait bounds for a trait with the given path for each type parmaeter
1540 /// referenced in the types of non-filtered fields.
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.
add_trait_bounds( &self, bound: &TraitBound, where_clause: &mut Option<WhereClause>, mode: AddBounds, )1547 pub fn add_trait_bounds(
1548 &self,
1549 bound: &TraitBound,
1550 where_clause: &mut Option<WhereClause>,
1551 mode: AddBounds,
1552 ) {
1553 // If we have any explicit where predicates, make sure to add them first.
1554 if !self.extra_predicates.is_empty() {
1555 let clause = get_or_insert_with(&mut *where_clause, || WhereClause {
1556 where_token: Default::default(),
1557 predicates: punctuated::Punctuated::new(),
1558 });
1559 clause
1560 .predicates
1561 .extend(self.extra_predicates.iter().cloned());
1562 }
1563
1564 let mut seen = HashSet::new();
1565 let mut pred = |ty: Type| {
1566 if !seen.contains(&ty) {
1567 seen.insert(ty.clone());
1568
1569 // Add a predicate.
1570 let clause = get_or_insert_with(&mut *where_clause, || WhereClause {
1571 where_token: Default::default(),
1572 predicates: punctuated::Punctuated::new(),
1573 });
1574 clause.predicates.push(WherePredicate::Type(PredicateType {
1575 lifetimes: None,
1576 bounded_ty: ty,
1577 colon_token: Default::default(),
1578 bounds: Some(punctuated::Pair::End(TypeParamBound::Trait(bound.clone())))
1579 .into_iter()
1580 .collect(),
1581 }));
1582 }
1583 };
1584
1585 for variant in &self.variants {
1586 for binding in &variant.bindings {
1587 match mode {
1588 AddBounds::Both | AddBounds::Fields => {
1589 for &seen in &binding.seen_generics {
1590 if seen {
1591 pred(binding.ast().ty.clone());
1592 break;
1593 }
1594 }
1595 }
1596 _ => {}
1597 }
1598
1599 match mode {
1600 AddBounds::Both | AddBounds::Generics => {
1601 for param in binding.referenced_ty_params() {
1602 pred(Type::Path(TypePath {
1603 qself: None,
1604 path: (*param).clone().into(),
1605 }));
1606 }
1607 }
1608 _ => {}
1609 }
1610 }
1611 }
1612 }
1613
1614 /// > NOTE: This methods' features are superceded by `Structure::gen_impl`.
1615 ///
1616 /// Creates an `impl` block with the required generic type fields filled in
1617 /// to implement the trait `path`.
1618 ///
1619 /// This method also adds where clauses to the impl requiring that all
1620 /// referenced type parmaeters implement the trait `path`.
1621 ///
1622 /// # Hygiene and Paths
1623 ///
1624 /// This method wraps the impl block inside of a `const` (see the example
1625 /// below). In this scope, the first segment of the passed-in path is
1626 /// `extern crate`-ed in. If you don't want to generate that `extern crate`
1627 /// item, use a global path.
1628 ///
1629 /// This means that if you are implementing `my_crate::Trait`, you simply
1630 /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the
1631 /// entirety of the definition, you can refer to your crate as `my_crate`.
1632 ///
1633 /// # Caveat
1634 ///
1635 /// If the method contains any macros in type position, all parameters will
1636 /// be considered bound. This is because we cannot determine which type
1637 /// parameters are bound by type macros.
1638 ///
1639 /// # Panics
1640 ///
1641 /// Panics if the path string parameter is not a valid `TraitBound`.
1642 ///
1643 /// # Example
1644 /// ```
1645 /// # use synstructure::*;
1646 /// let di: syn::DeriveInput = syn::parse_quote! {
1647 /// enum A<T, U> {
1648 /// B(T),
1649 /// C(Option<U>),
1650 /// }
1651 /// };
1652 /// let mut s = Structure::new(&di);
1653 ///
1654 /// s.filter_variants(|v| v.ast().ident != "B");
1655 ///
1656 /// assert_eq!(
1657 /// s.bound_impl(quote!(krate::Trait), quote!{
1658 /// fn a() {}
1659 /// }).to_string(),
1660 /// quote!{
1661 /// #[allow(non_upper_case_globals)]
1662 /// #[doc(hidden)]
1663 /// const _DERIVE_krate_Trait_FOR_A: () = {
1664 /// extern crate krate;
1665 /// impl<T, U> krate::Trait for A<T, U>
1666 /// where Option<U>: krate::Trait,
1667 /// U: krate::Trait
1668 /// {
1669 /// fn a() {}
1670 /// }
1671 /// };
1672 /// }.to_string()
1673 /// );
1674 /// ```
bound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream1675 pub fn bound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream {
1676 self.impl_internal(
1677 path.into_token_stream(),
1678 body.into_token_stream(),
1679 quote!(),
1680 None,
1681 )
1682 }
1683
1684 /// > NOTE: This methods' features are superceded by `Structure::gen_impl`.
1685 ///
1686 /// Creates an `impl` block with the required generic type fields filled in
1687 /// to implement the unsafe trait `path`.
1688 ///
1689 /// This method also adds where clauses to the impl requiring that all
1690 /// referenced type parmaeters implement the trait `path`.
1691 ///
1692 /// # Hygiene and Paths
1693 ///
1694 /// This method wraps the impl block inside of a `const` (see the example
1695 /// below). In this scope, the first segment of the passed-in path is
1696 /// `extern crate`-ed in. If you don't want to generate that `extern crate`
1697 /// item, use a global path.
1698 ///
1699 /// This means that if you are implementing `my_crate::Trait`, you simply
1700 /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the
1701 /// entirety of the definition, you can refer to your crate as `my_crate`.
1702 ///
1703 /// # Caveat
1704 ///
1705 /// If the method contains any macros in type position, all parameters will
1706 /// be considered bound. This is because we cannot determine which type
1707 /// parameters are bound by type macros.
1708 ///
1709 /// # Panics
1710 ///
1711 /// Panics if the path string parameter is not a valid `TraitBound`.
1712 ///
1713 /// # Example
1714 /// ```
1715 /// # use synstructure::*;
1716 /// let di: syn::DeriveInput = syn::parse_quote! {
1717 /// enum A<T, U> {
1718 /// B(T),
1719 /// C(Option<U>),
1720 /// }
1721 /// };
1722 /// let mut s = Structure::new(&di);
1723 ///
1724 /// s.filter_variants(|v| v.ast().ident != "B");
1725 ///
1726 /// assert_eq!(
1727 /// s.unsafe_bound_impl(quote!(krate::Trait), quote!{
1728 /// fn a() {}
1729 /// }).to_string(),
1730 /// quote!{
1731 /// #[allow(non_upper_case_globals)]
1732 /// #[doc(hidden)]
1733 /// const _DERIVE_krate_Trait_FOR_A: () = {
1734 /// extern crate krate;
1735 /// unsafe impl<T, U> krate::Trait for A<T, U>
1736 /// where Option<U>: krate::Trait,
1737 /// U: krate::Trait
1738 /// {
1739 /// fn a() {}
1740 /// }
1741 /// };
1742 /// }.to_string()
1743 /// );
1744 /// ```
unsafe_bound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream1745 pub fn unsafe_bound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream {
1746 self.impl_internal(
1747 path.into_token_stream(),
1748 body.into_token_stream(),
1749 quote!(unsafe),
1750 None,
1751 )
1752 }
1753
1754 /// > NOTE: This methods' features are superceded by `Structure::gen_impl`.
1755 ///
1756 /// Creates an `impl` block with the required generic type fields filled in
1757 /// to implement the trait `path`.
1758 ///
1759 /// This method will not add any where clauses to the impl.
1760 ///
1761 /// # Hygiene and Paths
1762 ///
1763 /// This method wraps the impl block inside of a `const` (see the example
1764 /// below). In this scope, the first segment of the passed-in path is
1765 /// `extern crate`-ed in. If you don't want to generate that `extern crate`
1766 /// item, use a global path.
1767 ///
1768 /// This means that if you are implementing `my_crate::Trait`, you simply
1769 /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the
1770 /// entirety of the definition, you can refer to your crate as `my_crate`.
1771 ///
1772 /// # Panics
1773 ///
1774 /// Panics if the path string parameter is not a valid `TraitBound`.
1775 ///
1776 /// # Example
1777 /// ```
1778 /// # use synstructure::*;
1779 /// let di: syn::DeriveInput = syn::parse_quote! {
1780 /// enum A<T, U> {
1781 /// B(T),
1782 /// C(Option<U>),
1783 /// }
1784 /// };
1785 /// let mut s = Structure::new(&di);
1786 ///
1787 /// s.filter_variants(|v| v.ast().ident != "B");
1788 ///
1789 /// assert_eq!(
1790 /// s.unbound_impl(quote!(krate::Trait), quote!{
1791 /// fn a() {}
1792 /// }).to_string(),
1793 /// quote!{
1794 /// #[allow(non_upper_case_globals)]
1795 /// #[doc(hidden)]
1796 /// const _DERIVE_krate_Trait_FOR_A: () = {
1797 /// extern crate krate;
1798 /// impl<T, U> krate::Trait for A<T, U> {
1799 /// fn a() {}
1800 /// }
1801 /// };
1802 /// }.to_string()
1803 /// );
1804 /// ```
unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream1805 pub fn unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream {
1806 self.impl_internal(
1807 path.into_token_stream(),
1808 body.into_token_stream(),
1809 quote!(),
1810 Some(AddBounds::None),
1811 )
1812 }
1813
1814 /// > NOTE: This methods' features are superceded by `Structure::gen_impl`.
1815 ///
1816 /// Creates an `impl` block with the required generic type fields filled in
1817 /// to implement the unsafe trait `path`.
1818 ///
1819 /// This method will not add any where clauses to the impl.
1820 ///
1821 /// # Hygiene and Paths
1822 ///
1823 /// This method wraps the impl block inside of a `const` (see the example
1824 /// below). In this scope, the first segment of the passed-in path is
1825 /// `extern crate`-ed in. If you don't want to generate that `extern crate`
1826 /// item, use a global path.
1827 ///
1828 /// This means that if you are implementing `my_crate::Trait`, you simply
1829 /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the
1830 /// entirety of the definition, you can refer to your crate as `my_crate`.
1831 ///
1832 /// # Panics
1833 ///
1834 /// Panics if the path string parameter is not a valid `TraitBound`.
1835 ///
1836 /// # Example
1837 /// ```
1838 /// # use synstructure::*;
1839 /// let di: syn::DeriveInput = syn::parse_quote! {
1840 /// enum A<T, U> {
1841 /// B(T),
1842 /// C(Option<U>),
1843 /// }
1844 /// };
1845 /// let mut s = Structure::new(&di);
1846 ///
1847 /// s.filter_variants(|v| v.ast().ident != "B");
1848 ///
1849 /// assert_eq!(
1850 /// s.unsafe_unbound_impl(quote!(krate::Trait), quote!{
1851 /// fn a() {}
1852 /// }).to_string(),
1853 /// quote!{
1854 /// #[allow(non_upper_case_globals)]
1855 /// #[doc(hidden)]
1856 /// const _DERIVE_krate_Trait_FOR_A: () = {
1857 /// extern crate krate;
1858 /// unsafe impl<T, U> krate::Trait for A<T, U> {
1859 /// fn a() {}
1860 /// }
1861 /// };
1862 /// }.to_string()
1863 /// );
1864 /// ```
1865 #[deprecated]
unsafe_unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream1866 pub fn unsafe_unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream {
1867 self.impl_internal(
1868 path.into_token_stream(),
1869 body.into_token_stream(),
1870 quote!(unsafe),
1871 Some(AddBounds::None),
1872 )
1873 }
1874
impl_internal( &self, path: TokenStream, body: TokenStream, safety: TokenStream, mode: Option<AddBounds>, ) -> TokenStream1875 fn impl_internal(
1876 &self,
1877 path: TokenStream,
1878 body: TokenStream,
1879 safety: TokenStream,
1880 mode: Option<AddBounds>,
1881 ) -> TokenStream {
1882 let mode = mode.unwrap_or(self.add_bounds);
1883 let name = &self.ast.ident;
1884 let mut gen_clone = self.ast.generics.clone();
1885 gen_clone.params.extend(self.extra_impl.clone().into_iter());
1886 let (impl_generics, _, _) = gen_clone.split_for_impl();
1887 let (_, ty_generics, where_clause) = self.ast.generics.split_for_impl();
1888
1889 let bound = syn::parse2::<TraitBound>(path)
1890 .expect("`path` argument must be a valid rust trait bound");
1891
1892 let mut where_clause = where_clause.cloned();
1893 self.add_trait_bounds(&bound, &mut where_clause, mode);
1894
1895 let dummy_const: Ident = sanitize_ident(&format!(
1896 "_DERIVE_{}_FOR_{}",
1897 (&bound).into_token_stream(),
1898 name.into_token_stream(),
1899 ));
1900
1901 // This function is smart. If a global path is passed, no extern crate
1902 // statement will be generated, however, a relative path will cause the
1903 // crate which it is relative to to be imported within the current
1904 // scope.
1905 let mut extern_crate = quote!();
1906 if bound.path.leading_colon.is_none() {
1907 if let Some(seg) = bound.path.segments.first() {
1908 let seg = &seg.ident;
1909 extern_crate = quote! { extern crate #seg; };
1910 }
1911 }
1912
1913 quote! {
1914 #[allow(non_upper_case_globals)]
1915 #[doc(hidden)]
1916 const #dummy_const: () = {
1917 #extern_crate
1918 #safety impl #impl_generics #bound for #name #ty_generics #where_clause {
1919 #body
1920 }
1921 };
1922 }
1923 }
1924
1925 /// Generate an impl block for the given struct. This impl block will
1926 /// automatically use hygiene tricks to avoid polluting the caller's
1927 /// namespace, and will automatically add trait bounds for generic type
1928 /// parameters.
1929 ///
1930 /// # Syntax
1931 ///
1932 /// This function accepts its arguments as a `TokenStream`. The recommended way
1933 /// to call this function is passing the result of invoking the `quote!`
1934 /// macro to it.
1935 ///
1936 /// ```ignore
1937 /// s.gen_impl(quote! {
1938 /// // You can write any items which you want to import into scope here.
1939 /// // For example, you may want to include an `extern crate` for the
1940 /// // crate which implements your trait. These items will only be
1941 /// // visible to the code you generate, and won't be exposed to the
1942 /// // consuming crate
1943 /// extern crate krate;
1944 ///
1945 /// // You can also add `use` statements here to bring types or traits
1946 /// // into scope.
1947 /// //
1948 /// // WARNING: Try not to use common names here, because the stable
1949 /// // version of syn does not support hygiene and you could accidentally
1950 /// // shadow types from the caller crate.
1951 /// use krate::Trait as MyTrait;
1952 ///
1953 /// // The actual impl block is a `gen impl` or `gen unsafe impl` block.
1954 /// // You can use `@Self` to refer to the structure's type.
1955 /// gen impl MyTrait for @Self {
1956 /// fn f(&self) { ... }
1957 /// }
1958 /// })
1959 /// ```
1960 ///
1961 /// The most common usage of this trait involves loading the crate the
1962 /// target trait comes from with `extern crate`, and then invoking a `gen
1963 /// impl` block.
1964 ///
1965 /// # Hygiene
1966 ///
1967 /// This method tries to handle hygiene intelligenly for both stable and
1968 /// unstable proc-macro implementations, however there are visible
1969 /// differences.
1970 ///
1971 /// The output of every `gen_impl` function is wrapped in a dummy `const`
1972 /// value, to ensure that it is given its own scope, and any values brought
1973 /// into scope are not leaked to the calling crate. For example, the above
1974 /// invocation may generate an output like the following:
1975 ///
1976 /// ```ignore
1977 /// const _DERIVE_krate_Trait_FOR_Struct: () = {
1978 /// extern crate krate;
1979 /// use krate::Trait as MyTrait;
1980 /// impl<T> MyTrait for Struct<T> where T: MyTrait {
1981 /// fn f(&self) { ... }
1982 /// }
1983 /// };
1984 /// ```
1985 ///
1986 /// ### Using the `std` crate
1987 ///
1988 /// If you are using `quote!()` to implement your trait, with the
1989 /// `proc-macro2/nightly` feature, `std` isn't considered to be in scope for
1990 /// your macro. This means that if you use types from `std` in your
1991 /// procedural macro, you'll want to explicitly load it with an `extern
1992 /// crate std;`.
1993 ///
1994 /// ### Absolute paths
1995 ///
1996 /// You should generally avoid using absolute paths in your generated code,
1997 /// as they will resolve very differently when using the stable and nightly
1998 /// versions of `proc-macro2`. Instead, load the crates you need to use
1999 /// explictly with `extern crate` and
2000 ///
2001 /// # Trait Bounds
2002 ///
2003 /// This method will automatically add trait bounds for any type parameters
2004 /// which are referenced within the types of non-ignored fields.
2005 ///
2006 /// Additional type parameters may be added with the generics syntax after
2007 /// the `impl` keyword.
2008 ///
2009 /// ### Type Macro Caveat
2010 ///
2011 /// If the method contains any macros in type position, all parameters will
2012 /// be considered bound. This is because we cannot determine which type
2013 /// parameters are bound by type macros.
2014 ///
2015 /// # Errors
2016 ///
2017 /// This function will generate a `compile_error!` if additional type
2018 /// parameters added by `impl<..>` conflict with generic type parameters on
2019 /// the original struct.
2020 ///
2021 /// # Panics
2022 ///
2023 /// This function will panic if the input `TokenStream` is not well-formed.
2024 ///
2025 /// # Example Usage
2026 ///
2027 /// ```
2028 /// # use synstructure::*;
2029 /// let di: syn::DeriveInput = syn::parse_quote! {
2030 /// enum A<T, U> {
2031 /// B(T),
2032 /// C(Option<U>),
2033 /// }
2034 /// };
2035 /// let mut s = Structure::new(&di);
2036 ///
2037 /// s.filter_variants(|v| v.ast().ident != "B");
2038 ///
2039 /// assert_eq!(
2040 /// s.gen_impl(quote! {
2041 /// extern crate krate;
2042 /// gen impl krate::Trait for @Self {
2043 /// fn a() {}
2044 /// }
2045 /// }).to_string(),
2046 /// quote!{
2047 /// #[allow(non_upper_case_globals)]
2048 /// const _DERIVE_krate_Trait_FOR_A: () = {
2049 /// extern crate krate;
2050 /// impl<T, U> krate::Trait for A<T, U>
2051 /// where
2052 /// Option<U>: krate::Trait,
2053 /// U: krate::Trait
2054 /// {
2055 /// fn a() {}
2056 /// }
2057 /// };
2058 /// }.to_string()
2059 /// );
2060 ///
2061 /// // NOTE: You can also add extra generics after the impl
2062 /// assert_eq!(
2063 /// s.gen_impl(quote! {
2064 /// extern crate krate;
2065 /// gen impl<X: krate::OtherTrait> krate::Trait<X> for @Self
2066 /// where
2067 /// X: Send + Sync,
2068 /// {
2069 /// fn a() {}
2070 /// }
2071 /// }).to_string(),
2072 /// quote!{
2073 /// #[allow(non_upper_case_globals)]
2074 /// const _DERIVE_krate_Trait_X_FOR_A: () = {
2075 /// extern crate krate;
2076 /// impl<X: krate::OtherTrait, T, U> krate::Trait<X> for A<T, U>
2077 /// where
2078 /// X: Send + Sync,
2079 /// Option<U>: krate::Trait<X>,
2080 /// U: krate::Trait<X>
2081 /// {
2082 /// fn a() {}
2083 /// }
2084 /// };
2085 /// }.to_string()
2086 /// );
2087 ///
2088 /// // NOTE: you can generate multiple traits with a single call
2089 /// assert_eq!(
2090 /// s.gen_impl(quote! {
2091 /// extern crate krate;
2092 ///
2093 /// gen impl krate::Trait for @Self {
2094 /// fn a() {}
2095 /// }
2096 ///
2097 /// gen impl krate::OtherTrait for @Self {
2098 /// fn b() {}
2099 /// }
2100 /// }).to_string(),
2101 /// quote!{
2102 /// #[allow(non_upper_case_globals)]
2103 /// const _DERIVE_krate_Trait_FOR_A: () = {
2104 /// extern crate krate;
2105 /// impl<T, U> krate::Trait for A<T, U>
2106 /// where
2107 /// Option<U>: krate::Trait,
2108 /// U: krate::Trait
2109 /// {
2110 /// fn a() {}
2111 /// }
2112 ///
2113 /// impl<T, U> krate::OtherTrait for A<T, U>
2114 /// where
2115 /// Option<U>: krate::OtherTrait,
2116 /// U: krate::OtherTrait
2117 /// {
2118 /// fn b() {}
2119 /// }
2120 /// };
2121 /// }.to_string()
2122 /// );
2123 /// ```
2124 ///
2125 /// Use `add_bounds` to change which bounds are generated.
gen_impl(&self, cfg: TokenStream) -> TokenStream2126 pub fn gen_impl(&self, cfg: TokenStream) -> TokenStream {
2127 Parser::parse2(
2128 |input: ParseStream<'_>| -> Result<TokenStream> { self.gen_impl_parse(input, true) },
2129 cfg,
2130 )
2131 .expect("Failed to parse gen_impl")
2132 }
2133
gen_impl_parse(&self, input: ParseStream<'_>, wrap: bool) -> Result<TokenStream>2134 fn gen_impl_parse(&self, input: ParseStream<'_>, wrap: bool) -> Result<TokenStream> {
2135 fn parse_prefix(input: ParseStream<'_>) -> Result<Option<Token![unsafe]>> {
2136 if input.parse::<Ident>()? != "gen" {
2137 return Err(input.error("Expected keyword `gen`"));
2138 }
2139 let safety = input.parse::<Option<Token![unsafe]>>()?;
2140 let _ = input.parse::<Token![impl]>()?;
2141 Ok(safety)
2142 }
2143
2144 let mut before = vec![];
2145 loop {
2146 if parse_prefix(&input.fork()).is_ok() {
2147 break;
2148 }
2149 before.push(input.parse::<TokenTree>()?);
2150 }
2151
2152 // Parse the prefix "for real"
2153 let safety = parse_prefix(input)?;
2154
2155 // optional `<>`
2156 let mut generics = input.parse::<Generics>()?;
2157
2158 // @bound
2159 let bound = input.parse::<TraitBound>()?;
2160
2161 // `for @Self`
2162 let _ = input.parse::<Token![for]>()?;
2163 let _ = input.parse::<Token![@]>()?;
2164 let _ = input.parse::<Token![Self]>()?;
2165
2166 // optional `where ...`
2167 generics.where_clause = input.parse()?;
2168
2169 // Body of the impl
2170 let body;
2171 braced!(body in input);
2172 let body = body.parse::<TokenStream>()?;
2173
2174 // Try to parse the next entry in sequence. If this fails, we'll fall
2175 // back to just parsing the entire rest of the TokenStream.
2176 let maybe_next_impl = self.gen_impl_parse(&input.fork(), false);
2177
2178 // Eat tokens to the end. Whether or not our speculative nested parse
2179 // succeeded, we're going to want to consume the rest of our input.
2180 let mut after = input.parse::<TokenStream>()?;
2181 if let Ok(stream) = maybe_next_impl {
2182 after = stream;
2183 }
2184 assert!(input.is_empty(), "Should've consumed the rest of our input");
2185
2186 /* Codegen Logic */
2187 let name = &self.ast.ident;
2188
2189 // Add the generics from the original struct in, and then add any
2190 // additional trait bounds which we need on the type.
2191 if let Err(err) = merge_generics(&mut generics, &self.ast.generics) {
2192 // Report the merge error as a `compile_error!`, as it may be
2193 // triggerable by an end-user.
2194 return Ok(err.to_compile_error());
2195 }
2196
2197 self.add_trait_bounds(&bound, &mut generics.where_clause, self.add_bounds);
2198 let (impl_generics, _, where_clause) = generics.split_for_impl();
2199 let (_, ty_generics, _) = self.ast.generics.split_for_impl();
2200
2201 let generated = quote! {
2202 #(#before)*
2203 #safety impl #impl_generics #bound for #name #ty_generics #where_clause {
2204 #body
2205 }
2206 #after
2207 };
2208
2209 if wrap {
2210 let dummy_const: Ident = sanitize_ident(&format!(
2211 "_DERIVE_{}_FOR_{}",
2212 (&bound).into_token_stream(),
2213 name.into_token_stream(),
2214 ));
2215
2216 Ok(quote! {
2217 #[allow(non_upper_case_globals)]
2218 const #dummy_const: () = {
2219 #generated
2220 };
2221 })
2222 } else {
2223 Ok(generated)
2224 }
2225 }
2226 }
2227
2228 /// Dumps an unpretty version of a tokenstream. Takes any type which implements
2229 /// `Display`.
2230 ///
2231 /// This is mostly useful for visualizing the output of a procedural macro, as
2232 /// it makes it marginally more readable. It is used in the implementation of
2233 /// `test_derive!` to unprettily print the output.
2234 ///
2235 /// # Stability
2236 ///
2237 /// The stability of the output of this function is not guaranteed. Do not
2238 /// assert that the output of this function does not change between minor
2239 /// versions.
2240 ///
2241 /// # Example
2242 ///
2243 /// ```
2244 /// # use quote::quote;
2245 /// assert_eq!(
2246 /// synstructure::unpretty_print(quote! {
2247 /// #[allow(non_upper_case_globals)]
2248 /// const _DERIVE_krate_Trait_FOR_A: () = {
2249 /// extern crate krate;
2250 /// impl<T, U> krate::Trait for A<T, U>
2251 /// where
2252 /// Option<U>: krate::Trait,
2253 /// U: krate::Trait
2254 /// {
2255 /// fn a() {}
2256 /// }
2257 /// };
2258 /// }),
2259 /// "# [
2260 /// allow (
2261 /// non_upper_case_globals )
2262 /// ]
2263 /// const _DERIVE_krate_Trait_FOR_A : (
2264 /// )
2265 /// = {
2266 /// extern crate krate ;
2267 /// impl < T , U > krate :: Trait for A < T , U > where Option < U > : krate :: Trait , U : krate :: Trait {
2268 /// fn a (
2269 /// )
2270 /// {
2271 /// }
2272 /// }
2273 /// }
2274 /// ;
2275 /// "
2276 /// )
2277 /// ```
unpretty_print<T: std::fmt::Display>(ts: T) -> String2278 pub fn unpretty_print<T: std::fmt::Display>(ts: T) -> String {
2279 let mut res = String::new();
2280
2281 let raw_s = ts.to_string();
2282 let mut s = &raw_s[..];
2283 let mut indent = 0;
2284 while let Some(i) = s.find(&['(', '{', '[', ')', '}', ']', ';'][..]) {
2285 match &s[i..=i] {
2286 "(" | "{" | "[" => indent += 1,
2287 ")" | "}" | "]" => indent -= 1,
2288 _ => {}
2289 }
2290 res.push_str(&s[..=i]);
2291 res.push('\n');
2292 for _ in 0..indent {
2293 res.push_str(" ");
2294 }
2295 s = trim_start_matches(&s[i + 1..], ' ');
2296 }
2297 res.push_str(s);
2298 res
2299 }
2300
2301 /// `trim_left_matches` has been deprecated in favor of `trim_start_matches`.
2302 /// This helper silences the warning, as we need to continue using
2303 /// `trim_left_matches` for rust 1.15 support.
2304 #[allow(deprecated)]
trim_start_matches(s: &str, c: char) -> &str2305 fn trim_start_matches(s: &str, c: char) -> &str {
2306 s.trim_left_matches(c)
2307 }
2308
2309 /// Helper trait describing values which may be returned by macro implementation
2310 /// methods used by this crate's macros.
2311 pub trait MacroResult {
2312 /// Convert this result into a `Result` for further processing / validation.
into_result(self) -> Result<TokenStream>2313 fn into_result(self) -> Result<TokenStream>;
2314
2315 /// Convert this result into a `proc_macro::TokenStream`, ready to return
2316 /// from a native `proc_macro` implementation.
2317 ///
2318 /// If `into_result()` would return an `Err`, this method should instead
2319 /// generate a `compile_error!` invocation to nicely report the error.
2320 ///
2321 /// *This method is available if `synstructure` is built with the
2322 /// `"proc-macro"` feature.*
2323 #[cfg(all(
2324 not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
2325 feature = "proc-macro"
2326 ))]
into_stream(self) -> proc_macro::TokenStream where Self: Sized,2327 fn into_stream(self) -> proc_macro::TokenStream
2328 where
2329 Self: Sized,
2330 {
2331 match self.into_result() {
2332 Ok(ts) => ts.into(),
2333 Err(err) => err.to_compile_error().into(),
2334 }
2335 }
2336 }
2337
2338 #[cfg(all(
2339 not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
2340 feature = "proc-macro"
2341 ))]
2342 impl MacroResult for proc_macro::TokenStream {
into_result(self) -> Result<TokenStream>2343 fn into_result(self) -> Result<TokenStream> {
2344 Ok(self.into())
2345 }
2346
into_stream(self) -> proc_macro::TokenStream2347 fn into_stream(self) -> proc_macro::TokenStream {
2348 self
2349 }
2350 }
2351
2352 impl MacroResult for TokenStream {
into_result(self) -> Result<TokenStream>2353 fn into_result(self) -> Result<TokenStream> {
2354 Ok(self)
2355 }
2356 }
2357
2358 impl<T: MacroResult> MacroResult for Result<T> {
into_result(self) -> Result<TokenStream>2359 fn into_result(self) -> Result<TokenStream> {
2360 match self {
2361 Ok(v) => v.into_result(),
2362 Err(err) => Err(err),
2363 }
2364 }
2365 }
2366