Skip to content

Commit d54fa95

Browse files
committed
Support setting suffixes for identifiers
1 parent 258e9f8 commit d54fa95

File tree

6 files changed

+130
-440
lines changed

6 files changed

+130
-440
lines changed

README.md

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,14 @@ For example, to define a function to zip a pair of tuples into a tuple of pairs:
77

88
```rust
99
#[typle(Tuple for 0..=12)]
10-
pub fn zip<A: Tuple, B: Tuple>(
11-
a: A,
12-
b: B,
13-
) -> (typle! {
10+
pub fn zip<A: Tuple, B: Tuple>(a: A, b: B) -> (typle! {
1411
i in .. => (A<{i}>, B<{i}>)
15-
})
16-
{
12+
}) {
1713
(typle! {
1814
i in .. => (a[[i]], b[[i]])
1915
})
2016
}
17+
2118
```
2219

2320
The types `A` and `B` are generic but are constrained to be tuples. The tuples
@@ -59,46 +56,36 @@ struct MultipleHandlers<T> {
5956
handlers: T,
6057
}
6158

62-
#[typle(Tuple for 0..=3)]
59+
#[typle(Tuple for 1..=3)]
6360
impl<T> HandleStuff for MultipleHandlers<T>
6461
where
65-
T: Tuple, // `T` is a tuple with 0 to 3 components.
66-
T<_>: HandleStuff, // All components implement `HandleStuff`.
62+
T: Tuple, // `T` is a tuple with 1 to 3 components.
63+
T<_>: HandleStuff, // All components implement `HandleStuff`.
6764
{
65+
// Return a tuple of output from each handler applied to the same input.
6866
type Output = (typle! {i in .. => T<{i}>::Output});
6967

70-
// Return a tuple of output from each handler applied to the same input.
7168
fn handle_stuff(&self, input: Input) -> Self::Output {
72-
if typle_const!(T::LEN == 0) {
73-
()
74-
} else {
75-
(
76-
typle! {
77-
i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())
78-
},
79-
// Avoid expensive clone for the last handler.
80-
self.handlers[[T::LAST]].handle_stuff(input),
81-
)
82-
}
69+
(
70+
typle! {
71+
i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())
72+
},
73+
// Avoid expensive clone for the last handler.
74+
self.handlers[[T::LAST]].handle_stuff(input),
75+
)
8376
}
8477
}
8578
```
8679

8780
This generates the implementations
8881
```rust
89-
impl HandleStuff for MultipleHandlers<()> {
90-
type Output = ();
91-
fn handle_stuff(&self, input: Input) -> Self::Output {
92-
{ () }
93-
}
94-
}
9582
impl<T0> HandleStuff for MultipleHandlers<(T0,)>
9683
where
9784
T0: HandleStuff,
9885
{
9986
type Output = (T0::Output,);
10087
fn handle_stuff(&self, input: Input) -> Self::Output {
101-
{ (self.handlers.0.handle_stuff(input),) }
88+
(self.handlers.0.handle_stuff(input),)
10289
}
10390
}
10491
impl<T0, T1> HandleStuff for MultipleHandlers<(T0, T1)>
@@ -108,12 +95,10 @@ where
10895
{
10996
type Output = (T0::Output, T1::Output);
11097
fn handle_stuff(&self, input: Input) -> Self::Output {
111-
{
112-
(
113-
self.handlers.0.handle_stuff(input.clone()),
114-
self.handlers.1.handle_stuff(input),
115-
)
116-
}
98+
(
99+
self.handlers.0.handle_stuff(input.clone()),
100+
self.handlers.1.handle_stuff(input),
101+
)
117102
}
118103
}
119104
impl<T0, T1, T2> HandleStuff for MultipleHandlers<(T0, T1, T2)>
@@ -124,13 +109,11 @@ where
124109
{
125110
type Output = (T0::Output, T1::Output, T2::Output);
126111
fn handle_stuff(&self, input: Input) -> Self::Output {
127-
{
128-
(
129-
self.handlers.0.handle_stuff(input.clone()),
130-
self.handlers.1.handle_stuff(input.clone()),
131-
self.handlers.2.handle_stuff(input),
132-
)
133-
}
112+
(
113+
self.handlers.0.handle_stuff(input.clone()),
114+
self.handlers.1.handle_stuff(input.clone()),
115+
self.handlers.2.handle_stuff(input),
116+
)
134117
}
135118
}
136119
```

src/context.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,12 @@ impl TypleContext {
200200
}
201201
result = Some(Typle::Generic(Rc::new(
202202
(0..self.typle_len.unwrap_or(self.typle_macro.max_len))
203-
.map(|i| format!("{}{}", &type_ident, i))
203+
.map(|i| match self.typle_macro.suffixes.get(i) {
204+
Some(suffix) => {
205+
format!("{}{}", &type_ident, suffix)
206+
}
207+
None => format!("{}{}", &type_ident, i),
208+
})
204209
.collect(),
205210
)));
206211
continue;

src/lib.rs

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@
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;
714714
use proc_macro2::{Ident, TokenStream, TokenTree};
715715
use quote::ToTokens;
716716
use 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

761762
impl 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
///

tests/compile/function.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,13 @@ fn heapify<T: Tuple>(params: T) -> (typle!(i in .. => Box<T<{i}>>)) {
3535
(typle!(i in .. => Box::new(params[[i]])))
3636
}
3737

38-
#[rustfmt::skip]
39-
#[typle(Tuple for 0..=12)]
38+
#[allow(non_camel_case_types)]
39+
#[typle(Tuple for 0..=5, suffixes=["", "01", "x", "three"])]
4040
#[typle_attr_if(Tuple::LEN == 0, allow(unused_assignments))]
4141
pub fn zip<A: Tuple, B: Tuple>(
4242
first: A,
43-
second: B
44-
) -> (typle!(i in ..Tuple::LEN => (A<{i}>, B<{i}>)))
45-
{
43+
second: B,
44+
) -> (typle!(i in ..Tuple::LEN => (A<{i}>, B<{i}>))) {
4645
(typle!(i in ..Tuple::LEN => (first[[i]], second[[i]])))
4746
}
4847

0 commit comments

Comments
 (0)