impl_trait_for_tuples/
semi_automatic.rs

1//! Implementation of the semi-automatic tuple trait implementation.
2//!
3//! The semi-automatic implementation uses an implementation provided by the user to generate the
4//! tuple implementations. The user is able to use a special syntax `for_tuples!( #(TUPLE)* );` to
5//! express the tuple access while the `TUPLE` ident can be chosen by the user.
6
7use proc_macro2::TokenStream;
8
9use syn::{
10    bracketed,
11    fold::{self, Fold},
12    parenthesized,
13    parse::{Parse, ParseStream},
14    parse_quote,
15    spanned::Spanned,
16    token, Block, Error, Expr, ExprField, FnArg, Ident, ImplItem, ImplItemMethod, Index, ItemImpl,
17    Macro, Member, Result, Stmt, Type, WhereClause, WherePredicate,
18};
19
20use quote::{quote, ToTokens};
21
22/// By default we add the trait bound for the implemented trait to each tuple type. When this
23/// attribute is given we don't add this bound.
24const TUPLE_TYPES_NO_DEFAULT_TRAIT_BOUND: &str = "tuple_types_no_default_trait_bound";
25const TUPLE_TYPES_CUSTOM_TRAIT_BOUND: &str = "tuple_types_custom_trait_bound";
26
27/// The supported separators in the `#( Tuple::test() )SEPARATOR*` syntax.
28enum Separator {
29    Comma(token::Comma),
30    Add(token::Add),
31    Sub(token::Sub),
32    Or(token::Or),
33    And(token::And),
34    Star(token::Star),
35    Div(token::Div),
36}
37
38impl Separator {
39    /// Try to parse the separator before the `*` token.
40    fn parse_before_star(input: ParseStream) -> Result<Option<Self>> {
41        if input.peek2(token::Star) {
42            Self::parse(input).map(Some)
43        } else {
44            Ok(None)
45        }
46    }
47
48    /// Convert into a `TokenStream`.
49    ///
50    /// `last` - Is this the last separator to add? Only `,` will be added on `last == true`.
51    fn to_token_stream(&self, last: bool) -> TokenStream {
52        let empty_on_last = |token: &dyn ToTokens| {
53            if last {
54                TokenStream::default()
55            } else {
56                token.to_token_stream()
57            }
58        };
59
60        match self {
61            Self::Comma(comma) => comma.to_token_stream(),
62            Self::Add(add) => empty_on_last(add),
63            Self::Sub(sub) => empty_on_last(sub),
64            Self::Or(or) => empty_on_last(or),
65            Self::And(and) => empty_on_last(and),
66            Self::Star(star) => empty_on_last(star),
67            Self::Div(div) => empty_on_last(div),
68        }
69    }
70}
71
72impl Parse for Separator {
73    fn parse(input: ParseStream) -> Result<Self> {
74        let lookahead1 = input.lookahead1();
75
76        if lookahead1.peek(token::Comma) {
77            Ok(Self::Comma(input.parse()?))
78        } else if lookahead1.peek(token::Add) {
79            Ok(Self::Add(input.parse()?))
80        } else if lookahead1.peek(token::Sub) {
81            Ok(Self::Sub(input.parse()?))
82        } else if lookahead1.peek(token::Or) {
83            Ok(Self::Or(input.parse()?))
84        } else if lookahead1.peek(token::And) {
85            Ok(Self::And(input.parse()?))
86        } else if lookahead1.peek(token::Star) {
87            Ok(Self::Star(input.parse()?))
88        } else if lookahead1.peek(token::Div) {
89            Ok(Self::Div(input.parse()?))
90        } else {
91            Err(lookahead1.error())
92        }
93    }
94}
95
96/// The different kind of repetitions that can be found in a [`TupleRepetition`].
97enum Repetition {
98    Stmts(Vec<Stmt>),
99    Type(Type),
100    Where(WherePredicate),
101}
102
103/// The `#( Tuple::test() )SEPARATOR*` (tuple repetition) syntax.
104struct TupleRepetition {
105    pub pound_token: token::Pound,
106    pub _paren_token: token::Paren,
107    pub repetition: Repetition,
108    pub separator: Option<Separator>,
109    pub _star_token: token::Star,
110}
111
112impl TupleRepetition {
113    /// Parse the inner representation as stmts.
114    fn parse_as_stmts(input: ParseStream) -> Result<Self> {
115        let content;
116        Ok(Self {
117            pound_token: input.parse()?,
118            _paren_token: parenthesized!(content in input),
119            repetition: Repetition::Stmts(content.call(Block::parse_within)?),
120            separator: Separator::parse_before_star(input)?,
121            _star_token: input.parse()?,
122        })
123    }
124
125    /// Parse the inner representation as a where predicate.
126    fn parse_as_where_predicate(input: ParseStream) -> Result<Self> {
127        let content;
128        Ok(Self {
129            pound_token: input.parse()?,
130            _paren_token: parenthesized!(content in input),
131            repetition: Repetition::Where(content.parse()?),
132            separator: Separator::parse_before_star(input)?,
133            _star_token: input.parse()?,
134        })
135    }
136
137    /// Parse the inner representation as a type.
138    fn parse_as_type(input: ParseStream) -> Result<Self> {
139        let content;
140        Ok(Self {
141            pound_token: input.parse()?,
142            _paren_token: parenthesized!(content in input),
143            repetition: Repetition::Type(content.parse()?),
144            separator: Separator::parse_before_star(input)?,
145            _star_token: input.parse()?,
146        })
147    }
148
149    /// Expand this repetition to the actual stmts implementation.
150    fn expand_as_stmts(
151        self,
152        tuple_placeholder_ident: &Ident,
153        tuples: &[Ident],
154        use_self: bool,
155    ) -> Result<TokenStream> {
156        let mut generated = TokenStream::new();
157        let span = self.pound_token.span();
158        let stmts = match self.repetition {
159            Repetition::Stmts(stmts) => stmts,
160            _ => return Err(Error::new(
161                span,
162                "Internal error, expected `repetition` to be of type `Stmts`! Please report this issue!",
163            )),
164        };
165
166        for (i, tuple) in tuples.iter().enumerate() {
167            generated.extend(stmts.iter().cloned().map(|s| {
168                ReplaceTuplePlaceholder::replace_ident_in_stmt(
169                    tuple_placeholder_ident,
170                    tuple,
171                    use_self,
172                    i,
173                    s,
174                )
175                .map(|s| s.to_token_stream())
176                .unwrap_or_else(|e| e.to_compile_error())
177            }));
178
179            if let Some(ref sep) = self.separator {
180                generated.extend(sep.to_token_stream(i + 1 == tuples.len()));
181            }
182        }
183
184        Ok(generated)
185    }
186
187    /// Expand this repetition to the actual type declaration.
188    fn expand_as_type_declaration(
189        self,
190        tuple_placeholder_ident: &Ident,
191        tuples: &[Ident],
192    ) -> Result<TokenStream> {
193        let mut generated = TokenStream::new();
194        let span = self.pound_token.span();
195        let ty = match self.repetition {
196            Repetition::Type(ty) => ty,
197            _ => return Err(Error::new(
198                span,
199                "Internal error, expected `repetition` to be of type `Type`! Please report this issue!",
200            )),
201        };
202
203        for (i, tuple) in tuples.iter().enumerate() {
204            generated.extend(
205                ReplaceTuplePlaceholder::replace_ident_in_type(tuple_placeholder_ident, tuple, ty.clone())
206                    .map(|s| s.to_token_stream())
207                    .unwrap_or_else(|e| e.to_compile_error()),
208            );
209
210            if let Some(ref sep) = self.separator {
211                generated.extend(sep.to_token_stream(i + 1 == tuples.len()));
212            }
213        }
214
215        Ok(generated)
216    }
217
218    /// Expand this to the given `where_clause`.
219    /// It is expected that the instance was created with `parse_as_where_predicate`.
220    fn expand_to_where_clause(
221        self,
222        tuple_placeholder_ident: &Ident,
223        tuples: &[Ident],
224        where_clause: &mut WhereClause,
225    ) -> Result<()> {
226        let span = self.pound_token.span();
227        let predicate = match self.repetition {
228            Repetition::Where(pred) => pred,
229            _ => return Err(Error::new(
230                span,
231                "Internal error, expected `repetition` to be of type `Where`! Please report this issue!",
232            )),
233        };
234
235        for tuple in tuples.iter() {
236            where_clause.predicates.push(
237                ReplaceTuplePlaceholder::replace_ident_in_where_predicate(
238                    tuple_placeholder_ident,
239                    tuple,
240                    predicate.clone(),
241                )?,
242            );
243        }
244
245        Ok(())
246    }
247}
248
249/// Replace the tuple place holder in the ast.
250struct ReplaceTuplePlaceholder<'a> {
251    search: &'a Ident,
252    replace: &'a Ident,
253    use_self: bool,
254    index: Index,
255    errors: Vec<Error>,
256}
257
258impl<'a> ReplaceTuplePlaceholder<'a> {
259    /// Replace the given `replace` ident in the given `stmt`.
260    fn replace_ident_in_stmt(
261        search: &'a Ident,
262        replace: &'a Ident,
263        use_self: bool,
264        index: usize,
265        stmt: Stmt,
266    ) -> Result<Stmt> {
267        let mut folder = Self {
268            search,
269            replace,
270            use_self,
271            index: index.into(),
272            errors: Vec::new(),
273        };
274
275        let res = fold::fold_stmt(&mut folder, stmt);
276
277        if let Some(first) = folder.errors.pop() {
278            Err(folder.errors.into_iter().fold(first, |mut e, n| {
279                e.combine(n);
280                e
281            }))
282        } else {
283            Ok(res)
284        }
285    }
286
287    /// Replace the given `replace` ident in the given `type_`.
288    fn replace_ident_in_type(search: &'a Ident, replace: &'a Ident, type_: Type) -> Result<Type> {
289        let mut folder = Self {
290            search,
291            replace,
292            use_self: false,
293            index: 0.into(),
294            errors: Vec::new(),
295        };
296
297        let res = fold::fold_type(&mut folder, type_);
298
299        if let Some(first) = folder.errors.pop() {
300            Err(folder.errors.into_iter().fold(first, |mut e, n| {
301                e.combine(n);
302                e
303            }))
304        } else {
305            Ok(res)
306        }
307    }
308
309    /// Replace the given `replace` ident in the given `where_predicate`.
310    fn replace_ident_in_where_predicate(
311        search: &'a Ident,
312        replace: &'a Ident,
313        where_predicate: WherePredicate,
314    ) -> Result<WherePredicate> {
315        let mut folder = Self {
316            search,
317            replace,
318            use_self: false,
319            index: 0.into(),
320            errors: Vec::new(),
321        };
322
323        let res = fold::fold_where_predicate(&mut folder, where_predicate);
324
325        if let Some(first) = folder.errors.pop() {
326            Err(folder.errors.into_iter().fold(first, |mut e, n| {
327                e.combine(n);
328                e
329            }))
330        } else {
331            Ok(res)
332        }
333    }
334}
335
336impl<'a> Fold for ReplaceTuplePlaceholder<'a> {
337    fn fold_ident(&mut self, ident: Ident) -> Ident {
338        if &ident == self.search {
339            self.replace.clone()
340        } else {
341            ident
342        }
343    }
344
345    fn fold_expr(&mut self, expr: Expr) -> Expr {
346        match expr {
347            Expr::MethodCall(mut call) => match *call.receiver {
348                Expr::Path(ref path) if path.path.is_ident(self.search) => {
349                    if self.use_self {
350                        let index = &self.index;
351                        call.receiver = parse_quote!( self.#index );
352
353                        call.into()
354                    } else {
355                        self.errors.push(Error::new(
356                            path.span(),
357                            "Can not call non-static method from within a static method.",
358                        ));
359                        Expr::Verbatim(Default::default())
360                    }
361                }
362                _ => fold::fold_expr_method_call(self, call).into(),
363            },
364            _ => fold::fold_expr(self, expr),
365        }
366    }
367
368    fn fold_expr_field(&mut self, mut expr: ExprField) -> ExprField {
369        match expr.member {
370            Member::Named(ref ident) if ident == self.search => {
371                // Replace `something.Tuple` with `something.0`, `something.1`, etc.
372                expr.member = Member::Unnamed(self.index.clone());
373                expr
374            }
375            _ => expr,
376        }
377    }
378}
379
380/// The expression of a const item.
381enum ConstExpr {
382    /// repetition
383    Simple { tuple_repetition: TupleRepetition },
384    /// &[ repetition ]
385    RefArray {
386        and_token: token::And,
387        bracket_token: token::Bracket,
388        tuple_repetition: TupleRepetition,
389    },
390}
391
392impl ConstExpr {
393    /// Expand `self` into a [`TokenStream`].
394    fn expand(
395        self,
396        tuple_placeholder_ident: &Ident,
397        tuples: &[Ident],
398        use_self: bool,
399    ) -> Result<TokenStream> {
400        match self {
401            Self::Simple { tuple_repetition } => {
402                tuple_repetition.expand_as_stmts(tuple_placeholder_ident, tuples, use_self)
403            }
404            Self::RefArray {
405                and_token,
406                bracket_token,
407                tuple_repetition,
408            } => {
409                let repetition =
410                    tuple_repetition.expand_as_stmts(tuple_placeholder_ident, tuples, use_self)?;
411
412                let mut token_stream = and_token.to_token_stream();
413                bracket_token.surround(&mut token_stream, |tokens| tokens.extend(repetition));
414                Ok(token_stream)
415            }
416        }
417    }
418}
419
420impl Parse for ConstExpr {
421    fn parse(input: ParseStream) -> Result<Self> {
422        let lookahead1 = input.lookahead1();
423
424        if lookahead1.peek(token::And) {
425            let content;
426            Ok(ConstExpr::RefArray {
427                and_token: input.parse()?,
428                bracket_token: bracketed!(content in input),
429                tuple_repetition: content.call(TupleRepetition::parse_as_stmts)?,
430            })
431        } else if lookahead1.peek(token::Pound) {
432            Ok(ConstExpr::Simple {
433                tuple_repetition: TupleRepetition::parse_as_stmts(input)?,
434            })
435        } else {
436            Err(lookahead1.error())
437        }
438    }
439}
440
441/// The `for_tuples!` macro syntax.
442enum ForTuplesMacro {
443    /// The macro at an item type position.
444    ItemType {
445        type_token: token::Type,
446        ident: Ident,
447        equal_token: token::Eq,
448        paren_token: token::Paren,
449        tuple_repetition: TupleRepetition,
450        semi_token: token::Semi,
451    },
452    /// The macro at an item const position.
453    ItemConst {
454        const_token: token::Const,
455        ident: Ident,
456        colon_token: token::Colon,
457        const_type: Type,
458        equal_token: token::Eq,
459        expr: ConstExpr,
460        semi_token: token::Semi,
461    },
462    /// The repetition stmt wrapped in parenthesis.
463    StmtParenthesized {
464        paren_token: token::Paren,
465        tuple_repetition: TupleRepetition,
466    },
467    /// Just the repetition stmt.
468    Stmt { tuple_repetition: TupleRepetition },
469    /// A custom where clause.
470    Where {
471        _where_token: token::Where,
472        tuple_repetition: TupleRepetition,
473    },
474}
475
476impl Parse for ForTuplesMacro {
477    fn parse(input: ParseStream) -> Result<Self> {
478        let lookahead1 = input.lookahead1();
479
480        if lookahead1.peek(token::Type) {
481            let content;
482            Ok(ForTuplesMacro::ItemType {
483                type_token: input.parse()?,
484                ident: input.parse()?,
485                equal_token: input.parse()?,
486                paren_token: parenthesized!(content in input),
487                tuple_repetition: content.call(TupleRepetition::parse_as_type)?,
488                semi_token: input.parse()?,
489            })
490        } else if lookahead1.peek(token::Const) {
491            Ok(ForTuplesMacro::ItemConst {
492                const_token: input.parse()?,
493                ident: input.parse()?,
494                colon_token: input.parse()?,
495                const_type: input.parse()?,
496                equal_token: input.parse()?,
497                expr: input.parse()?,
498                semi_token: input.parse()?,
499            })
500        } else if lookahead1.peek(token::Paren) {
501            let content;
502            Ok(ForTuplesMacro::StmtParenthesized {
503                paren_token: parenthesized!(content in input),
504                tuple_repetition: content.call(TupleRepetition::parse_as_stmts)?,
505            })
506        } else if lookahead1.peek(token::Pound) {
507            Ok(ForTuplesMacro::Stmt {
508                tuple_repetition: input.call(TupleRepetition::parse_as_stmts)?,
509            })
510        } else if lookahead1.peek(token::Where) {
511            Ok(ForTuplesMacro::Where {
512                _where_token: input.parse()?,
513                tuple_repetition: input.call(TupleRepetition::parse_as_where_predicate)?,
514            })
515        } else {
516            Err(lookahead1.error())
517        }
518    }
519}
520
521impl ForTuplesMacro {
522    /// Try to parse the given macro as `Self`.
523    ///
524    /// `allow_where` signals that a custom where clause is allowed at this position.
525    ///
526    /// Returns `Ok(None)` if it is not a `for_tuples!` macro.
527    fn try_from(macro_item: &Macro, allow_where: bool) -> Result<Option<Self>> {
528        // Not the macro we are searching for
529        if !macro_item.path.is_ident("for_tuples") {
530            return Ok(None);
531        }
532
533        let res = macro_item.parse_body::<Self>()?;
534
535        if !allow_where && res.is_where() {
536            Err(Error::new(
537                macro_item.span(),
538                "Custom where clause not allowed at this position!",
539            ))
540        } else {
541            Ok(Some(res))
542        }
543    }
544
545    /// Is this a custom where clause?
546    fn is_where(&self) -> bool {
547        matches!(self, Self::Where { .. })
548    }
549
550    /// Convert this into the where clause tuple repetition.
551    fn into_where(self) -> Option<TupleRepetition> {
552        match self {
553            Self::Where {
554                tuple_repetition, ..
555            } => Some(tuple_repetition),
556            _ => None,
557        }
558    }
559
560    /// Expand `self` to the actual implementation without the `for_tuples!` macro.
561    ///
562    /// This will unroll the repetition by replacing the placeholder identifier in each iteration
563    /// with the one given in `tuples`. If `use_self` is `true`, the tuple will be access by using
564    /// `self.x`.
565    ///
566    /// Returns the generated code.
567    fn expand(
568        self,
569        tuple_placeholder_ident: &Ident,
570        tuples: &[Ident],
571        use_self: bool,
572    ) -> TokenStream {
573        match self {
574            Self::ItemType {
575                type_token,
576                ident,
577                equal_token,
578                paren_token,
579                tuple_repetition,
580                semi_token,
581            } => {
582                let mut token_stream = type_token.to_token_stream();
583                let repetition =
584                    tuple_repetition.expand_as_type_declaration(tuple_placeholder_ident, tuples);
585
586                match repetition {
587                    Ok(rep) => {
588                        ident.to_tokens(&mut token_stream);
589                        equal_token.to_tokens(&mut token_stream);
590                        paren_token.surround(&mut token_stream, |tokens| tokens.extend(rep));
591                        semi_token.to_tokens(&mut token_stream);
592                    }
593                    Err(e) => token_stream.extend(e.to_compile_error()),
594                }
595
596                token_stream
597            }
598            Self::ItemConst {
599                const_token,
600                ident,
601                colon_token,
602                const_type,
603                equal_token,
604                expr,
605                semi_token,
606            } => {
607                let mut token_stream = const_token.to_token_stream();
608
609                let expr = expr.expand(tuple_placeholder_ident, tuples, use_self);
610
611                match expr {
612                    Ok(expr) => {
613                        ident.to_tokens(&mut token_stream);
614                        colon_token.to_tokens(&mut token_stream);
615                        const_type.to_tokens(&mut token_stream);
616                        equal_token.to_tokens(&mut token_stream);
617                        token_stream.extend(expr);
618                        semi_token.to_tokens(&mut token_stream);
619                    }
620                    Err(e) => token_stream.extend(e.to_compile_error()),
621                }
622
623                token_stream
624            }
625            Self::StmtParenthesized {
626                paren_token,
627                tuple_repetition,
628            } => {
629                let mut token_stream = TokenStream::new();
630                let repetition =
631                    tuple_repetition.expand_as_stmts(tuple_placeholder_ident, tuples, use_self);
632
633                match repetition {
634                    Ok(rep) => {
635                        paren_token.surround(&mut token_stream, |tokens| tokens.extend(rep))
636                    }
637                    Err(e) => token_stream.extend(e.to_compile_error()),
638                }
639
640                token_stream
641            }
642            Self::Stmt { tuple_repetition } => tuple_repetition
643                .expand_as_stmts(tuple_placeholder_ident, tuples, use_self)
644                .unwrap_or_else(|e| e.to_compile_error()),
645            Self::Where { .. } => TokenStream::new(),
646        }
647    }
648}
649
650/// Add the tuple elements as generic parameters to the given trait implementation.
651fn add_tuple_elements_generics(
652    tuples: &[Ident],
653    mut trait_impl: ItemImpl,
654    bound: Option<TokenStream>,
655) -> Result<ItemImpl> {
656    crate::utils::add_tuple_element_generics(tuples, bound, &mut trait_impl.generics);
657    Ok(trait_impl)
658}
659
660/// Fold a given trait implementation into a tuple implementation of the given trait.
661struct ToTupleImplementation<'a> {
662    /// The tuple idents to use while expanding the repetitions.
663    tuples: &'a [Ident],
664    /// The placeholder ident given by the user.
665    ///
666    /// This placeholder ident while be replaced in the expansion with the correct tuple identifiers.
667    tuple_placeholder_ident: &'a Ident,
668    /// Any errors found while doing the conversion.
669    errors: Vec<Error>,
670    /// This is set to `true`, when folding in a function block that has a `self` parameter.
671    has_self_parameter: bool,
672    /// A custom where clause provided by the user.
673    custom_where_clause: Option<TupleRepetition>,
674}
675
676// Struct to parse custom trait bounds
677#[derive(Debug)]
678struct BoundsStruct {
679    _paren_token: token::Paren,
680    bounds: syn::TypeTraitObject,
681}
682
683impl Parse for BoundsStruct {
684    fn parse(input: ParseStream) -> Result<Self> {
685        let content;
686        Ok(BoundsStruct {
687            _paren_token: parenthesized!(content in input),
688            bounds: content.parse()?,
689        })
690    }
691}
692
693impl<'a> ToTupleImplementation<'a> {
694    /// Generate the tuple implementation for the given `tuples`.
695    fn generate_implementation(
696        trait_impl: &ItemImpl,
697        tuple_placeholder_ident: &'a Ident,
698        tuples: &'a [Ident],
699        ref_tuples: bool,
700    ) -> Result<TokenStream> {
701        let mut to_tuple = ToTupleImplementation {
702            tuples,
703            errors: Vec::new(),
704            tuple_placeholder_ident,
705            has_self_parameter: false,
706            custom_where_clause: None,
707        };
708
709        let mut res = fold::fold_item_impl(&mut to_tuple, trait_impl.clone());
710
711        let default_trait = trait_impl.trait_.clone().map(|t| t.1).ok_or_else(|| {
712            Error::new(
713                trait_impl.span(),
714                "The semi-automatic implementation is required to implement a trait!",
715            )
716        })?;
717
718        // Check if we should customize the trait bound
719        let trait_ = if let Some(pos) = res
720            .attrs
721            .iter()
722            .position(|a| a.path.is_ident(TUPLE_TYPES_CUSTOM_TRAIT_BOUND))
723        {
724            // Parse custom trait bound
725            let attr = &res.attrs[pos];
726            let input = attr.tokens.to_token_stream();
727            let result = syn::parse2::<BoundsStruct>(input);
728            let trait_name = match result {
729                Ok(b) => b.bounds,
730                Err(e) => {
731                    return Err(Error::new(
732                        e.span(),
733                        format!("Invalid trait bound: {}", e.to_string()),
734                    ))
735                }
736            };
737
738            res.attrs.remove(pos);
739            quote! { #trait_name }
740        } else {
741            quote! { #default_trait }
742        };
743
744        // Check if we should add the bound to the implemented trait for each tuple type.
745        let add_bound = if let Some(pos) = res
746            .attrs
747            .iter()
748            .position(|a| a.path.is_ident(TUPLE_TYPES_NO_DEFAULT_TRAIT_BOUND))
749        {
750            res.attrs.remove(pos);
751            None
752        } else {
753            Some(trait_)
754        };
755
756        // Add the tuple generics
757        let mut res = add_tuple_elements_generics(tuples, res, add_bound)?;
758        // Add the correct self type
759        if ref_tuples {
760            res.self_ty = parse_quote!( ( #( &#tuples, )* ) );
761        } else {
762            res.self_ty = parse_quote!( ( #( #tuples, )* ) );
763        };
764        res.attrs.push(parse_quote!(#[allow(unused)]));
765
766        if let Some(where_clause) = to_tuple.custom_where_clause.take() {
767            where_clause.expand_to_where_clause(
768                tuple_placeholder_ident,
769                tuples,
770                res.generics.make_where_clause(),
771            )?;
772        }
773
774        if let Some(first_error) = to_tuple.errors.pop() {
775            Err(to_tuple.errors.into_iter().fold(first_error, |mut e, n| {
776                e.combine(n);
777                e
778            }))
779        } else {
780            Ok(res.to_token_stream())
781        }
782    }
783
784    /// Fold the expr and returns the folded expr and if it was a `for_tuples!`.
785    fn custom_fold_expr(&mut self, expr: Expr) -> (Expr, bool) {
786        match expr {
787            Expr::Macro(expr_macro) => match ForTuplesMacro::try_from(&expr_macro.mac, false) {
788                Ok(Some(for_tuples)) => (
789                    Expr::Verbatim(for_tuples.expand(
790                        &self.tuple_placeholder_ident,
791                        self.tuples,
792                        self.has_self_parameter,
793                    )),
794                    true,
795                ),
796                Ok(None) => (fold::fold_expr_macro(self, expr_macro).into(), false),
797                Err(e) => {
798                    self.errors.push(e);
799                    (Expr::Verbatim(Default::default()), false)
800                }
801            },
802            _ => (fold::fold_expr(self, expr), false),
803        }
804    }
805}
806
807impl<'a> Fold for ToTupleImplementation<'a> {
808    fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem {
809        match i {
810            ImplItem::Macro(macro_item) => match ForTuplesMacro::try_from(&macro_item.mac, true) {
811                Ok(Some(for_tuples)) => {
812                    if for_tuples.is_where() {
813                        if self.custom_where_clause.is_some() {
814                            self.errors.push(Error::new(
815                                macro_item.span(),
816                                "Only one custom where clause is supported!",
817                            ));
818                        } else {
819                            self.custom_where_clause = for_tuples.into_where();
820                        }
821
822                        ImplItem::Verbatim(Default::default())
823                    } else {
824                        ImplItem::Verbatim(for_tuples.expand(
825                            &self.tuple_placeholder_ident,
826                            self.tuples,
827                            false,
828                        ))
829                    }
830                }
831                Ok(None) => fold::fold_impl_item_macro(self, macro_item).into(),
832                Err(e) => {
833                    self.errors.push(e);
834                    ImplItem::Verbatim(Default::default())
835                }
836            },
837            _ => fold::fold_impl_item(self, i),
838        }
839    }
840
841    fn fold_expr(&mut self, expr: Expr) -> Expr {
842        self.custom_fold_expr(expr).0
843    }
844
845    fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
846        let (expr, trailing_semi) = match stmt {
847            Stmt::Expr(expr) => (expr, None),
848            Stmt::Semi(expr, semi) => (expr, Some(semi)),
849            _ => return fold::fold_stmt(self, stmt),
850        };
851
852        let (expr, expanded) = self.custom_fold_expr(expr);
853
854        if expanded {
855            Stmt::Expr(expr)
856        } else if let Some(semi) = trailing_semi {
857            Stmt::Semi(expr, semi)
858        } else {
859            Stmt::Expr(expr)
860        }
861    }
862
863    fn fold_type(&mut self, ty: Type) -> Type {
864        match ty {
865            Type::Macro(ty_macro) => match ForTuplesMacro::try_from(&ty_macro.mac, false) {
866                Ok(Some(for_tuples)) => Type::Verbatim(for_tuples.expand(
867                    &self.tuple_placeholder_ident,
868                    self.tuples,
869                    false,
870                )),
871                Ok(None) => fold::fold_type_macro(self, ty_macro).into(),
872                Err(e) => {
873                    self.errors.push(e);
874                    Type::Verbatim(Default::default())
875                }
876            },
877            _ => fold::fold_type(self, ty),
878        }
879    }
880
881    fn fold_impl_item_method(&mut self, mut impl_item_method: ImplItemMethod) -> ImplItemMethod {
882        let has_self = impl_item_method
883            .sig
884            .inputs
885            .first()
886            .map(|a| match a {
887                FnArg::Receiver(_) => true,
888                _ => false,
889            })
890            .unwrap_or(false);
891
892        impl_item_method.sig = fold::fold_signature(self, impl_item_method.sig);
893
894        // Store the old value and set the current one
895        let old_has_self_parameter = self.has_self_parameter;
896        self.has_self_parameter = has_self;
897
898        impl_item_method.block = fold::fold_block(self, impl_item_method.block);
899        self.has_self_parameter = old_has_self_parameter;
900
901        impl_item_method
902    }
903}
904
905/// Extracts the tuple placeholder ident from the given trait implementation.
906fn extract_tuple_placeholder_ident(trait_impl: &ItemImpl) -> Result<(bool, Ident)> {
907    match *trait_impl.self_ty {
908        Type::Reference(ref type_ref) => {
909            if let Type::Path(ref type_path) = *type_ref.elem {
910                if let Some(ident) = type_path.path.get_ident() {
911                    return Ok((true, ident.clone()));
912                }
913            }
914        }
915        Type::Path(ref type_path) => {
916            if let Some(ident) = type_path.path.get_ident() {
917                return Ok((false, ident.clone()));
918            }
919        }
920        _ => {}
921    }
922
923    Err(Error::new(
924        trait_impl.self_ty.span(),
925        "Expected an `Ident` as tuple placeholder.",
926    ))
927}
928
929/// Generate the semi-automatic tuple implementations for a given trait implementation and the given tuples.
930pub fn semi_automatic_impl(
931    trait_impl: ItemImpl,
932    tuple_elements: Vec<Ident>,
933    min: Option<usize>,
934) -> Result<TokenStream> {
935    let placeholder_ident = extract_tuple_placeholder_ident(&trait_impl)?;
936
937    let mut res = TokenStream::new();
938
939    (min.unwrap_or(0)..=tuple_elements.len()).try_for_each(|i| {
940        res.extend(ToTupleImplementation::generate_implementation(
941            &trait_impl,
942            &placeholder_ident.1,
943            &tuple_elements[..i],
944            placeholder_ident.0,
945        )?);
946        Ok::<_, Error>(())
947    })?;
948
949    Ok(res)
950}