190190//! # Conditionals
191191//!
192192//! The `typle!` macro accepts an `if` statement with an optional `else` clause.
193- //! If there is no `else` clause the macro filters out components that do not match
193+ //! If there is no `else` clause the macro filters out elements that do not match
194194//! the condition.
195195//!
196196//! The `typle_attr_if` attribute allows conditional inclusion of attributes. It works similarly to
@@ -714,7 +714,7 @@ use context::TypleContext;
714714use proc_macro2:: { Ident , TokenStream , TokenTree } ;
715715use quote:: ToTokens ;
716716use syn:: spanned:: Spanned as _;
717- use syn:: { Error , Item , Type , TypeNever } ;
717+ use syn:: { Error , Expr , Item , Type , TypeNever } ;
718718
719719#[ doc( hidden) ]
720720#[ proc_macro_attribute]
@@ -756,6 +756,7 @@ struct TypleMacro {
756756 min_len : usize ,
757757 max_len : usize ,
758758 never_type : Type ,
759+ suffixes : Vec < String > ,
759760}
760761
761762impl TryFrom < TokenStream > for TypleMacro {
@@ -767,6 +768,7 @@ impl TryFrom<TokenStream> for TypleMacro {
767768 let mut never_type = Type :: Never ( TypeNever {
768769 bang_token : syn:: token:: Not :: default ( ) ,
769770 } ) ;
771+ let mut suffixes = Vec :: new ( ) ;
770772 let mut args_iter = args. into_iter ( ) ;
771773 // Tuple
772774 let Some ( TokenTree :: Ident ( trait_ident) ) = args_iter. next ( ) else {
@@ -780,24 +782,27 @@ impl TryFrom<TokenStream> for TypleMacro {
780782 }
781783 }
782784
783- let mut range_tokens = TokenStream :: new ( ) ;
784- let mut never_tokens = Vec :: new ( ) ;
785- let mut comma_seen = false ;
786- for token in args_iter {
787- if comma_seen {
788- never_tokens. push ( token) ;
789- } else {
790- if let TokenTree :: Punct ( punct) = & token {
791- if punct. as_char ( ) == ',' {
792- comma_seen = true ;
793- continue ;
794- }
785+ let mut sections = Vec :: new ( ) ;
786+ let mut section = Vec :: new ( ) ;
787+ for tt in args_iter {
788+ match tt {
789+ TokenTree :: Punct ( punct) if punct. as_char ( ) == ',' => {
790+ sections. push ( std:: mem:: take ( & mut section) ) ;
791+ }
792+ tt => {
793+ section. push ( tt) ;
795794 }
796- range_tokens. extend ( [ token] ) ;
797795 }
798796 }
797+ if !section. is_empty ( ) {
798+ sections. push ( section) ;
799+ }
800+ let mut sections = sections. into_iter ( ) ;
801+ let Some ( range_tokens) = sections. next ( ) else {
802+ return Err ( Error :: new ( default_span, "expected range" ) ) ;
803+ } ;
799804 // 2..=12
800- let range = syn:: parse2 :: < syn:: ExprRange > ( range_tokens) ?;
805+ let range = syn:: parse2 :: < syn:: ExprRange > ( range_tokens. into_iter ( ) . collect ( ) ) ?;
801806 let min = range
802807 . start
803808 . as_ref ( )
@@ -822,32 +827,51 @@ impl TryFrom<TokenStream> for TypleMacro {
822827 if max < min {
823828 return Err ( Error :: new ( range. span ( ) , "range contains no values" ) ) ;
824829 }
825- if !never_tokens. is_empty ( ) {
826- // never=some::Type
827- let mut iter = never_tokens. into_iter ( ) ;
828- let Some ( TokenTree :: Ident ( ident) ) = iter. next ( ) else {
830+ for section in sections {
831+ let mut tokens = section. into_iter ( ) ;
832+ let Some ( TokenTree :: Ident ( ident) ) = tokens. next ( ) else {
829833 return Err ( Error :: new ( default_span, "expected identifier after comma" ) ) ;
830834 } ;
831- if ident != "never" {
832- return Err ( Error :: new (
833- default_span,
834- "expected identifier 'never' after comma" ,
835- ) ) ;
836- }
837- let Some ( TokenTree :: Punct ( punct) ) = iter. next ( ) else {
838- return Err ( Error :: new ( default_span, "expected equals after never" ) ) ;
839- } ;
840- if punct. as_char ( ) != '=' {
841- return Err ( Error :: new ( default_span, "expected equals after never" ) ) ;
835+ if ident == "never" {
836+ let Some ( TokenTree :: Punct ( punct) ) = tokens. next ( ) else {
837+ return Err ( Error :: new ( default_span, "expected equals after never" ) ) ;
838+ } ;
839+ if punct. as_char ( ) != '=' {
840+ return Err ( Error :: new ( default_span, "expected equals after never" ) ) ;
841+ }
842+ never_type = syn:: parse2 :: < Type > ( tokens. collect ( ) ) ?;
843+ } else if ident == "suffixes" {
844+ let Some ( TokenTree :: Punct ( punct) ) = tokens. next ( ) else {
845+ return Err ( Error :: new ( default_span, "expected equals after never" ) ) ;
846+ } ;
847+ if punct. as_char ( ) != '=' {
848+ return Err ( Error :: new ( default_span, "expected equals after never" ) ) ;
849+ }
850+
851+ let expr = syn:: parse2 :: < Expr > ( tokens. collect ( ) ) ?;
852+ let Expr :: Array ( array) = expr else {
853+ return Err ( Error :: new ( expr. span ( ) , "expected array" ) ) ;
854+ } ;
855+ for elem in array. elems {
856+ let Expr :: Lit ( syn:: ExprLit {
857+ lit : syn:: Lit :: Str ( suffix) ,
858+ ..
859+ } ) = elem
860+ else {
861+ return Err ( Error :: new ( elem. span ( ) , "expected string" ) ) ;
862+ } ;
863+ suffixes. push ( suffix. value ( ) ) ;
864+ }
865+ } else {
866+ return Err ( Error :: new ( ident. span ( ) , "unexpected identifier" ) ) ;
842867 }
843- let type_stream = iter. collect ( ) ;
844- never_type = syn:: parse2 :: < Type > ( type_stream) ?;
845868 }
846869 Ok ( TypleMacro {
847870 trait_ident,
848871 min_len : min,
849872 max_len : max,
850873 never_type,
874+ suffixes,
851875 } )
852876 }
853877}
@@ -1005,7 +1029,7 @@ pub fn typle_fold(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
10051029
10061030/// Create variants in an enum.
10071031///
1008- /// In an enum, the `typle_variant` macro allows the creation of variants for each component .
1032+ /// In an enum, the `typle_variant` macro allows the creation of variants for each element .
10091033///
10101034/// A variant is created for each index in the range provided.
10111035///
0 commit comments