impl-trait-for-tuples-0.2.2/.cargo_vcs_info.json0000644000000001360000000000100152150ustar { "git": { "sha1": "90fd91127b49f2a78423316e68a02bdfad31bd6f" }, "path_in_vcs": "" }impl-trait-for-tuples-0.2.2/.gitignore000064400000000000000000000000360072674642500160240ustar 00000000000000/target **/*.rs.bk Cargo.lock impl-trait-for-tuples-0.2.2/Cargo.toml0000644000000022670000000000100132220ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "impl-trait-for-tuples" version = "0.2.2" authors = ["Bastian Köcher "] description = "Attribute macro to implement a trait for tuples\n" documentation = "https://docs.rs/impl-trait-for-tuples" readme = "./README.md" keywords = ["trait", "tuple", "crate", "macro", "proc-macro"] categories = ["development-tools::procedural-macro-helpers"] license = "Apache-2.0/MIT" repository = "https://github.com/bkchr/impl-trait-for-tuples" resolver = "2" [lib] proc-macro = true [dependencies.proc-macro2] version = "1.0.3" [dependencies.quote] version = "1.0.2" [dependencies.syn] version = "1.0.5" features = ["full", "visit", "fold", "extra-traits"] [dev-dependencies.trybuild] version = "1.0.55" impl-trait-for-tuples-0.2.2/Cargo.toml.orig000064400000000000000000000012600072674642500167230ustar 00000000000000[package] name = "impl-trait-for-tuples" version = "0.2.2" authors = ["Bastian Köcher "] edition = "2021" categories = [ "development-tools::procedural-macro-helpers" ] documentation = "https://docs.rs/impl-trait-for-tuples" repository = "https://github.com/bkchr/impl-trait-for-tuples" keywords = [ "trait", "tuple", "crate", "macro", "proc-macro" ] license = "Apache-2.0/MIT" description = """ Attribute macro to implement a trait for tuples """ readme = "./README.md" [lib] proc-macro = true [dependencies] syn = { version = "1.0.5", features = [ "full", "visit", "fold", "extra-traits" ] } quote = "1.0.2" proc-macro2 = "1.0.3" [dev-dependencies] trybuild = "1.0.55" impl-trait-for-tuples-0.2.2/README.md000064400000000000000000000110110072674642500153060ustar 00000000000000# impl-trait-for-tuples [![](https://docs.rs/impl-trait-for-tuples/badge.svg)](https://docs.rs/impl-trait-for-tuples/) [![](https://img.shields.io/crates/v/impl-trait-for-tuples.svg)](https://crates.io/crates/impl-trait-for-tuples) [![](https://img.shields.io/crates/d/impl-trait-for-tuples.png)](https://crates.io/crates/impl-trait-for-tuples) Attribute macro to implement a trait for tuples * [Introduction](#introduction) * [Syntax](#syntax) * [Limitations](#limitations) * [Example](#example) * [License](#license) ## Introduction When wanting to implement a trait for combinations of tuples, Rust requires the trait to be implemented for each combination manually. With this crate you just need to place `#[impl_for_tuples(5)]` above your trait declaration (in full-automatic mode) to implement the trait for the tuple combinations `(), (T0), (T0, T1), (T0, T1, T2), (T0, T1, T2, T3), (T0, T1, T2, T3, T4, T5)`. The number of tuples is the parameter given to the attribute and can be chosen freely. This crate provides two modes full-automatic and semi-automatic. The full-automatic mode just requires the trait definition to implement the trait for the tuple combinations. While being much easier to use, it also comes with some restrictions like no associated types, no return values or no associated consts. To support these, the semi-automatic mode is provided. This mode requires a dummy implementation block of the trait that is expanded to all the tuple combinations implementations. To express the tuple access in this dummy implementation a special syntax is required `for_tuples!( #( Tuple::function(); )* )`. This would expand to `Tuple::function();` for each tuple while `Tuple` is chosen by the user and will be replaced by the corresponding tuple identifier per iteration. ## Syntax The attribute macro can be called with one `#[impl_for_tuples(5)]` or with two `#[impl_for_tuples(2, 5)]` parameters. The former instructs the macro to generate up to a tuple of five elements and the later instructs it to generate from a tuple with two element up to five elements. ### Semi-automatic syntax ```rust trait Trait { type Ret; type Arg; type FixedType; const VALUE: u32; fn test(arg: Self::Arg) -> Self::Ret; fn test_with_self(&self) -> Result<(), ()>; } #[impl_for_tuples(1, 5)] impl Trait for Tuple { // Here we expand the `Ret` and `Arg` associated types. for_tuples!( type Ret = ( #( Tuple::Ret ),* ); ); for_tuples!( type Arg = ( #( Tuple::Arg ),* ); ); for_tuples!( const VALUE: u32 = #( Tuple::VALUE )+*; ); // Here we set the `FixedType` to `u32` and add a custom where bound that forces the same // `FixedType` for all tuple types. type FixedType = u32; for_tuples!( where #( Tuple: Trait )* ); fn test(arg: Self::Arg) -> Self::Ret { for_tuples!( ( #( Tuple::test(arg.Tuple) ),* ) ) } fn test_with_self(&self) -> Result<(), ()> { for_tuples!( #( Tuple.test_with_self()?; )* ); Ok(()) } } ``` The given example shows all supported combinations of `for_tuples!`. When accessing a method from the `self` tuple instance, `self.Tuple` is the required syntax and is replaced by `self.0`, `self.1`, etc. The placeholder tuple identifer is taken from the self type given to the implementation block. So, it is up to the user to chose any valid identifier. The separator given to `#( Tuple::something() )SEPARATOR*` can be chosen from `,`, `+`, `-`, `*`, `/`, `|`, `&` or nothing for no separator. By adding the `#[tuple_types_no_default_trait_bound]` above the impl block, the macro will not add the automatic bound to the implemented trait for each tuple type. The trait bound can be customized using `#[tuple_types_custom_trait_bound(NewBound)]`. The new bound will be used instead of the impleted trait for each tuple type. ## Limitations The macro does not supports `for_tuples!` calls in a different macro, so stuff like `vec![ for_tuples!( bla ) ]` will generate invalid code. ## Example ### Full-automatic ```rust #[impl_for_tuples(5)] trait Notify { fn notify(&self); } ``` ### Semi-automatic ```rust trait Notify { fn notify(&self) -> Result<(), ()>; } #[impl_for_tuples(5)] impl Notify for TupleIdentifier { fn notify(&self) -> Result<(), ()> { for_tuples!( #( TupleIdentifier.notify()?; )* ); Ok(()) } } ``` ## License Licensed under either of * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) * [MIT license](http://opensource.org/licenses/MIT) at your option. License: Apache-2.0/MIT impl-trait-for-tuples-0.2.2/src/full_automatic.rs000064400000000000000000000157360072674642500202160ustar 00000000000000//! Implementation of the full-automatic tuple trait implementation. //! //! The full-automatic implementation uses the trait definition to generate the implementations for //! tuples. This has some limitations, as no support for associated types, consts, return values or //! functions with a default implementation. use crate::utils::add_tuple_element_generics; use proc_macro2::{Span, TokenStream}; use std::iter::repeat; use syn::{ parse_quote, spanned::Spanned, visit::{self, Visit}, Error, FnArg, Generics, Ident, Index, ItemTrait, Pat, Result, ReturnType, Signature, TraitItem, TraitItemMethod, Type, }; use quote::quote; /// Generate the full-automatic tuple implementations for a given trait definition and the given tuples. pub fn full_automatic_impl( definition: ItemTrait, tuple_elements: Vec, min: Option, ) -> Result { check_trait_declaration(&definition)?; let impls = (min.unwrap_or(0)..=tuple_elements.len()) .map(|i| generate_tuple_impl(&definition, &tuple_elements[0..i])); Ok(quote!( #definition #( #impls )* )) } fn check_trait_declaration(trait_decl: &ItemTrait) -> Result<()> { let mut visitor = CheckTraitDeclaration { errors: Vec::new() }; visit::visit_item_trait(&mut visitor, trait_decl); match visitor.errors.pop() { Some(init) => Err(visitor.errors.into_iter().fold(init, |mut old, new| { old.combine(new); old })), None => Ok(()), } } /// Checks that the given trait declaration corresponds to the expected format. struct CheckTraitDeclaration { /// Stores all errors that are found. errors: Vec, } impl CheckTraitDeclaration { fn add_error(&mut self, span: &T) { self.errors.push(Error::new(span.span(), CHECK_ERROR_MSG)); } } const CHECK_ERROR_MSG: &str = "Not supported by full-automatic tuple implementation. \ Use semi-automatic tuple implementation for more control of the implementation."; impl<'ast> Visit<'ast> for CheckTraitDeclaration { fn visit_trait_item(&mut self, ti: &'ast TraitItem) { match ti { TraitItem::Method(m) => visit::visit_trait_item_method(self, m), _ => self.add_error(ti), } } fn visit_return_type(&mut self, rt: &'ast ReturnType) { match rt { ReturnType::Default => {} ReturnType::Type(_, ty) => match **ty { Type::Tuple(ref tuple) if tuple.elems.is_empty() => {} _ => self.add_error(rt), }, } } } fn generate_tuple_impl(definition: &ItemTrait, tuple_elements: &[Ident]) -> TokenStream { let name = &definition.ident; let unsafety = &definition.unsafety; let generics = generate_generics(definition, tuple_elements); let ty_generics = definition.generics.split_for_impl().1; let (impl_generics, _, where_clause) = generics.split_for_impl(); let fns = definition.items.iter().filter_map(|i| match i { TraitItem::Method(method) => Some(generate_delegate_method(method, tuple_elements)), _ => None, }); quote!( #[allow(unused)] #unsafety impl #impl_generics #name #ty_generics for ( #( #tuple_elements, )* ) #where_clause { #( #fns )* } ) } /// Collects all non-reference argument types. struct CollectNonReferenceArgTypes { result: Vec, } impl<'ast> Visit<'ast> for CollectNonReferenceArgTypes { fn visit_type(&mut self, ty: &'ast Type) { if !is_reference_type(ty) { self.result.push(ty.clone()); } } } fn generate_generics(definition: &ItemTrait, tuple_elements: &[Ident]) -> Generics { let mut generics = definition.generics.clone(); let name = &definition.ident; let ty_generics = definition.generics.split_for_impl().1; // Make sure that all non-reference types implement `Clone`. let mut visitor = CollectNonReferenceArgTypes { result: Vec::new() }; definition .items .iter() .for_each(|item| visit::visit_trait_item(&mut visitor, item)); visitor.result.dedup(); { let where_clause = generics.make_where_clause(); visitor .result .into_iter() .for_each(|ty| where_clause.predicates.push(parse_quote!(#ty: Clone))); } add_tuple_element_generics( tuple_elements, Some(quote!(#name #ty_generics)), &mut generics, ); generics } fn generate_delegate_method(method: &TraitItemMethod, tuple_elements: &[Ident]) -> TokenStream { let name = repeat(&method.sig.ident); let self_arg = method .sig .inputs .first() .map(|a| match a { FnArg::Receiver(_) => true, _ => false, }) .unwrap_or(false); let (sig, arg_names, arg_clones) = update_signature_and_extract_arg_infos(method.sig.clone()); let arg_names_per_tuple = repeat(&arg_names); let arg_clones_per_tuple = repeat(&arg_clones); let tuple_access = tuple_elements.iter().enumerate().map(|(i, te)| { if self_arg { let index = Index::from(i); quote!(self.#index.) } else { quote!(#te::) } }); let mut res = method.clone(); res.sig = sig; res.semi_token = None; res.default = Some(parse_quote!( { #( #tuple_access #name ( #( #arg_names_per_tuple #arg_clones_per_tuple ),* ); )* } )); quote!( #res ) } /// Update `Signature` by replacing all wild card argument names with unique identifiers, collect all /// argument names and if we need to clone an argument. fn update_signature_and_extract_arg_infos( mut sig: Signature, ) -> (Signature, Vec, Vec) { let mut unique_id = 0; let mut arg_clone = Vec::new(); let mut push_arg_clone = |is_ref: bool| { if is_ref { arg_clone.push(quote!()) } else { arg_clone.push(quote!(.clone())) } }; let arg_names = sig .inputs .iter_mut() .filter_map(|a| match a { FnArg::Typed(ref mut arg) => match &mut *arg.pat { Pat::Ident(p) => { push_arg_clone(is_reference_type(&arg.ty)); Some(p.ident.clone()) } Pat::Wild(_) => { push_arg_clone(is_reference_type(&arg.ty)); let ident = Ident::new( &format!("tuple_element_unique_ident_{}", unique_id), Span::call_site(), ); unique_id += 1; let ident2 = ident.clone(); arg.pat = parse_quote!(#ident); Some(ident2) } _ => None, }, _ => None, }) .collect::>(); (sig, arg_names, arg_clone) } fn is_reference_type(ty: &Type) -> bool { match ty { Type::Reference(_) => true, _ => false, } } impl-trait-for-tuples-0.2.2/src/lib.rs000064400000000000000000000204140072674642500157410ustar 00000000000000/*! [![](https://docs.rs/impl-trait-for-tuples/badge.svg)](https://docs.rs/impl-trait-for-tuples/) [![](https://img.shields.io/crates/v/impl-trait-for-tuples.svg)](https://crates.io/crates/impl-trait-for-tuples) [![](https://img.shields.io/crates/d/impl-trait-for-tuples.png)](https://crates.io/crates/impl-trait-for-tuples) Attribute macro to implement a trait for tuples * [Introduction](#introduction) * [Syntax](#syntax) * [Limitations](#limitations) * [Example](#example) * [License](#license) ## Introduction When wanting to implement a trait for combinations of tuples, Rust requires the trait to be implemented for each combination manually. With this crate you just need to place `#[impl_for_tuples(5)]` above your trait declaration (in full-automatic mode) to implement the trait for the tuple combinations `(), (T0), (T0, T1), (T0, T1, T2), (T0, T1, T2, T3), (T0, T1, T2, T3, T4, T5)`. The number of tuples is the parameter given to the attribute and can be chosen freely. This crate provides two modes full-automatic and semi-automatic. The full-automatic mode just requires the trait definition to implement the trait for the tuple combinations. While being much easier to use, it also comes with some restrictions like no associated types, no return values or no associated consts. To support these, the semi-automatic mode is provided. This mode requires a dummy implementation block of the trait that is expanded to all the tuple combinations implementations. To express the tuple access in this dummy implementation a special syntax is required `for_tuples!( #( Tuple::function(); )* )`. This would expand to `Tuple::function();` for each tuple while `Tuple` is chosen by the user and will be replaced by the corresponding tuple identifier per iteration. ## Syntax The attribute macro can be called with one `#[impl_for_tuples(5)]` or with two `#[impl_for_tuples(2, 5)]` parameters. The former instructs the macro to generate up to a tuple of five elements and the later instructs it to generate from a tuple with two element up to five elements. ### Semi-automatic syntax ``` # use impl_trait_for_tuples::impl_for_tuples; trait Trait { type Ret; type Arg; type FixedType; const VALUE: u32; fn test(arg: Self::Arg) -> Self::Ret; fn test_with_self(&self) -> Result<(), ()>; } #[impl_for_tuples(1, 5)] impl Trait for Tuple { // Here we expand the `Ret` and `Arg` associated types. for_tuples!( type Ret = ( #( Tuple::Ret ),* ); ); for_tuples!( type Arg = ( #( Tuple::Arg ),* ); ); for_tuples!( const VALUE: u32 = #( Tuple::VALUE )+*; ); // Here we set the `FixedType` to `u32` and add a custom where bound that forces the same // `FixedType` for all tuple types. type FixedType = u32; for_tuples!( where #( Tuple: Trait )* ); fn test(arg: Self::Arg) -> Self::Ret { for_tuples!( ( #( Tuple::test(arg.Tuple) ),* ) ) } fn test_with_self(&self) -> Result<(), ()> { for_tuples!( #( Tuple.test_with_self()?; )* ); Ok(()) } } # fn main() {} ``` The given example shows all supported combinations of `for_tuples!`. When accessing a method from the `self` tuple instance, `self.Tuple` is the required syntax and is replaced by `self.0`, `self.1`, etc. The placeholder tuple identifer is taken from the self type given to the implementation block. So, it is up to the user to chose any valid identifier. The separator given to `#( Tuple::something() )SEPARATOR*` can be chosen from `,`, `+`, `-`, `*`, `/`, `|`, `&` or nothing for no separator. By adding the `#[tuple_types_no_default_trait_bound]` above the impl block, the macro will not add the automatic bound to the implemented trait for each tuple type. The trait bound can be customized using `#[tuple_types_custom_trait_bound(NewBound)]`. The new bound will be used instead of the impleted trait for each tuple type. ## Limitations The macro does not supports `for_tuples!` calls in a different macro, so stuff like `vec![ for_tuples!( bla ) ]` will generate invalid code. ## Example ### Full-automatic ``` # use impl_trait_for_tuples::impl_for_tuples; #[impl_for_tuples(5)] trait Notify { fn notify(&self); } # fn main() {} ``` ### Semi-automatic ``` # use impl_trait_for_tuples::impl_for_tuples; trait Notify { fn notify(&self) -> Result<(), ()>; } #[impl_for_tuples(5)] impl Notify for TupleIdentifier { fn notify(&self) -> Result<(), ()> { for_tuples!( #( TupleIdentifier.notify()?; )* ); Ok(()) } } # fn main() {} ``` ## License Licensed under either of * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) * [MIT license](http://opensource.org/licenses/MIT) at your option. */ extern crate proc_macro; use proc_macro2::{Span, TokenStream}; use syn::{ parse::{Parse, ParseStream}, parse_macro_input, punctuated::Punctuated, token, Attribute, Error, Ident, ItemImpl, ItemTrait, LitInt, Result, }; mod full_automatic; mod semi_automatic; mod utils; /// Enum to parse the input and to distinguish between full/semi-automatic mode. enum FullOrSemiAutomatic { /// Full-automatic trait implementation for tuples uses the trait definition. Full(ItemTrait), /// Sem-automatic trait implementation for tuples uses a trait implementation. Semi(ItemImpl), } impl Parse for FullOrSemiAutomatic { fn parse(input: ParseStream) -> Result { // We need to parse any attributes first, before we know what we actually can parse. let fork = input.fork(); fork.call(Attribute::parse_outer)?; // If there is a `unsafe` in front of, just skip it. if fork.peek(token::Unsafe) { fork.parse::()?; } let lookahead1 = fork.lookahead1(); if lookahead1.peek(token::Impl) { Ok(Self::Semi(input.parse()?)) } else if lookahead1.peek(token::Trait) || lookahead1.peek(token::Pub) { Ok(Self::Full(input.parse()?)) } else { Err(lookahead1.error()) } } } /// The minimum and maximum given as two `LitInt`'s to the macro as arguments. struct MinMax { min: Option, max: usize, } impl Parse for MinMax { fn parse(input: ParseStream) -> Result { let args = Punctuated::::parse_terminated(input)?; if args.is_empty() { Err(Error::new( Span::call_site(), "Expected at least one argument to the macro!", )) } else if args.len() == 1 { Ok(Self { max: args[0].base10_parse()?, min: None, }) } else if args.len() == 2 { let min = args[0].base10_parse()?; let max = args[1].base10_parse()?; if min >= max { Err(Error::new( Span::call_site(), "It is expected that `min` comes before `max` and that `max > min` is true!", )) } else { Ok(Self { min: Some(min), max, }) } } else { Err(Error::new( Span::call_site(), "Too many arguments given to the macro!", )) } } } /// See [crate](index.html) documentation. #[proc_macro_attribute] pub fn impl_for_tuples( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let input = parse_macro_input!(input as FullOrSemiAutomatic); let min_max = parse_macro_input!(args as MinMax); impl_for_tuples_impl(input, min_max) .unwrap_or_else(|e| e.to_compile_error()) .into() } fn impl_for_tuples_impl(input: FullOrSemiAutomatic, min_max: MinMax) -> Result { let tuple_elements = (0usize..min_max.max) .map(|i| generate_tuple_element_ident(i)) .collect::>(); match input { FullOrSemiAutomatic::Full(definition) => { full_automatic::full_automatic_impl(definition, tuple_elements, min_max.min) } FullOrSemiAutomatic::Semi(trait_impl) => { semi_automatic::semi_automatic_impl(trait_impl, tuple_elements, min_max.min) } } } fn generate_tuple_element_ident(num: usize) -> Ident { Ident::new(&format!("TupleElement{}", num), Span::call_site()) } impl-trait-for-tuples-0.2.2/src/semi_automatic.rs000064400000000000000000000753110072674642500202040ustar 00000000000000//! Implementation of the semi-automatic tuple trait implementation. //! //! The semi-automatic implementation uses an implementation provided by the user to generate the //! tuple implementations. The user is able to use a special syntax `for_tuples!( #(TUPLE)* );` to //! express the tuple access while the `TUPLE` ident can be chosen by the user. use proc_macro2::TokenStream; use syn::{ bracketed, fold::{self, Fold}, parenthesized, parse::{Parse, ParseStream}, parse_quote, spanned::Spanned, token, Block, Error, Expr, ExprField, FnArg, Ident, ImplItem, ImplItemMethod, Index, ItemImpl, Macro, Member, Result, Stmt, Type, WhereClause, WherePredicate, }; use quote::{quote, ToTokens}; /// By default we add the trait bound for the implemented trait to each tuple type. When this /// attribute is given we don't add this bound. const TUPLE_TYPES_NO_DEFAULT_TRAIT_BOUND: &str = "tuple_types_no_default_trait_bound"; const TUPLE_TYPES_CUSTOM_TRAIT_BOUND: &str = "tuple_types_custom_trait_bound"; /// The supported separators in the `#( Tuple::test() )SEPARATOR*` syntax. enum Separator { Comma(token::Comma), Add(token::Add), Sub(token::Sub), Or(token::Or), And(token::And), Star(token::Star), Div(token::Div), } impl Separator { /// Try to parse the separator before the `*` token. fn parse_before_star(input: ParseStream) -> Result> { if input.peek2(token::Star) { Self::parse(input).map(Some) } else { Ok(None) } } /// Convert into a `TokenStream`. /// /// `last` - Is this the last separator to add? Only `,` will be added on `last == true`. fn to_token_stream(&self, last: bool) -> TokenStream { let empty_on_last = |token: &dyn ToTokens| { if last { TokenStream::default() } else { token.to_token_stream() } }; match self { Self::Comma(comma) => comma.to_token_stream(), Self::Add(add) => empty_on_last(add), Self::Sub(sub) => empty_on_last(sub), Self::Or(or) => empty_on_last(or), Self::And(and) => empty_on_last(and), Self::Star(star) => empty_on_last(star), Self::Div(div) => empty_on_last(div), } } } impl Parse for Separator { fn parse(input: ParseStream) -> Result { let lookahead1 = input.lookahead1(); if lookahead1.peek(token::Comma) { Ok(Self::Comma(input.parse()?)) } else if lookahead1.peek(token::Add) { Ok(Self::Add(input.parse()?)) } else if lookahead1.peek(token::Sub) { Ok(Self::Sub(input.parse()?)) } else if lookahead1.peek(token::Or) { Ok(Self::Or(input.parse()?)) } else if lookahead1.peek(token::And) { Ok(Self::And(input.parse()?)) } else if lookahead1.peek(token::Star) { Ok(Self::Star(input.parse()?)) } else if lookahead1.peek(token::Div) { Ok(Self::Div(input.parse()?)) } else { Err(lookahead1.error()) } } } /// The different kind of repetitions that can be found in a [`TupleRepetition`]. enum Repetition { Stmts(Vec), Type(Type), Where(WherePredicate), } /// The `#( Tuple::test() )SEPARATOR*` (tuple repetition) syntax. struct TupleRepetition { pub pound_token: token::Pound, pub _paren_token: token::Paren, pub repetition: Repetition, pub separator: Option, pub _star_token: token::Star, } impl TupleRepetition { /// Parse the inner representation as stmts. fn parse_as_stmts(input: ParseStream) -> Result { let content; Ok(Self { pound_token: input.parse()?, _paren_token: parenthesized!(content in input), repetition: Repetition::Stmts(content.call(Block::parse_within)?), separator: Separator::parse_before_star(input)?, _star_token: input.parse()?, }) } /// Parse the inner representation as a where predicate. fn parse_as_where_predicate(input: ParseStream) -> Result { let content; Ok(Self { pound_token: input.parse()?, _paren_token: parenthesized!(content in input), repetition: Repetition::Where(content.parse()?), separator: Separator::parse_before_star(input)?, _star_token: input.parse()?, }) } /// Parse the inner representation as a type. fn parse_as_type(input: ParseStream) -> Result { let content; Ok(Self { pound_token: input.parse()?, _paren_token: parenthesized!(content in input), repetition: Repetition::Type(content.parse()?), separator: Separator::parse_before_star(input)?, _star_token: input.parse()?, }) } /// Expand this repetition to the actual stmts implementation. fn expand_as_stmts( self, tuple_placeholder_ident: &Ident, tuples: &[Ident], use_self: bool, ) -> Result { let mut generated = TokenStream::new(); let span = self.pound_token.span(); let stmts = match self.repetition { Repetition::Stmts(stmts) => stmts, _ => return Err(Error::new( span, "Internal error, expected `repetition` to be of type `Stmts`! Please report this issue!", )), }; for (i, tuple) in tuples.iter().enumerate() { generated.extend(stmts.iter().cloned().map(|s| { ReplaceTuplePlaceholder::replace_ident_in_stmt( tuple_placeholder_ident, tuple, use_self, i, s, ) .map(|s| s.to_token_stream()) .unwrap_or_else(|e| e.to_compile_error()) })); if let Some(ref sep) = self.separator { generated.extend(sep.to_token_stream(i + 1 == tuples.len())); } } Ok(generated) } /// Expand this repetition to the actual type declaration. fn expand_as_type_declaration( self, tuple_placeholder_ident: &Ident, tuples: &[Ident], ) -> Result { let mut generated = TokenStream::new(); let span = self.pound_token.span(); let ty = match self.repetition { Repetition::Type(ty) => ty, _ => return Err(Error::new( span, "Internal error, expected `repetition` to be of type `Type`! Please report this issue!", )), }; for (i, tuple) in tuples.iter().enumerate() { generated.extend( ReplaceTuplePlaceholder::replace_ident_in_type(tuple_placeholder_ident, tuple, ty.clone()) .map(|s| s.to_token_stream()) .unwrap_or_else(|e| e.to_compile_error()), ); if let Some(ref sep) = self.separator { generated.extend(sep.to_token_stream(i + 1 == tuples.len())); } } Ok(generated) } /// Expand this to the given `where_clause`. /// It is expected that the instance was created with `parse_as_where_predicate`. fn expand_to_where_clause( self, tuple_placeholder_ident: &Ident, tuples: &[Ident], where_clause: &mut WhereClause, ) -> Result<()> { let span = self.pound_token.span(); let predicate = match self.repetition { Repetition::Where(pred) => pred, _ => return Err(Error::new( span, "Internal error, expected `repetition` to be of type `Where`! Please report this issue!", )), }; for tuple in tuples.iter() { where_clause.predicates.push( ReplaceTuplePlaceholder::replace_ident_in_where_predicate( tuple_placeholder_ident, tuple, predicate.clone(), )?, ); } Ok(()) } } /// Replace the tuple place holder in the ast. struct ReplaceTuplePlaceholder<'a> { search: &'a Ident, replace: &'a Ident, use_self: bool, index: Index, errors: Vec, } impl<'a> ReplaceTuplePlaceholder<'a> { /// Replace the given `replace` ident in the given `stmt`. fn replace_ident_in_stmt( search: &'a Ident, replace: &'a Ident, use_self: bool, index: usize, stmt: Stmt, ) -> Result { let mut folder = Self { search, replace, use_self, index: index.into(), errors: Vec::new(), }; let res = fold::fold_stmt(&mut folder, stmt); if let Some(first) = folder.errors.pop() { Err(folder.errors.into_iter().fold(first, |mut e, n| { e.combine(n); e })) } else { Ok(res) } } /// Replace the given `replace` ident in the given `type_`. fn replace_ident_in_type(search: &'a Ident, replace: &'a Ident, type_: Type) -> Result { let mut folder = Self { search, replace, use_self: false, index: 0.into(), errors: Vec::new(), }; let res = fold::fold_type(&mut folder, type_); if let Some(first) = folder.errors.pop() { Err(folder.errors.into_iter().fold(first, |mut e, n| { e.combine(n); e })) } else { Ok(res) } } /// Replace the given `replace` ident in the given `where_predicate`. fn replace_ident_in_where_predicate( search: &'a Ident, replace: &'a Ident, where_predicate: WherePredicate, ) -> Result { let mut folder = Self { search, replace, use_self: false, index: 0.into(), errors: Vec::new(), }; let res = fold::fold_where_predicate(&mut folder, where_predicate); if let Some(first) = folder.errors.pop() { Err(folder.errors.into_iter().fold(first, |mut e, n| { e.combine(n); e })) } else { Ok(res) } } } impl<'a> Fold for ReplaceTuplePlaceholder<'a> { fn fold_ident(&mut self, ident: Ident) -> Ident { if &ident == self.search { self.replace.clone() } else { ident } } fn fold_expr(&mut self, expr: Expr) -> Expr { match expr { Expr::MethodCall(mut call) => match *call.receiver { Expr::Path(ref path) if path.path.is_ident(self.search) => { if self.use_self { let index = &self.index; call.receiver = parse_quote!( self.#index ); call.into() } else { self.errors.push(Error::new( path.span(), "Can not call non-static method from within a static method.", )); Expr::Verbatim(Default::default()) } } _ => fold::fold_expr_method_call(self, call).into(), }, _ => fold::fold_expr(self, expr), } } fn fold_expr_field(&mut self, mut expr: ExprField) -> ExprField { match expr.member { Member::Named(ref ident) if ident == self.search => { // Replace `something.Tuple` with `something.0`, `something.1`, etc. expr.member = Member::Unnamed(self.index.clone()); expr } _ => expr, } } } /// The expression of a const item. enum ConstExpr { /// repetition Simple { tuple_repetition: TupleRepetition }, /// &[ repetition ] RefArray { and_token: token::And, bracket_token: token::Bracket, tuple_repetition: TupleRepetition, }, } impl ConstExpr { /// Expand `self` into a [`TokenStream`]. fn expand( self, tuple_placeholder_ident: &Ident, tuples: &[Ident], use_self: bool, ) -> Result { match self { Self::Simple { tuple_repetition } => { tuple_repetition.expand_as_stmts(tuple_placeholder_ident, tuples, use_self) } Self::RefArray { and_token, bracket_token, tuple_repetition, } => { let repetition = tuple_repetition.expand_as_stmts(tuple_placeholder_ident, tuples, use_self)?; let mut token_stream = and_token.to_token_stream(); bracket_token.surround(&mut token_stream, |tokens| tokens.extend(repetition)); Ok(token_stream) } } } } impl Parse for ConstExpr { fn parse(input: ParseStream) -> Result { let lookahead1 = input.lookahead1(); if lookahead1.peek(token::And) { let content; Ok(ConstExpr::RefArray { and_token: input.parse()?, bracket_token: bracketed!(content in input), tuple_repetition: content.call(TupleRepetition::parse_as_stmts)?, }) } else if lookahead1.peek(token::Pound) { Ok(ConstExpr::Simple { tuple_repetition: TupleRepetition::parse_as_stmts(input)?, }) } else { Err(lookahead1.error()) } } } /// The `for_tuples!` macro syntax. enum ForTuplesMacro { /// The macro at an item type position. ItemType { type_token: token::Type, ident: Ident, equal_token: token::Eq, paren_token: token::Paren, tuple_repetition: TupleRepetition, semi_token: token::Semi, }, /// The macro at an item const position. ItemConst { const_token: token::Const, ident: Ident, colon_token: token::Colon, const_type: Type, equal_token: token::Eq, expr: ConstExpr, semi_token: token::Semi, }, /// The repetition stmt wrapped in parenthesis. StmtParenthesized { paren_token: token::Paren, tuple_repetition: TupleRepetition, }, /// Just the repetition stmt. Stmt { tuple_repetition: TupleRepetition }, /// A custom where clause. Where { _where_token: token::Where, tuple_repetition: TupleRepetition, }, } impl Parse for ForTuplesMacro { fn parse(input: ParseStream) -> Result { let lookahead1 = input.lookahead1(); if lookahead1.peek(token::Type) { let content; Ok(ForTuplesMacro::ItemType { type_token: input.parse()?, ident: input.parse()?, equal_token: input.parse()?, paren_token: parenthesized!(content in input), tuple_repetition: content.call(TupleRepetition::parse_as_type)?, semi_token: input.parse()?, }) } else if lookahead1.peek(token::Const) { Ok(ForTuplesMacro::ItemConst { const_token: input.parse()?, ident: input.parse()?, colon_token: input.parse()?, const_type: input.parse()?, equal_token: input.parse()?, expr: input.parse()?, semi_token: input.parse()?, }) } else if lookahead1.peek(token::Paren) { let content; Ok(ForTuplesMacro::StmtParenthesized { paren_token: parenthesized!(content in input), tuple_repetition: content.call(TupleRepetition::parse_as_stmts)?, }) } else if lookahead1.peek(token::Pound) { Ok(ForTuplesMacro::Stmt { tuple_repetition: input.call(TupleRepetition::parse_as_stmts)?, }) } else if lookahead1.peek(token::Where) { Ok(ForTuplesMacro::Where { _where_token: input.parse()?, tuple_repetition: input.call(TupleRepetition::parse_as_where_predicate)?, }) } else { Err(lookahead1.error()) } } } impl ForTuplesMacro { /// Try to parse the given macro as `Self`. /// /// `allow_where` signals that a custom where clause is allowed at this position. /// /// Returns `Ok(None)` if it is not a `for_tuples!` macro. fn try_from(macro_item: &Macro, allow_where: bool) -> Result> { // Not the macro we are searching for if !macro_item.path.is_ident("for_tuples") { return Ok(None); } let res = macro_item.parse_body::()?; if !allow_where && res.is_where() { Err(Error::new( macro_item.span(), "Custom where clause not allowed at this position!", )) } else { Ok(Some(res)) } } /// Is this a custom where clause? fn is_where(&self) -> bool { matches!(self, Self::Where { .. }) } /// Convert this into the where clause tuple repetition. fn into_where(self) -> Option { match self { Self::Where { tuple_repetition, .. } => Some(tuple_repetition), _ => None, } } /// Expand `self` to the actual implementation without the `for_tuples!` macro. /// /// This will unroll the repetition by replacing the placeholder identifier in each iteration /// with the one given in `tuples`. If `use_self` is `true`, the tuple will be access by using /// `self.x`. /// /// Returns the generated code. fn expand( self, tuple_placeholder_ident: &Ident, tuples: &[Ident], use_self: bool, ) -> TokenStream { match self { Self::ItemType { type_token, ident, equal_token, paren_token, tuple_repetition, semi_token, } => { let mut token_stream = type_token.to_token_stream(); let repetition = tuple_repetition.expand_as_type_declaration(tuple_placeholder_ident, tuples); match repetition { Ok(rep) => { ident.to_tokens(&mut token_stream); equal_token.to_tokens(&mut token_stream); paren_token.surround(&mut token_stream, |tokens| tokens.extend(rep)); semi_token.to_tokens(&mut token_stream); } Err(e) => token_stream.extend(e.to_compile_error()), } token_stream } Self::ItemConst { const_token, ident, colon_token, const_type, equal_token, expr, semi_token, } => { let mut token_stream = const_token.to_token_stream(); let expr = expr.expand(tuple_placeholder_ident, tuples, use_self); match expr { Ok(expr) => { ident.to_tokens(&mut token_stream); colon_token.to_tokens(&mut token_stream); const_type.to_tokens(&mut token_stream); equal_token.to_tokens(&mut token_stream); token_stream.extend(expr); semi_token.to_tokens(&mut token_stream); } Err(e) => token_stream.extend(e.to_compile_error()), } token_stream } Self::StmtParenthesized { paren_token, tuple_repetition, } => { let mut token_stream = TokenStream::new(); let repetition = tuple_repetition.expand_as_stmts(tuple_placeholder_ident, tuples, use_self); match repetition { Ok(rep) => { paren_token.surround(&mut token_stream, |tokens| tokens.extend(rep)) } Err(e) => token_stream.extend(e.to_compile_error()), } token_stream } Self::Stmt { tuple_repetition } => tuple_repetition .expand_as_stmts(tuple_placeholder_ident, tuples, use_self) .unwrap_or_else(|e| e.to_compile_error()), Self::Where { .. } => TokenStream::new(), } } } /// Add the tuple elements as generic parameters to the given trait implementation. fn add_tuple_elements_generics( tuples: &[Ident], mut trait_impl: ItemImpl, bound: Option, ) -> Result { crate::utils::add_tuple_element_generics(tuples, bound, &mut trait_impl.generics); Ok(trait_impl) } /// Fold a given trait implementation into a tuple implementation of the given trait. struct ToTupleImplementation<'a> { /// The tuple idents to use while expanding the repetitions. tuples: &'a [Ident], /// The placeholder ident given by the user. /// /// This placeholder ident while be replaced in the expansion with the correct tuple identifiers. tuple_placeholder_ident: &'a Ident, /// Any errors found while doing the conversion. errors: Vec, /// This is set to `true`, when folding in a function block that has a `self` parameter. has_self_parameter: bool, /// A custom where clause provided by the user. custom_where_clause: Option, } // Struct to parse custom trait bounds #[derive(Debug)] struct BoundsStruct { _paren_token: token::Paren, bounds: syn::TypeTraitObject, } impl Parse for BoundsStruct { fn parse(input: ParseStream) -> Result { let content; Ok(BoundsStruct { _paren_token: parenthesized!(content in input), bounds: content.parse()?, }) } } impl<'a> ToTupleImplementation<'a> { /// Generate the tuple implementation for the given `tuples`. fn generate_implementation( trait_impl: &ItemImpl, tuple_placeholder_ident: &'a Ident, tuples: &'a [Ident], ref_tuples: bool, ) -> Result { let mut to_tuple = ToTupleImplementation { tuples, errors: Vec::new(), tuple_placeholder_ident, has_self_parameter: false, custom_where_clause: None, }; let mut res = fold::fold_item_impl(&mut to_tuple, trait_impl.clone()); let default_trait = trait_impl.trait_.clone().map(|t| t.1).ok_or_else(|| { Error::new( trait_impl.span(), "The semi-automatic implementation is required to implement a trait!", ) })?; // Check if we should customize the trait bound let trait_ = if let Some(pos) = res .attrs .iter() .position(|a| a.path.is_ident(TUPLE_TYPES_CUSTOM_TRAIT_BOUND)) { // Parse custom trait bound let attr = &res.attrs[pos]; let input = attr.tokens.to_token_stream(); let result = syn::parse2::(input); let trait_name = match result { Ok(b) => b.bounds, Err(e) => { return Err(Error::new( e.span(), format!("Invalid trait bound: {}", e.to_string()), )) } }; res.attrs.remove(pos); quote! { #trait_name } } else { quote! { #default_trait } }; // Check if we should add the bound to the implemented trait for each tuple type. let add_bound = if let Some(pos) = res .attrs .iter() .position(|a| a.path.is_ident(TUPLE_TYPES_NO_DEFAULT_TRAIT_BOUND)) { res.attrs.remove(pos); None } else { Some(trait_) }; // Add the tuple generics let mut res = add_tuple_elements_generics(tuples, res, add_bound)?; // Add the correct self type if ref_tuples { res.self_ty = parse_quote!( ( #( &#tuples, )* ) ); } else { res.self_ty = parse_quote!( ( #( #tuples, )* ) ); }; res.attrs.push(parse_quote!(#[allow(unused)])); if let Some(where_clause) = to_tuple.custom_where_clause.take() { where_clause.expand_to_where_clause( tuple_placeholder_ident, tuples, res.generics.make_where_clause(), )?; } if let Some(first_error) = to_tuple.errors.pop() { Err(to_tuple.errors.into_iter().fold(first_error, |mut e, n| { e.combine(n); e })) } else { Ok(res.to_token_stream()) } } /// Fold the expr and returns the folded expr and if it was a `for_tuples!`. fn custom_fold_expr(&mut self, expr: Expr) -> (Expr, bool) { match expr { Expr::Macro(expr_macro) => match ForTuplesMacro::try_from(&expr_macro.mac, false) { Ok(Some(for_tuples)) => ( Expr::Verbatim(for_tuples.expand( &self.tuple_placeholder_ident, self.tuples, self.has_self_parameter, )), true, ), Ok(None) => (fold::fold_expr_macro(self, expr_macro).into(), false), Err(e) => { self.errors.push(e); (Expr::Verbatim(Default::default()), false) } }, _ => (fold::fold_expr(self, expr), false), } } } impl<'a> Fold for ToTupleImplementation<'a> { fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem { match i { ImplItem::Macro(macro_item) => match ForTuplesMacro::try_from(¯o_item.mac, true) { Ok(Some(for_tuples)) => { if for_tuples.is_where() { if self.custom_where_clause.is_some() { self.errors.push(Error::new( macro_item.span(), "Only one custom where clause is supported!", )); } else { self.custom_where_clause = for_tuples.into_where(); } ImplItem::Verbatim(Default::default()) } else { ImplItem::Verbatim(for_tuples.expand( &self.tuple_placeholder_ident, self.tuples, false, )) } } Ok(None) => fold::fold_impl_item_macro(self, macro_item).into(), Err(e) => { self.errors.push(e); ImplItem::Verbatim(Default::default()) } }, _ => fold::fold_impl_item(self, i), } } fn fold_expr(&mut self, expr: Expr) -> Expr { self.custom_fold_expr(expr).0 } fn fold_stmt(&mut self, stmt: Stmt) -> Stmt { let (expr, trailing_semi) = match stmt { Stmt::Expr(expr) => (expr, None), Stmt::Semi(expr, semi) => (expr, Some(semi)), _ => return fold::fold_stmt(self, stmt), }; let (expr, expanded) = self.custom_fold_expr(expr); if expanded { Stmt::Expr(expr) } else if let Some(semi) = trailing_semi { Stmt::Semi(expr, semi) } else { Stmt::Expr(expr) } } fn fold_type(&mut self, ty: Type) -> Type { match ty { Type::Macro(ty_macro) => match ForTuplesMacro::try_from(&ty_macro.mac, false) { Ok(Some(for_tuples)) => Type::Verbatim(for_tuples.expand( &self.tuple_placeholder_ident, self.tuples, false, )), Ok(None) => fold::fold_type_macro(self, ty_macro).into(), Err(e) => { self.errors.push(e); Type::Verbatim(Default::default()) } }, _ => fold::fold_type(self, ty), } } fn fold_impl_item_method(&mut self, mut impl_item_method: ImplItemMethod) -> ImplItemMethod { let has_self = impl_item_method .sig .inputs .first() .map(|a| match a { FnArg::Receiver(_) => true, _ => false, }) .unwrap_or(false); impl_item_method.sig = fold::fold_signature(self, impl_item_method.sig); // Store the old value and set the current one let old_has_self_parameter = self.has_self_parameter; self.has_self_parameter = has_self; impl_item_method.block = fold::fold_block(self, impl_item_method.block); self.has_self_parameter = old_has_self_parameter; impl_item_method } } /// Extracts the tuple placeholder ident from the given trait implementation. fn extract_tuple_placeholder_ident(trait_impl: &ItemImpl) -> Result<(bool, Ident)> { match *trait_impl.self_ty { Type::Reference(ref type_ref) => { if let Type::Path(ref type_path) = *type_ref.elem { if let Some(ident) = type_path.path.get_ident() { return Ok((true, ident.clone())); } } } Type::Path(ref type_path) => { if let Some(ident) = type_path.path.get_ident() { return Ok((false, ident.clone())); } } _ => {} } Err(Error::new( trait_impl.self_ty.span(), "Expected an `Ident` as tuple placeholder.", )) } /// Generate the semi-automatic tuple implementations for a given trait implementation and the given tuples. pub fn semi_automatic_impl( trait_impl: ItemImpl, tuple_elements: Vec, min: Option, ) -> Result { let placeholder_ident = extract_tuple_placeholder_ident(&trait_impl)?; let mut res = TokenStream::new(); (min.unwrap_or(0)..=tuple_elements.len()).try_for_each(|i| { res.extend(ToTupleImplementation::generate_implementation( &trait_impl, &placeholder_ident.1, &tuple_elements[..i], placeholder_ident.0, )?); Ok::<_, Error>(()) })?; Ok(res) } impl-trait-for-tuples-0.2.2/src/utils.rs000064400000000000000000000011140072674642500163270ustar 00000000000000//! Provides common utils function shared between full and semi-automatic. use proc_macro2::TokenStream; use syn::{parse_quote, Generics, Ident}; use quote::quote; /// Add the given tuple elements as generics with the given `bounds` to `generics`. pub fn add_tuple_element_generics( tuple_elements: &[Ident], bounds: Option, generics: &mut Generics, ) { let bound = bounds.map(|b| quote!(: #b)).unwrap_or_else(|| quote!()); tuple_elements.iter().for_each(|tuple_element| { generics.params.push(parse_quote!(#tuple_element #bound)); }); } impl-trait-for-tuples-0.2.2/tests/codegen.rs000064400000000000000000000346650072674642500171670ustar 00000000000000use impl_trait_for_tuples::impl_for_tuples; #[test] fn is_implemented_for_tuples() { #[impl_for_tuples(5)] trait EmptyTrait {} struct EmptyTraitImpl; impl EmptyTrait for EmptyTraitImpl {} fn test() {} test::<()>(); test::(); test::<(EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl)>(); test::<( EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, )>(); test::<( ( EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, ), ( EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, ), )>(); } #[test] fn full_automatic_accept_empty_tuple_return() { #[impl_for_tuples(5)] trait EmptyTupleReturn { fn test() -> (); } } #[test] fn full_automatic_unsafe_trait() { #[impl_for_tuples(5)] unsafe trait UnsafeTrait { fn test(); } } #[test] fn accept_attributes() { /// Hey, I'm an attribute! #[cfg(test)] #[impl_for_tuples(5)] trait Attributes {} trait Test {} /// Hey, I'm an attribute! #[cfg(test)] #[impl_for_tuples(5)] impl Test for Tuple {} } #[test] fn is_implemented_for_tuples_with_semi() { trait EmptyTrait {} #[impl_for_tuples(5)] impl EmptyTrait for Tuple {} struct EmptyTraitImpl; impl EmptyTrait for EmptyTraitImpl {} fn test() {} test::<()>(); test::(); test::<(EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl)>(); test::<( EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, )>(); test::<( ( EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, ), ( EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, EmptyTraitImpl, ), )>(); } #[test] fn trait_with_static_functions() { #[impl_for_tuples(50)] trait TraitWithFunctions { fn function(counter: &mut u32); fn function_with_args(data: String, l: u32); fn function_with_args_wild(_: String, _: u32); } struct Impl; impl TraitWithFunctions for Impl { fn function(counter: &mut u32) { *counter += 1; } fn function_with_args(_: String, _: u32) {} fn function_with_args_wild(_: String, _: u32) {} } fn test(counter: &mut u32) { T::function(counter); } let mut counter = 0; test::<(Impl, Impl, Impl)>(&mut counter); assert_eq!(3, counter); let mut counter = 0; test::<(Impl, Impl, Impl, Impl, Impl)>(&mut counter); assert_eq!(5, counter); } #[test] fn trait_with_functions() { #[impl_for_tuples(50)] trait TraitWithFunctions { fn function(&self, counter: &mut u32); fn function_with_args(&self, data: String, l: u32); fn function_with_args_wild(self, _: String, _: u32); } struct Impl; impl TraitWithFunctions for Impl { fn function(&self, counter: &mut u32) { *counter += 1; } fn function_with_args(&self, _: String, _: u32) {} fn function_with_args_wild(self, _: String, _: u32) {} } fn test(data: T, counter: &mut u32) { data.function(counter); } let mut counter = 0; test((Impl, Impl, Impl), &mut counter); assert_eq!(3, counter); let mut counter = 0; test((Impl, Impl, Impl, Impl, Impl), &mut counter); assert_eq!(5, counter); } #[test] fn trait_with_static_functions_and_generics() { #[impl_for_tuples(50)] trait TraitWithFunctions { fn function(counter: &mut u32); fn function_with_args(data: String, l: T); fn function_with_args_wild(_: String, _: &N); } struct Impl; impl TraitWithFunctions for Impl { fn function(counter: &mut u32) { *counter += 1; } fn function_with_args(_: String, _: T) {} fn function_with_args_wild(_: String, _: &N) {} } fn test>(counter: &mut u32) { T::function(counter); } let mut counter = 0; test::<()>(&mut counter); assert_eq!(0, counter); let mut counter = 0; test::(&mut counter); assert_eq!(1, counter); let mut counter = 0; test::<(Impl, Impl, Impl)>(&mut counter); assert_eq!(3, counter); let mut counter = 0; test::<(Impl, Impl, Impl, Impl, Impl)>(&mut counter); assert_eq!(5, counter); } #[test] fn trait_with_return_type() { trait TraitWithReturnType { fn function(counter: &mut u32) -> Result<(), ()>; } #[impl_for_tuples(50)] impl TraitWithReturnType for Tuple { fn function(counter: &mut u32) -> Result<(), ()> { for_tuples!( #( Tuple::function(counter)?; )* ); Ok(()) } } struct Impl; impl TraitWithReturnType for Impl { fn function(counter: &mut u32) -> Result<(), ()> { *counter += 1; Ok(()) } } fn test(counter: &mut u32) { T::function(counter).unwrap(); } let mut counter = 0; test::<()>(&mut counter); assert_eq!(0, counter); let mut counter = 0; test::(&mut counter); assert_eq!(1, counter); let mut counter = 0; test::<(Impl, Impl, Impl)>(&mut counter); assert_eq!(3, counter); let mut counter = 0; test::<(Impl, Impl, Impl, Impl, Impl)>(&mut counter); assert_eq!(5, counter); } #[test] fn trait_with_associated_type() { trait TraitWithAssociatedType { type Ret; fn function(counter: &mut u32) -> Self::Ret; } #[impl_for_tuples(50)] impl TraitWithAssociatedType for Tuple { for_tuples!( type Ret = ( #( Tuple::Ret ),* ); ); fn function(counter: &mut u32) -> Self::Ret { for_tuples!( ( #( Tuple::function(counter) ),* ) ) } } struct Impl; impl TraitWithAssociatedType for Impl { type Ret = u32; fn function(counter: &mut u32) -> u32 { *counter += 1; *counter } } fn test(counter: &mut u32) -> T::Ret { T::function(counter) } let mut counter = 0; let res = test::<()>(&mut counter); assert_eq!(0, counter); assert_eq!((), res); let mut counter = 0; let res = test::(&mut counter); assert_eq!(1, counter); assert_eq!((1), res); let mut counter = 0; let res = test::<(Impl, Impl, Impl)>(&mut counter); assert_eq!(3, counter); assert_eq!((1, 2, 3), res); let mut counter = 0; let res = test::<(Impl, Impl, Impl, Impl, Impl)>(&mut counter); assert_eq!(5, counter); assert_eq!((1, 2, 3, 4, 5), res); } #[test] fn trait_with_associated_type_and_generics() { trait TraitWithAssociatedType { type Ret; fn function(counter: &mut u32) -> Self::Ret; } #[impl_for_tuples(50)] impl TraitWithAssociatedType for Tuple { for_tuples!( type Ret = ( #( Tuple::Ret ),* ); ); fn function(counter: &mut u32) -> Self::Ret { for_tuples!( ( #( Tuple::function(counter) ),* ) ) } } struct Impl; impl TraitWithAssociatedType for Impl { type Ret = u32; fn function(counter: &mut u32) -> u32 { *counter += 1; *counter } } fn test>(counter: &mut u32) -> T::Ret { T::function(counter) } let mut counter = 0; let res = test::<()>(&mut counter); assert_eq!(0, counter); assert_eq!((), res); let mut counter = 0; let res = test::(&mut counter); assert_eq!(1, counter); assert_eq!((1), res); let mut counter = 0; let res = test::<(Impl, Impl, Impl)>(&mut counter); assert_eq!(3, counter); assert_eq!((1, 2, 3), res); let mut counter = 0; let res = test::<(Impl, Impl, Impl, Impl, Impl)>(&mut counter); assert_eq!(5, counter); assert_eq!((1, 2, 3, 4, 5), res); } #[test] fn trait_with_associated_type_and_self() { trait TraitWithAssociatedTypeAndSelf { type Ret; fn function(&self, counter: &mut u32) -> Self::Ret; } #[impl_for_tuples(50)] impl TraitWithAssociatedTypeAndSelf for Tuple { for_tuples!( type Ret = ( #( Tuple::Ret ),* ); ); fn function(&self, counter: &mut u32) -> Self::Ret { for_tuples!( ( #( Tuple.function(counter) ),* ) ) } } struct Impl; impl TraitWithAssociatedTypeAndSelf for Impl { type Ret = u32; fn function(&self, counter: &mut u32) -> u32 { *counter += 1; *counter } } fn test(data: T, counter: &mut u32) -> T::Ret { data.function(counter) } let mut counter = 0; let res = test((), &mut counter); assert_eq!(0, counter); assert_eq!((), res); let mut counter = 0; let res = test(Impl, &mut counter); assert_eq!(1, counter); assert_eq!((1), res); let mut counter = 0; let res = test((Impl, Impl, Impl), &mut counter); assert_eq!(3, counter); assert_eq!((1, 2, 3), res); let mut counter = 0; let res = test((Impl, Impl, Impl, Impl, Impl), &mut counter); assert_eq!(5, counter); assert_eq!((1, 2, 3, 4, 5), res); } #[test] fn semi_automatic_tuple_access() { trait Trait { type Arg; fn test(arg: Self::Arg); } #[impl_for_tuples(5)] impl Trait for Tuple { for_tuples!( type Arg = ( #( Tuple::Arg ),* ); ); fn test(arg: Self::Arg) { for_tuples!( #( Tuple::test(arg.Tuple); )* ) } } } #[test] fn semi_automatic_with_custom_where_clause() { trait Trait { type Arg; fn test(arg: Self::Arg); } #[impl_for_tuples(5)] impl Trait for Tuple { for_tuples!( where #( Tuple: Trait ),* ); type Arg = u32; fn test(arg: Self::Arg) { for_tuples!( #( Tuple::test(arg); )* ) } } } #[test] fn for_tuples_in_nested_expr_works() { trait Trait { type Arg; type Res; fn test(arg: Self::Arg) -> Result; } #[impl_for_tuples(5)] impl Trait for Tuple { for_tuples!( where #( Tuple: Trait ),* ); type Arg = u32; for_tuples!( type Res = ( #( Tuple::Res ),* ); ); fn test(arg: Self::Arg) -> Result { Ok(for_tuples!( ( #( Tuple::test(arg)? ),* ) )) } } } #[test] fn test_separators() { trait Trait { fn plus() -> u32; fn minus() -> i32; fn star() -> u32; } #[impl_for_tuples(1, 5)] impl Trait for Tuple { fn plus() -> u32 { for_tuples!( #( Tuple::plus() )+* ) } fn minus() -> i32 { for_tuples!( #( Tuple::minus() )-* ) } fn star() -> u32 { for_tuples!( #( Tuple::star() )** ) } } struct Impl; impl Trait for Impl { fn plus() -> u32 { 5 } fn minus() -> i32 { 1000 } fn star() -> u32 { 5 } } assert_eq!(<(Impl, Impl, Impl)>::plus(), 15); assert_eq!(<(Impl, Impl, Impl)>::star(), 125); assert_eq!(<(Impl, Impl, Impl)>::minus(), -1000); } #[test] fn semi_automatic_tuple_with_custom_trait_bound() { trait Trait { type Arg; fn test(arg: Self::Arg); } trait Custom { type NewArg; fn new_test(arg: Self::NewArg); } #[impl_for_tuples(5)] #[tuple_types_custom_trait_bound(Custom)] impl Trait for Tuple { for_tuples!( type Arg = ( #( Tuple::NewArg ),* ); ); fn test(arg: Self::Arg) { for_tuples!( #( Tuple::new_test(arg.Tuple); )* ); } } } #[test] fn semi_automatic_tuple_with_custom_advanced_trait_bound() { trait Trait { type Arg; type Output; fn test(arg: Self::Arg); fn clone_test(&self) -> Self::Output; } trait Custom { type NewArg; fn new_test(arg: Self::NewArg); } #[impl_for_tuples(5)] #[tuple_types_custom_trait_bound(Custom + Clone)] impl Trait for Tuple { for_tuples!( type Arg = ( #( Tuple::NewArg ),* ); ); for_tuples!( type Output = ( #( Tuple ),* ); ); fn test(arg: Self::Arg) { for_tuples!( #( Tuple::new_test(arg.Tuple); )* ); } fn clone_test(&self) -> Self::Output { for_tuples!( ( #( Tuple.clone() ),* ) ); } } } #[test] fn semi_automatic_tuple_as_ref() { trait Trait { type Arg; fn test(arg: Self::Arg); } #[impl_for_tuples(5)] impl Trait for &Tuple { for_tuples!( type Arg = ( #( Tuple::Arg ),* ); ); fn test(arg: Self::Arg) { for_tuples!( #( Tuple::test(arg.Tuple); )* ) } } } #[test] fn semi_automatic_associated_const() { trait Trait { const TYPE: &'static [u32]; } trait Trait2 { const TYPE: u32; } #[impl_for_tuples(1, 5)] #[tuple_types_no_default_trait_bound] impl Trait for Tuple { for_tuples!( where #( Tuple: Trait2 )* ); for_tuples!( const TYPE: &'static [u32] = &[ #( Tuple::TYPE ),* ]; ); } } #[test] fn semi_automatic_associated_const_calculation() { trait Trait { const TYPE: u32; } #[impl_for_tuples(1, 5)] impl Trait for Tuple { for_tuples!( const TYPE: u32 = #( Tuple::TYPE )+*; ); } struct Test; impl Trait for Test { const TYPE: u32 = 1; } assert_eq!(3, <(Test, Test, Test)>::TYPE); assert_eq!(1, Test::TYPE); } #[test] fn semi_automatic_associated_type() { trait Trait { type A; type B; } #[impl_for_tuples(5)] impl Trait for Tuple { for_tuples!( type A = ( #( Option< Tuple::B > ),* ); ); for_tuples!( type B = ( #( Tuple::B ),* ); ); } } #[test] fn semi_automatic_unsafe_trait() { unsafe trait Trait { type A; } #[impl_for_tuples(5)] unsafe impl Trait for Tuple { for_tuples!( type A = ( #( Tuple::A ),* ); ); } } impl-trait-for-tuples-0.2.2/tests/fail/custom_trait_bound_invalid.rs000064400000000000000000000011320072674642500240670ustar 00000000000000trait Test { type Arg; fn test(arg: Self::Arg); } trait Custom { type NewArg; fn new_test(arg: Self::NewArg); } #[impl_trait_for_tuples::impl_for_tuples(5)] #[tuple_types_custom_trait_bound(Custom, Clone)] impl Test for Tuple { for_tuples!( type Arg = ( #( Tuple::NewArg ),* ); ); fn test(arg: Self::Arg) { for_tuples!( #( Tuple::new_test(arg.Tuple); )* ); } } struct Impl; impl Custom for Impl { type NewArg = (); fn new_test(_arg: Self::NewArg) {} } fn test() {} fn main() { test::<(Impl, Impl)>(); test::<(Impl, Impl, Impl)>(); } impl-trait-for-tuples-0.2.2/tests/fail/custom_trait_bound_invalid.stderr000064400000000000000000000020630072674642500247520ustar 00000000000000error: Invalid trait bound: unexpected token --> tests/fail/custom_trait_bound_invalid.rs:14:40 | 14 | #[tuple_types_custom_trait_bound(Custom, Clone)] | ^ error[E0277]: the trait bound `(Impl, Impl): Test` is not satisfied --> tests/fail/custom_trait_bound_invalid.rs:32:12 | 32 | test::<(Impl, Impl)>(); | ^^^^^^^^^^^^ the trait `Test` is not implemented for `(Impl, Impl)` | note: required by a bound in `test` --> tests/fail/custom_trait_bound_invalid.rs:30:12 | 30 | fn test() {} | ^^^^ required by this bound in `test` error[E0277]: the trait bound `(Impl, Impl, Impl): Test` is not satisfied --> tests/fail/custom_trait_bound_invalid.rs:33:12 | 33 | test::<(Impl, Impl, Impl)>(); | ^^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `(Impl, Impl, Impl)` | note: required by a bound in `test` --> tests/fail/custom_trait_bound_invalid.rs:30:12 | 30 | fn test() {} | ^^^^ required by this bound in `test` impl-trait-for-tuples-0.2.2/tests/fail/trait_bound_not_added.rs000064400000000000000000000005240072674642500227740ustar 00000000000000trait Test { fn test(); } #[impl_trait_for_tuples::impl_for_tuples(5)] #[tuple_types_no_default_trait_bound] impl Test for Tuple { fn test() { for_tuples!( #( Tuple::test(); )* ) } } struct Impl; impl Test for Impl {} fn test() {} fn main() { test::<(Impl, Impl)>(); test::<(Impl, Impl, Impl)>(); } impl-trait-for-tuples-0.2.2/tests/fail/trait_bound_not_added.stderr000064400000000000000000000057330072674642500236620ustar 00000000000000error[E0046]: not all trait items implemented, missing: `test` --> $DIR/trait_bound_not_added.rs:15:1 | 2 | fn test(); | ---------- `test` from trait ... 15 | impl Test for Impl {} | ^^^^^^^^^^^^^^^^^^ missing `test` in implementation error[E0599]: no function or associated item named `test` found for type parameter `TupleElement0` in the current scope --> $DIR/trait_bound_not_added.rs:9:32 | 9 | for_tuples!( #( Tuple::test(); )* ) | ^^^^ function or associated item not found in `TupleElement0` | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `test`, perhaps you need to restrict type parameter `TupleElement0` with it: | 5 | TupleElement0: Test | error[E0599]: no function or associated item named `test` found for type parameter `TupleElement1` in the current scope --> $DIR/trait_bound_not_added.rs:9:32 | 9 | for_tuples!( #( Tuple::test(); )* ) | ^^^^ function or associated item not found in `TupleElement1` | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `test`, perhaps you need to restrict type parameter `TupleElement1` with it: | 5 | TupleElement1: Test | error[E0599]: no function or associated item named `test` found for type parameter `TupleElement2` in the current scope --> $DIR/trait_bound_not_added.rs:9:32 | 9 | for_tuples!( #( Tuple::test(); )* ) | ^^^^ function or associated item not found in `TupleElement2` | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `test`, perhaps you need to restrict type parameter `TupleElement2` with it: | 5 | TupleElement2: Test | error[E0599]: no function or associated item named `test` found for type parameter `TupleElement3` in the current scope --> $DIR/trait_bound_not_added.rs:9:32 | 9 | for_tuples!( #( Tuple::test(); )* ) | ^^^^ function or associated item not found in `TupleElement3` | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `test`, perhaps you need to restrict type parameter `TupleElement3` with it: | 5 | TupleElement3: Test | error[E0599]: no function or associated item named `test` found for type parameter `TupleElement4` in the current scope --> $DIR/trait_bound_not_added.rs:9:32 | 9 | for_tuples!( #( Tuple::test(); )* ) | ^^^^ function or associated item not found in `TupleElement4` | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `test`, perhaps you need to restrict type parameter `TupleElement4` with it: | 5 | TupleElement4: Test | impl-trait-for-tuples-0.2.2/tests/fail/tuple_impls_less_than_minimum_does_not_exists.rs000064400000000000000000000003060072674642500301000ustar 00000000000000#[impl_trait_for_tuples::impl_for_tuples(3, 5)] trait Test {} struct Impl; impl Test for Impl {} fn test() {} fn main() { test::<(Impl, Impl)>(); test::<(Impl, Impl, Impl)>(); } impl-trait-for-tuples-0.2.2/tests/fail/tuple_impls_less_than_minimum_does_not_exists.stderr000064400000000000000000000007140072674642500307620ustar 00000000000000error[E0277]: the trait bound `(Impl, Impl): Test` is not satisfied --> tests/fail/tuple_impls_less_than_minimum_does_not_exists.rs:10:12 | 10 | test::<(Impl, Impl)>(); | ^^^^^^^^^^^^ the trait `Test` is not implemented for `(Impl, Impl)` | note: required by a bound in `test` --> tests/fail/tuple_impls_less_than_minimum_does_not_exists.rs:8:12 | 8 | fn test() {} | ^^^^ required by this bound in `test` impl-trait-for-tuples-0.2.2/tests/fail.rs000064400000000000000000000001450072674642500164600ustar 00000000000000#[test] fn fail() { let t = trybuild::TestCases::new(); t.compile_fail("tests/fail/*.rs"); } impl-trait-for-tuples-0.2.2/tests/ui/calling_method_in_static_function.rs000064400000000000000000000004340072674642500250760ustar 00000000000000trait Test { type Test; fn test() -> Self::Test; } #[impl_trait_for_tuples::impl_for_tuples(2)] impl Test for Tuple { for_tuples!( type Test = ( #( Tuple::Test ),* ); ); fn test() -> Self::Test { for_tuples!( ( #( Tuple.test() ),* ) ) } } fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/calling_method_in_static_function.stderr000064400000000000000000000003270072674642500257560ustar 00000000000000error: Can not call non-static method from within a static method. --> $DIR/calling_method_in_static_function.rs:12:27 | 12 | for_tuples!( ( #( Tuple.test() ),* ) ) | ^^^^^ impl-trait-for-tuples-0.2.2/tests/ui/custom_where_clause_not_allowed.rs000064400000000000000000000002700072674642500246100ustar 00000000000000trait Test { fn test(); } #[impl_trait_for_tuples::impl_for_tuples(2)] impl Test for Tuple { fn test() { for_tuples!( where #( Tuple: Test ),* ) } } fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/custom_where_clause_not_allowed.stderr000064400000000000000000000003260072674642500254710ustar 00000000000000error: Custom where clause not allowed at this position! --> $DIR/custom_where_clause_not_allowed.rs:8:9 | 8 | for_tuples!( where #( Tuple: Test ),* ) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl-trait-for-tuples-0.2.2/tests/ui/empty_for_tuples.rs000064400000000000000000000004030072674642500215570ustar 00000000000000trait Test { type Test; fn test() -> Self::Test; } #[impl_trait_for_tuples::impl_for_tuples(1)] impl Test for Tuple { for_tuples!( type Test = ( #( Tuple::Test ),* ); ); fn test() -> Self::Test { for_tuples!() } } fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/empty_for_tuples.stderr000064400000000000000000000003000072674642500224320ustar 00000000000000error: unexpected end of input, expected one of: `type`, `const`, parentheses, `#`, `where` --> tests/ui/empty_for_tuples.rs:12:20 | 12 | for_tuples!() | ^^ impl-trait-for-tuples-0.2.2/tests/ui/max_before_min_in_arguments.rs000064400000000000000000000001140072674642500237030ustar 00000000000000#[impl_trait_for_tuples::impl_for_tuples(5, 2)] trait Test {} fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/max_before_min_in_arguments.stderr000064400000000000000000000006220072674642500245660ustar 00000000000000error: It is expected that `min` comes before `max` and that `max > min` is true! --> tests/ui/max_before_min_in_arguments.rs:1:1 | 1 | #[impl_trait_for_tuples::impl_for_tuples(5, 2)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the attribute macro `impl_trait_for_tuples::impl_for_tuples` (in Nightly builds, run with -Z macro-backtrace for more info) impl-trait-for-tuples-0.2.2/tests/ui/missing_arguments_to_macro.rs000064400000000000000000000001100072674642500235730ustar 00000000000000#[impl_trait_for_tuples::impl_for_tuples()] trait Test {} fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/missing_arguments_to_macro.stderr000064400000000000000000000005530072674642500244650ustar 00000000000000error: Expected at least one argument to the macro! --> tests/ui/missing_arguments_to_macro.rs:1:1 | 1 | #[impl_trait_for_tuples::impl_for_tuples()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the attribute macro `impl_trait_for_tuples::impl_for_tuples` (in Nightly builds, run with -Z macro-backtrace for more info) impl-trait-for-tuples-0.2.2/tests/ui/missing_paren_in_for_tuples.rs000064400000000000000000000002460072674642500237520ustar 00000000000000trait Test { type Test; } #[impl_trait_for_tuples::impl_for_tuples(1)] impl Test for Tuple { for_tuples!( type Test = #( Tuple::Test ),*; ); } fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/missing_paren_in_for_tuples.stderr000064400000000000000000000002550072674642500246310ustar 00000000000000error: expected parentheses --> tests/ui/missing_paren_in_for_tuples.rs:7:30 | 7 | for_tuples!( type Test = #( Tuple::Test ),*; ); | ^ impl-trait-for-tuples-0.2.2/tests/ui/no_const_value.rs000064400000000000000000000001340072674642500211760ustar 00000000000000#[impl_trait_for_tuples::impl_for_tuples(1)] trait Test { const Test: u32; } fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/no_const_value.stderr000064400000000000000000000003430072674642500220570ustar 00000000000000error: Not supported by full-automatic tuple implementation. Use semi-automatic tuple implementation for more control of the implementation. --> $DIR/no_const_value.rs:3:2 | 3 | const Test: u32; | ^^^^^^^^^^^^^^^^ impl-trait-for-tuples-0.2.2/tests/ui/no_return_value.rs000064400000000000000000000001400072674642500213640ustar 00000000000000#[impl_trait_for_tuples::impl_for_tuples(1)] trait Test { fn test() -> u32; } fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/no_return_value.stderr000064400000000000000000000003460072674642500222530ustar 00000000000000error: Not supported by full-automatic tuple implementation. Use semi-automatic tuple implementation for more control of the implementation. --> $DIR/no_return_value.rs:3:15 | 3 | fn test() -> u32; | ^^^^^^ impl-trait-for-tuples-0.2.2/tests/ui/no_type_parameter.rs000064400000000000000000000001260072674642500216760ustar 00000000000000#[impl_trait_for_tuples::impl_for_tuples(1)] trait Test { type Test; } fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/no_type_parameter.stderr000064400000000000000000000003320072674642500225540ustar 00000000000000error: Not supported by full-automatic tuple implementation. Use semi-automatic tuple implementation for more control of the implementation. --> $DIR/no_type_parameter.rs:3:2 | 3 | type Test; | ^^^^^^^^^^ impl-trait-for-tuples-0.2.2/tests/ui/too_much_arguments_to_macro.rs000064400000000000000000000001170072674642500237460ustar 00000000000000#[impl_trait_for_tuples::impl_for_tuples(1, 2, 3)] trait Test {} fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/too_much_arguments_to_macro.stderr000064400000000000000000000005640072674642500246330ustar 00000000000000error: Too many arguments given to the macro! --> tests/ui/too_much_arguments_to_macro.rs:1:1 | 1 | #[impl_trait_for_tuples::impl_for_tuples(1, 2, 3)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the attribute macro `impl_trait_for_tuples::impl_for_tuples` (in Nightly builds, run with -Z macro-backtrace for more info) impl-trait-for-tuples-0.2.2/tests/ui/unknown_separator.rs000064400000000000000000000004340072674642500217420ustar 00000000000000trait Test { type Test; fn test() -> Self::Test; } #[impl_trait_for_tuples::impl_for_tuples(2)] impl Test for Tuple { for_tuples!( type Test = ( #( Tuple::Test ),* ); ); fn test() -> Self::Test { for_tuples!( ( #( Tuple.test() )$* ) ) } } fn main() {} impl-trait-for-tuples-0.2.2/tests/ui/unknown_separator.stderr000064400000000000000000000003140072674642500226160ustar 00000000000000error: expected one of: `,`, `+`, `-`, `|`, `&`, `*`, `/` --> tests/ui/unknown_separator.rs:12:41 | 12 | for_tuples!( ( #( Tuple.test() )$* ) ) | ^ impl-trait-for-tuples-0.2.2/tests/ui.rs000064400000000000000000000001410072674642500161560ustar 00000000000000#[test] fn ui() { let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); }