Skip to main content

tokel_std/
state.rs

1//! Stateful generation [`Transformer`]s.
2//!
3//! # Available Transformers
4//!!
5//! | Transformer   | Argument Type                 | Description |
6//! |---------------|-------------------------------|-------------|
7//! | [`Enumerate`] | [`syn::parse::Nothing`]       | Yields an incrementing integer literal on each invocation (stateful). |
8//!
9//! # Argument Types
10//!
11//! - [`syn::parse::Nothing`]: No argument required.
12//!
13//! # Examples
14//!
15//! * `[< >]:enumerate` ->`0`
16//! * Calling the same transformer again advances its state: `[< >]:enumerate` ->`1`
17//! * Use `enumerate` inside another transformer's argument:
18//!   * `[< b c >]:push_left[[[< >]:enumerate]]` ->`0 b c`
19//!   * `[< b c >]:push_right[[[< >]:enumerate]]` ->`b c 1`
20
21use proc_macro2::{Literal, TokenStream};
22
23use quote::ToTokens;
24use tokel_engine::prelude::{Pass, Registry, Transformer};
25
26/// Yields an incrementing integer literal every time it is called.
27///
28/// # Argument
29///
30/// This takes no argument.
31///
32/// # Examples
33///
34/// * `[< >]:enumerate` ->`0`
35/// * As an argument to another transformer: `[< a b >]:push_left[[[< >]:enumerate]]` ->`0 a b`
36///
37/// # Remarks
38///
39/// The integer is internally an [`u32`], and is incremented with wrapping arithmetic.
40#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub struct Enumerate(u32);
42
43impl Pass for Enumerate {
44    type Argument = syn::parse::Nothing;
45
46    fn through(&mut self, _: TokenStream, _: Self::Argument) -> syn::Result<TokenStream> {
47        let Self(enumerate_counter) = self;
48
49        let current_value;
50        (current_value, *enumerate_counter) =
51            (*enumerate_counter, enumerate_counter.wrapping_add(1));
52
53        Ok(Literal::u32_unsuffixed(current_value).into_token_stream())
54    }
55}
56
57/// Inserts all `state`-related [`Transformer`]s into the specified [`Registry`].
58///
59/// # Errors
60///
61/// This will fail if at least one standard `state`-related [`Transformer`] is already present by-name in the [`Registry`].
62///
63/// On failure, there is no guarantee that other non-colliding transformers have not been registered.
64#[inline]
65pub fn register(registry: &mut Registry) -> Result<(), Box<dyn Transformer>> {
66    registry
67        .try_insert("enumerate", Enumerate::default())
68        .map_err(Box::new)
69        .map_err(|target_value| target_value as Box<dyn Transformer>)?;
70
71    Ok(())
72}