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