Skip to content

Commit 9611130

Browse files
committed
Expand conditional documentation
1 parent 593c5c3 commit 9611130

File tree

5 files changed

+169
-87
lines changed

5 files changed

+169
-87
lines changed

README.md

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,86 @@ provides access to individual components and their position.
4646

4747
```rust
4848
trait HandleStuff {
49-
type Input;
5049
type Output;
5150

52-
fn handle_stuff(&self, input: Self::Input) -> Self::Output;
51+
fn handle_stuff(&self, input: Input) -> Self::Output;
5352
}
5453

5554
struct MultipleHandlers<T> {
5655
handlers: T,
5756
}
5857

59-
#[typle(Tuple for 1..=12)]
60-
impl<T: Tuple, I: Clone> HandleStuff for MultipleHandlers<T>
58+
#[typle(Tuple for 0..=3)]
59+
impl<T> HandleStuff for MultipleHandlers<T>
6160
where
62-
T<_>: HandleStuff<Input = I>,
61+
T: Tuple, // `T`` is a tuple with 0 to 12 components.
62+
T<_>: HandleStuff, // All components implement `HandleStuff`.
6363
{
64-
type Input = I;
6564
type Output = (typle!(i in .. => T<{i}>::Output));
6665

67-
fn handle_stuff(&self, input: Self::Input) -> Self::Output {
68-
(
69-
typle!(i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())),
70-
// Avoid expensive clone for the last handler.
71-
self.handlers[[T::LAST]].handle_stuff(input),
72-
)
66+
// Return a tuple of output from each handler applied to the same input.
67+
fn handle_stuff(&self, input: Input) -> Self::Output {
68+
if typle_const!(T::LEN == 0) {
69+
()
70+
} else {
71+
(
72+
typle!(i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())),
73+
// Avoid expensive clone for the last handler.
74+
self.handlers[[T::LAST]].handle_stuff(input),
75+
)
76+
}
7377
}
7478
}
7579
```
7680

81+
This generates the implementations
82+
```rust
83+
impl HandleStuff for MultipleHandlers<()> {
84+
type Output = ();
85+
fn handle_stuff(&self, input: Input) -> Self::Output {
86+
{ () }
87+
}
88+
}
89+
impl<T0> HandleStuff for MultipleHandlers<(T0,)>
90+
where
91+
T0: HandleStuff,
92+
{
93+
type Output = (<T0>::Output,);
94+
fn handle_stuff(&self, input: Input) -> Self::Output {
95+
{ (self.handlers.0.handle_stuff(input),) }
96+
}
97+
}
98+
impl<T0, T1> HandleStuff for MultipleHandlers<(T0, T1)>
99+
where
100+
T0: HandleStuff,
101+
T1: HandleStuff,
102+
{
103+
type Output = (<T0>::Output, <T1>::Output);
104+
fn handle_stuff(&self, input: Input) -> Self::Output {
105+
{
106+
(
107+
self.handlers.0.handle_stuff(input.clone()),
108+
self.handlers.1.handle_stuff(input),
109+
)
110+
}
111+
}
112+
}
113+
impl<T0, T1, T2> HandleStuff for MultipleHandlers<(T0, T1, T2)>
114+
where
115+
T0: HandleStuff,
116+
T1: HandleStuff,
117+
T2: HandleStuff,
118+
{
119+
type Output = (<T0>::Output, <T1>::Output, <T2>::Output);
120+
fn handle_stuff(&self, input: Input) -> Self::Output {
121+
{
122+
(
123+
self.handlers.0.handle_stuff(input.clone()),
124+
self.handlers.1.handle_stuff(input.clone()),
125+
self.handlers.2.handle_stuff(input),
126+
)
127+
}
128+
}
129+
}
130+
```
77131
See the [crate documentation](https://docs.rs/typle/) for more examples.

src/context/shared.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ impl TypleContext {
343343
if ident1 == &self.typle_macro.ident || self.typles.contains_key(ident1) {
344344
// Tuple::LEN or T::LEN
345345
let Some(typle_len) = self.typle_len else {
346-
abort!(ident2, "LEN not available outside fn or impl");
346+
abort!(ident2, "LEN not defined outside fn or impl");
347347
};
348348
return Ok(Some(Lit::Int(syn::LitInt::new(
349349
&typle_len.to_string(),
@@ -358,10 +358,10 @@ impl TypleContext {
358358
if ident1 == &self.typle_macro.ident || self.typles.contains_key(ident1) {
359359
// Tuple::LAST or T::LAST
360360
let Some(typle_len) = self.typle_len else {
361-
abort!(ident2, "LAST not available outside fn or impl");
361+
abort!(ident2, "LAST not defined outside fn or impl");
362362
};
363363
if typle_len == 0 {
364-
abort!(ident2, "LAST not available when LEN == 0");
364+
abort!(ident2, "LAST not defined when LEN == 0");
365365
}
366366
return Ok(Some(Lit::Int(syn::LitInt::new(
367367
&(typle_len - 1).to_string(),

src/lib.rs

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! # `#[typle(...)]`
12
//! The `typle` attribute macro generates code for multiple tuple lengths. This code:
23
//!
34
//! ```rust
@@ -45,17 +46,19 @@
4546
//! /// Split off the first component of a tuple.
4647
//! #[typle(Tuple for 1..=12)]
4748
//! fn split_first<T: Tuple>(
48-
//! t: T // t: (T<0>, T<1>, T<2>,...)
49-
//! ) -> (T<0>, (T<{1..}>)) // (T<0>, (T<1>, T<2>,...))
49+
//! t: T // t: (T<0>, T<1>, T<2>,...)
50+
//! ) -> (T<0>, (T<{1..}>)) // -> (T<0>, (T<1>, T<2>,...))
5051
//! {
51-
//! (t[[0]], (t[[1..]])) // (t.0, (t.1, t.2,...))
52+
//! (t[[0]], (t[[1..]])) // (t.0, (t.1, t.2,...))
5253
//! }
5354
//!
5455
//! assert_eq!(split_first(('1', 2, 3.0)), ('1', (2, 3.0)));
5556
//! assert_eq!(split_first((2, 3.0)), (2, (3.0,)));
5657
//! assert_eq!(split_first((3.0,)), (3.0, ()));
5758
//! ```
5859
//!
60+
//! # `typle!(...)`
61+
//!
5962
//! The `typle!` macro creates a new sequence of types or expressions. A
6063
//! `typle!` macro can only appear where a comma-separated sequence is valid
6164
//! (e.g. a tuple, array, argument list, or where clause).
@@ -89,6 +92,8 @@
8992
//! assert_eq!(append((1, 2, 3), 4), (1, 2, 3, 4));
9093
//! ```
9194
//!
95+
//! # Constraints
96+
//!
9297
//! Specify constraints on the tuple components using one of the following
9398
//! forms. Except for the first form, these constraints can only appear in the
9499
//! `where` clause.
@@ -150,7 +155,8 @@
150155
//!
151156
//! ```
152157
//! # use typle::typle;
153-
//! #[typle(Tuple for 0..=12)]
158+
//! #[cfg_attr(not(feature = "big-tuple"), typle(Tuple for 0..=12))]
159+
//! #[cfg_attr(feature = "big-tuple", typle(Tuple for 0..=24))]
154160
//! fn even_to_string<T: Tuple>(
155161
//! t: T,
156162
//! ) -> (typle!(i in .. => if i % 2 == 0 { String } else { T<{i}> }))
@@ -165,46 +171,56 @@
165171
//! assert_eq!(even_to_string((0, vec![1], 2, 3)), ("0".to_owned(), vec![1], "2".to_owned(), 3));
166172
//! ```
167173
//!
168-
//! If there is no range in the `typle!` macro, the body is evaluated once. This can be
169-
//! useful in positions where an `if` expression is not permitted.
170-
//!
171174
//! The associated constant `LAST` is always equal to `LEN - 1`. This is convenient for cases where
172-
//! the final component should be treated differently, such as avoiding an additional clone. Using
173-
//! `LAST` for a zero-length tuple causes a compilation error.
175+
//! the final component should be treated differently, such as avoiding an additional clone. `LAST`
176+
//! is not defined when `LEN == 0` and will cause a compilation error.
177+
//!
178+
//! The `typle_const!` macro supports const-if on a boolean typle index expression. const-if allows
179+
//! conditional branches that do not compile, as long as the branch are `false` at compile-time. The
180+
//! following code compiles for `T::LEN == 0` because `T::LAST` appears in an `else` branch that is
181+
//! not compiled when `T::LEN == 0`.
174182
//!
175183
//! ```
176184
//! # use typle::typle;
185+
//! # #[derive(Clone)]
186+
//! # struct Input {}
177187
//! trait HandleStuff {
178-
//! type Input;
179188
//! type Output;
180189
//!
181-
//! fn handle_stuff(&self, input: Self::Input) -> Self::Output;
190+
//! fn handle_stuff(&self, input: Input) -> Self::Output;
182191
//! }
183192
//!
184193
//! struct MultipleHandlers<T> {
185194
//! handlers: T,
186195
//! }
187196
//!
188-
//! #[typle(Tuple for 1..=12)]
189-
//! impl<T: Tuple, I> HandleStuff for MultipleHandlers<T>
197+
//! #[typle(Tuple for 0..=12)]
198+
//! impl<T> HandleStuff for MultipleHandlers<T>
190199
//! where
191-
//! T<_>: HandleStuff<Input = I>,
192-
//! // Only require the Clone bound if there are two or more handlers
193-
//! typle!(=> if T::LEN > 1 { I: Clone }): Tuple::Bounds,
200+
//! T: Tuple,
201+
//! T<_>: HandleStuff,
194202
//! {
195-
//! type Input = I;
196203
//! type Output = (typle!(i in .. => T<{i}>::Output));
197204
//!
198-
//! fn handle_stuff(&self, input: Self::Input) -> Self::Output {
199-
//! (
200-
//! typle!(i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())),
201-
//! // Avoid expensive clone for the last handler.
202-
//! self.handlers[[T::LAST]].handle_stuff(input),
203-
//! )
205+
//! // Return a tuple of output from each handler applied to the same input.
206+
//! fn handle_stuff(&self, input: Input) -> Self::Output {
207+
//! if typle_const!(T::LEN == 0) {
208+
//! ()
209+
//! } else {
210+
//! (
211+
//! typle!(i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())),
212+
//! // Avoid expensive clone for the last handler.
213+
//! self.handlers[[T::LAST]].handle_stuff(input),
214+
//! )
215+
//! }
204216
//! }
205217
//! }
206218
//! ```
207219
//!
220+
//! Without `typle_const!` this code will fail to compile. When there is no compilation error
221+
//! `typle_const!` is not needed. With a constant condition the compiler will compile the false
222+
//! branch but will optimize it out.
223+
//!
208224
//! # Iteration
209225
//!
210226
//! Use the `typle_index!` macro in a `for` loop to iterate over a range bounded
@@ -297,7 +313,7 @@
297313
//! assert_eq!(('f',).wrapping_substring_at(12), "ff");
298314
//! ```
299315
//!
300-
//! # enums
316+
//! # `enum`
301317
//!
302318
//! Applying `typle` to an `enum` implements the `enum` once for the maximum length only.
303319
//!
@@ -359,12 +375,6 @@
359375
//! example `S::<typle_ident!(3)>` becomes the identifier `S3`. This is mainly
360376
//! used to refer to enum variants.
361377
//!
362-
//! The `typle_const!` macro supports const-if on a boolean typle index
363-
//! expression. const-if allows branches that do not compile, as long as they
364-
//! are `false` at compile-time. For example, this code compiles for `T::LEN == 4`
365-
//! even though the variant `TupleSequenceState::S4` does not exist because the
366-
//! branch that refers to it is not compiled when `(i == T::LAST)`.
367-
//!
368378
//! ```rust
369379
//! # use typle::typle;
370380
//! # pub trait Extract {

