From 2c5b50f1def1968517de8cbede3b9c0eee35d4ed Mon Sep 17 00:00:00 2001 From: Zhixing Zhang <me@neoto.xin> Date: Sun, 25 May 2025 03:20:47 -0700 Subject: [PATCH 1/2] Support lifetime params --- src/lib.rs | 81 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 471601b..1cab237 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,20 +6,43 @@ use proc_macro::TokenStream; use proc_macro2::{Literal, Span as Span2, TokenStream as TokenStream2}; -use quote::{format_ident, quote}; +use quote::{format_ident, quote, ToTokens}; use syn::{ parse::{Parse, ParseStream}, parse_macro_input, spanned::Spanned as _, token::Comma, - Attribute, Error, Ident, LitInt, LitStr, Result, + Attribute, Error, Ident, Lifetime, LitInt, LitStr, Result, }; struct AllTuples { fake_variadic: bool, macro_ident: Ident, start: usize, end: usize, - idents: Vec<Ident>, + idents: Vec<AllTuplesParam>, +} + +#[derive(Clone)] +enum AllTuplesParam { + Ident(Ident), + Lifetime(Lifetime), +} +impl Parse for AllTuplesParam { + fn parse(input: ParseStream) -> Result<Self> { + if let Ok(lifetime) = input.parse::<Lifetime>() { + return Ok(Self::Lifetime(lifetime)); + } else { + return Ok(Self::Ident(input.parse()?)); + } + } +} +impl ToTokens for AllTuplesParam { + fn to_tokens(&self, tokens: &mut TokenStream2) { + match self { + AllTuplesParam::Ident(ident) => ident.to_tokens(tokens), + AllTuplesParam::Lifetime(lifetime) => lifetime.to_tokens(tokens), + } + } } impl Parse for AllTuples { @@ -31,9 +54,9 @@ impl Parse for AllTuples { input.parse::<Comma>()?; let end = input.parse::<LitInt>()?.base10_parse()?; input.parse::<Comma>()?; - let mut idents = vec![input.parse::<Ident>()?]; + let mut idents = vec![input.parse::<AllTuplesParam>()?]; while input.parse::<Comma>().is_ok() { - idents.push(input.parse::<Ident>()?); + idents.push(input.parse::<AllTuplesParam>()?); } if start > 1 && fake_variadic { @@ -167,10 +190,15 @@ pub fn all_tuples(input: TokenStream) -> TokenStream { let len = 1 + input.end - input.start; let ident_tuples = (0..=len) .map(|i| { - let idents = input - .idents - .iter() - .map(|ident| format_ident!("{}{}", ident, i)); + let idents = input.idents.iter().map(|ident| match ident { + AllTuplesParam::Ident(ident) => { + AllTuplesParam::Ident(format_ident!("{}{}", ident, i)) + } + AllTuplesParam::Lifetime(lifetime) => AllTuplesParam::Lifetime(Lifetime { + apostrophe: lifetime.apostrophe, + ident: format_ident!("{}{}", lifetime.ident, i), + }), + }); to_ident_tuple(idents, input.idents.len()) }) .collect::<Vec<_>>(); @@ -242,11 +270,16 @@ pub fn all_tuples_enumerated(input: TokenStream) -> TokenStream { let len = 1 + input.end - input.start; let ident_tuples = (0..=len) .map(|i| { - let idents = input - .idents - .iter() - .map(|ident| format_ident!("{}{}", ident, i)); - to_ident_tuple_enumerated(idents, input.idents.len()) + let idents = input.idents.iter().map(|ident| match ident { + AllTuplesParam::Ident(ident) => { + AllTuplesParam::Ident(format_ident!("{}{}", ident, i)) + } + AllTuplesParam::Lifetime(lifetime) => AllTuplesParam::Lifetime(Lifetime { + apostrophe: lifetime.apostrophe, + ident: format_ident!("{}{}", lifetime.ident, i), + }), + }); + to_ident_tuple_enumerated(idents, i) }) .collect::<Vec<_>>(); let macro_ident = &input.macro_ident; @@ -384,10 +417,15 @@ pub fn all_tuples_with_size(input: TokenStream) -> TokenStream { let len = 1 + input.end - input.start; let ident_tuples = (0..=len) .map(|i| { - let idents = input - .idents - .iter() - .map(|ident| format_ident!("{}{}", ident, i)); + let idents = input.idents.iter().map(|ident| match ident { + AllTuplesParam::Ident(ident) => { + AllTuplesParam::Ident(format_ident!("{}{}", ident, i)) + } + AllTuplesParam::Lifetime(lifetime) => AllTuplesParam::Lifetime(Lifetime { + apostrophe: lifetime.apostrophe, + ident: format_ident!("{}{}", lifetime.ident, i), + }), + }); to_ident_tuple(idents, input.idents.len()) }) .collect::<Vec<_>>(); @@ -464,7 +502,7 @@ fn choose_ident_tuples_enumerated( } } -fn to_ident_tuple(idents: impl Iterator<Item = Ident>, len: usize) -> TokenStream2 { +fn to_ident_tuple(idents: impl Iterator<Item = AllTuplesParam>, len: usize) -> TokenStream2 { if len < 2 { quote! { #(#idents)* } } else { @@ -473,7 +511,10 @@ fn to_ident_tuple(idents: impl Iterator<Item = Ident>, len: usize) -> TokenStrea } /// Like `to_ident_tuple`, but it enumerates the identifiers -fn to_ident_tuple_enumerated(idents: impl Iterator<Item = Ident>, idx: usize) -> TokenStream2 { +fn to_ident_tuple_enumerated( + idents: impl Iterator<Item = AllTuplesParam>, + idx: usize, +) -> TokenStream2 { let idx = Literal::usize_unsuffixed(idx); quote! { (#idx, #(#idents),*) } } From a8ad82a77bee227fea7cf3b3e70623452bae7eae Mon Sep 17 00:00:00 2001 From: Zhixing Zhang <me@neoto.xin> Date: Sun, 25 May 2025 10:08:01 -0700 Subject: [PATCH 2/2] clippy --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1cab237..aa33654 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,9 +30,9 @@ enum AllTuplesParam { impl Parse for AllTuplesParam { fn parse(input: ParseStream) -> Result<Self> { if let Ok(lifetime) = input.parse::<Lifetime>() { - return Ok(Self::Lifetime(lifetime)); + Ok(Self::Lifetime(lifetime)) } else { - return Ok(Self::Ident(input.parse()?)); + Ok(Self::Ident(input.parse()?)) } } }