1use 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
22const 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
27enum 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 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 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
96enum Repetition {
98 Stmts(Vec<Stmt>),
99 Type(Type),
100 Where(WherePredicate),
101}
102
103struct 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 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 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 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 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 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 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
253struct 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 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 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 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 expr.member = Member::Unnamed(self.index.clone());
377 expr
378 }
379 _ => expr,
380 }
381 }
382}
383
384enum ConstExpr {
386 Simple { tuple_repetition: TupleRepetition },
388 RefArray {
390 and_token: token::And,
391 bracket_token: token::Bracket,
392 tuple_repetition: TupleRepetition,
393 },
394}
395
396impl ConstExpr {
397 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
445enum ForTuplesMacro {
447 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 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 StmtParenthesized {
468 paren_token: token::Paren,
469 tuple_repetition: TupleRepetition,
470 },
471 Stmt { tuple_repetition: TupleRepetition },
473 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 fn try_from(macro_item: &Macro, allow_where: bool) -> Result<Option<Self>> {
532 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 fn is_where(&self) -> bool {
551 matches!(self, Self::Where { .. })
552 }
553
554 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 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
652fn 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
662struct ToTupleImplementation<'a> {
664 tuples: &'a [Ident],
666 tuple_placeholder_ident: &'a Ident,
670 errors: Vec<Error>,
672 has_self_parameter: bool,
674 custom_where_clause: Option<TupleRepetition>,
676}
677
678impl<'a> ToTupleImplementation<'a> {
679 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 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 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 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 let mut res = add_tuple_elements_generics(tuples, res, add_bound)?;
750 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 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(¯o_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 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
904fn 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
928pub 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}