tests/compile/mod.expanded.rs

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2716,54 +2716,66 @@ pub mod typle_args {
27162716
::core::panicking::panic("not yet implemented")
27172717
}
27182718
}
2719+
struct Input {}
2720+
#[automatically_derived]
2721+
impl ::core::clone::Clone for Input {
2722+
#[inline]
2723+
fn clone(&self) -> Input {
2724+
Input {}
2725+
}
2726+
}
27192727
trait HandleStuff {
2720-
type Input;
27212728
type Output;
2722-
fn handle_stuff(&self, input: Self::Input) -> Self::Output;
2729+
fn handle_stuff(&self, input: Input) -> Self::Output;
27232730
}
27242731
struct MultipleHandlers<T> {
27252732
handlers: T,
27262733
}
2727-
impl<T0, I> HandleStuff for MultipleHandlers<(T0,)>
2734+
impl HandleStuff for MultipleHandlers<()> {
2735+
type Output = ();
2736+
fn handle_stuff(&self, input: Input) -> Self::Output {
2737+
{ () }
2738+
}
2739+
}
2740+
impl<T0> HandleStuff for MultipleHandlers<(T0,)>
27282741
where
2729-
T0: HandleStuff<Input = I>,
2742+
T0: HandleStuff,
27302743
{
2731-
type Input = I;
27322744
type Output = (<T0>::Output,);
2733-
fn handle_stuff(&self, input: Self::Input) -> Self::Output {
2734-
(self.handlers.0.handle_stuff(input),)
2745+
fn handle_stuff(&self, input: Input) -> Self::Output {
2746+
{ (self.handlers.0.handle_stuff(input),) }
27352747
}
27362748
}
2737-
impl<T0, T1, I> HandleStuff for MultipleHandlers<(T0, T1)>
2749+
impl<T0, T1> HandleStuff for MultipleHandlers<(T0, T1)>
27382750
where
2739-
T0: HandleStuff<Input = I>,
2740-
T1: HandleStuff<Input = I>,
2741-
I: Clone,
2751+
T0: HandleStuff,
2752+
T1: HandleStuff,
27422753
{
2743-
type Input = I;
27442754
type Output = (<T0>::Output, <T1>::Output);
2745-
fn handle_stuff(&self, input: Self::Input) -> Self::Output {
2746-
(
2747-
self.handlers.0.handle_stuff(input.clone()),
2748-
self.handlers.1.handle_stuff(input),
2749-
)
2755+
fn handle_stuff(&self, input: Input) -> Self::Output {
2756+
{
2757+
(
2758+
self.handlers.0.handle_stuff(input.clone()),
2759+
self.handlers.1.handle_stuff(input),
2760+
)
2761+
}
27502762
}
27512763
}
2752-
impl<T0, T1, T2, I> HandleStuff for MultipleHandlers<(T0, T1, T2)>
2764+
impl<T0, T1, T2> HandleStuff for MultipleHandlers<(T0, T1, T2)>
27532765
where
2754-
T0: HandleStuff<Input = I>,
2755-
T1: HandleStuff<Input = I>,
2756-
T2: HandleStuff<Input = I>,
2757-
I: Clone,
2766+
T0: HandleStuff,
2767+
T1: HandleStuff,
2768+
T2: HandleStuff,
27582769
{
2759-
type Input = I;
27602770
type Output = (<T0>::Output, <T1>::Output, <T2>::Output);
2761-
fn handle_stuff(&self, input: Self::Input) -> Self::Output {
2762-
(
2763-
self.handlers.0.handle_stuff(input.clone()),
2764-
self.handlers.1.handle_stuff(input.clone()),
2765-
self.handlers.2.handle_stuff(input),
2766-
)
2771+
fn handle_stuff(&self, input: Input) -> Self::Output {
2772+
{
2773+
(
2774+
self.handlers.0.handle_stuff(input.clone()),
2775+
self.handlers.1.handle_stuff(input.clone()),
2776+
self.handlers.2.handle_stuff(input),
2777+
)
2778+
}
27672779
}
27682780
}
27692781
}

0 commit comments

Comments
 (0)