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()?))
}
}
}