Skip to main content

tokel_std/
iter.rs

1//! Iteration-related Tokel [`Transformer`]s.
2//!
3//! # Available Transformers
4//!
5//! | Transformer         | Argument Type         | Description |
6//! |---------------------|----------------------|-------------|
7//! | [`Reverse`]         | [`syn::parse::Nothing`]     | Reverses the sequence of token trees. |
8//! | [`Intersperse`]     | [`TokenTree`]        | Inserts a token-tree between each token-tree in the input. |
9//! | [`PushLeft`]        | [`TokenStream`]      | Prepends a token stream to the input. |
10//! | [`PushRight`]       | [`TokenStream`]      | Appends a token stream to the input. |
11//! | [`PopLeft`]         | [`syn::parse::Nothing`]     | Removes the first token tree from the stream. |
12//! | [`PopRight`]        | [`syn::parse::Nothing`]     | Removes the last token tree from the stream. |
13//! | [`Take`]            | [`syn::LitInt`]      | Keeps only the first `N` tokens from the stream. |
14//! | [`Skip`]            | [`syn::LitInt`]      | Discards the first `N` tokens from the stream. |
15//! | [`Repeat`]          | [`syn::LitInt`]      | Duplicates the input stream `N` times. |
16//! | [`Count`]           | [`syn::parse::Nothing`]     | Emits the number of token trees present in the stream. |
17//! | [`Sequence`]        | [`SequenceRange`]    | Generates a sequence of integers based on a provided range. |
18//!
19//! # Argument Types
20//!
21//! - [`syn::parse::Nothing`]: No argument required.
22//! - [`TokenTree`]: A single token tree (e.g., a punctuation, identifier, etc.).
23//! - [`TokenStream`]: A sequence of token trees.
24//! - [`syn::LitInt`]: An integer literal (e.g., `[[ 3 ]]`).
25//! - [`SequenceRange`]: A Rust range literal (e.g., `[[ 1..=3 ]]`).
26//!
27//! # Examples
28//!
29//! - `[< a b c >]:reverse` ->`c b a`
30//! - `[< a b c >]:intersperse[[,]]` ->`a , b , c`
31//! - `[< b c >]:push_left[[a]]` ->`a b c`
32//! - `[< a b c >]:pop_right` ->`a b`
33//! - `[< a b c >]:take[[2]]` ->`a b`
34//! - `[< a b c >]:skip[[1]]` ->`b c`
35//! - `[< a b >]:repeat[[3]]` ->`a b a b a b`
36//! - `[< a b c >]:count` ->`3`
37//! - `[< >]:sequence[[ 1..=3 ]]` ->`1 2 3`
38//!
39//! * Transformers can be nested or composed by evaluating other transformers inside arguments:
40//!
41//! - `[< a b c >]:intersperse[[[< x y >]:reverse]]` ->`a y x b y x c`
42//! - `[< a b c >]:push_left[[[< x y >]:reverse]]` ->`y x a b c`
43//! - `[< a b c >]:push_right[[[< d e >]:take[[1]]]]` ->`a b c d`
44//! - `[< 1 2 3 >]:take[[[< 2 1 >]:reverse:take[[1]]]]` ->`1 2`
45//! - `[< a b c >]:repeat[[[< 2 1 >]:count]]` ->`a b c a b c`
46//! - `[< >]:sequence[[[< 1 4 >]:reverse:take[[1]]..4]]` ->`3 4 5 6`
47
48use std::{
49    iter,
50    ops::{Range, RangeInclusive},
51};
52
53use proc_macro2::{Literal, TokenStream, TokenTree};
54
55use quote::ToTokens;
56
57use syn::{
58    Token,
59    parse::{Parse, ParseStream},
60};
61
62use tokel_engine::prelude::{Pass, Registry, Transformer};
63
64/// Reverses the sequence of token trees in the stream.
65///
66/// # Arguments
67///
68/// This does not take any argument.
69///
70/// # Example
71///
72/// `[< a b c >]:reverse` ->`c b a`
73#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
74pub struct Reverse;
75
76impl Pass for Reverse {
77    type Argument = syn::parse::Nothing;
78
79    fn through(&mut self, input: TokenStream, _: Self::Argument) -> syn::Result<TokenStream> {
80        Ok(input
81            .into_iter()
82            .collect::<Vec<TokenTree>>()
83            .into_iter()
84            .rev()
85            .collect::<TokenStream>())
86    }
87}
88
89/// Inserts the provided token-tree in between each token-tree in the input.
90///
91/// # Arguments
92///
93/// This takes a singular [`TokenTree`] as argument.
94///
95/// # Example
96///
97/// `[< a b c >]:intersperse[[,]]` ->`a , b , c`
98///
99/// *NOTE*: Most tokens will be preserved *verbatim*, including any span-related information.
100#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
101pub struct Intersperse;
102
103impl Pass for Intersperse {
104    type Argument = TokenTree;
105
106    fn through(
107        &mut self,
108        input: TokenStream,
109        intersperse_tree: Self::Argument,
110    ) -> syn::Result<TokenStream> {
111        let mut target_output = TokenStream::new();
112
113        let mut target_iter = input.into_iter().into_iter().peekable();
114
115        while let Some(target_tree) = target_iter.next() {
116            let target_list = [
117                Some(target_tree),
118                if let Some(..) = target_iter.peek() {
119                    let intersperse_tree = intersperse_tree.clone();
120
121                    Some(intersperse_tree)
122                } else {
123                    None
124                },
125            ];
126
127            target_output.extend(target_list.into_iter().flatten());
128        }
129
130        Ok(target_output)
131    }
132}
133
134/// Pushes the provided token stream to the start (*left*) of the input token stream.
135///
136/// # Arguments
137///
138/// This takes a singular [`TokenStream`] as argument.
139///
140/// # Example
141///
142/// `[< b c >]:push_left[[a]]` ->`a b c`
143#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
144pub struct PushLeft;
145
146impl Pass for PushLeft {
147    type Argument = TokenStream;
148
149    fn through(&mut self, input: TokenStream, left: Self::Argument) -> syn::Result<TokenStream> {
150        Ok(iter::chain(left, input).collect::<TokenStream>())
151    }
152}
153
154/// Removes the last token tree from the stream (useful for trailing commas or other garbage).
155///
156/// # Arguments
157///
158/// This does not take any argument.
159///
160/// # Example
161///
162/// `[< a b c >]:pop_right` ->`a b`
163#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
164pub struct PopRight;
165
166impl Pass for PopRight {
167    type Argument = syn::parse::Nothing;
168
169    fn through(&mut self, input: TokenStream, _: Self::Argument) -> syn::Result<TokenStream> {
170        let mut target_list = input.into_iter().collect::<Vec<TokenTree>>();
171
172        let _ = target_list.pop();
173
174        Ok(target_list.into_iter().collect::<TokenStream>())
175    }
176}
177
178/// Appends the provided token stream to the end (*right*) of the input token stream.
179///
180/// # Arguments
181///
182/// This takes a singular [`TokenStream`] as argument.
183///
184/// # Example
185///
186/// `[< a b >]:push_right[[c]]` ->`a b c`
187#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
188pub struct PushRight;
189
190impl Pass for PushRight {
191    type Argument = TokenStream;
192
193    fn through(&mut self, input: TokenStream, right: Self::Argument) -> syn::Result<TokenStream> {
194        Ok(iter::chain(input, right).collect::<TokenStream>())
195    }
196}
197
198/// Removes the first token tree from the stream.
199///
200/// # Arguments
201///
202/// This does not take any argument.
203///
204/// # Example
205///
206/// * `[< a b c >]:pop_left` ->`b c`
207#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
208pub struct PopLeft;
209
210impl Pass for PopLeft {
211    type Argument = syn::parse::Nothing;
212
213    fn through(&mut self, input: TokenStream, _: Self::Argument) -> syn::Result<TokenStream> {
214        Ok(input.into_iter().skip(1).collect::<TokenStream>())
215    }
216}
217
218/// Keeps only the first `N` tokens from the stream.
219///
220/// # Arguments
221///
222/// This takes a single [`syn::LitInt`] as argument (e.g., `[[ 3 ]]`).
223///
224/// # Example
225///
226/// * `[< a b c d >]:take[[2]]` ->`a b`
227#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
228pub struct Take;
229
230impl Pass for Take {
231    type Argument = syn::LitInt;
232
233    fn through(&mut self, input: TokenStream, count: Self::Argument) -> syn::Result<TokenStream> {
234        let take_count = count.base10_parse()?;
235
236        Ok(input.into_iter().take(take_count).collect())
237    }
238}
239
240/// Discards the first `N` tokens from the stream.
241///
242/// # Arguments
243///
244/// This takes a single [`syn::LitInt`] as argument (e.g., `[[ 2 ]]`).
245///
246/// # Example
247///
248/// `[< a b c d >]:skip[[2]]` ->`c d`
249#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
250pub struct Skip;
251
252impl Pass for Skip {
253    type Argument = syn::LitInt;
254
255    fn through(&mut self, input: TokenStream, count: Self::Argument) -> syn::Result<TokenStream> {
256        let skip_count = count.base10_parse()?;
257
258        Ok(input.into_iter().skip(skip_count).collect())
259    }
260}
261
262/// Duplicates the input stream `N` times.
263///
264/// # Arguments
265///
266/// This takes a single [`syn::LitInt`] as argument (e.g., `[[ 3 ]]`).
267///
268/// # Example
269///
270/// * `[< a b >]:repeat[[3]]` ->`a b a b a b`
271#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
272pub struct Repeat;
273
274impl Pass for Repeat {
275    type Argument = syn::LitInt;
276
277    fn through(
278        &mut self,
279        input: TokenStream,
280        target_count: Self::Argument,
281    ) -> syn::Result<TokenStream> {
282        let target_list = input.into_iter().collect::<Vec<TokenTree>>();
283
284        let take_count = target_list.len() * target_count.base10_parse::<usize>()?;
285
286        Ok(target_list
287            .iter()
288            .cycle()
289            .take(take_count)
290            .cloned()
291            .collect::<TokenStream>())
292    }
293}
294
295/// Emits the number of token trees present in the stream.
296///
297/// # Arguments
298///
299/// This does not take any argument.
300///
301/// # Example
302///
303/// * `[< a b c >]:count` ->`3`
304#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
305pub struct Count;
306
307impl Pass for Count {
308    type Argument = syn::parse::Nothing;
309
310    fn through(&mut self, input: TokenStream, _: Self::Argument) -> syn::Result<TokenStream> {
311        Ok(Literal::usize_unsuffixed(input.into_iter().count()).to_token_stream())
312    }
313}
314
315/// The range argument of a [`Sequence`] pass.
316#[derive(Debug, Clone, PartialEq, Eq, Hash)]
317pub enum SequenceRange {
318    /// An inclusive range.
319    Inclusive(RangeInclusive<i32>),
320
321    /// A non-inclusive range.
322    NonInclusive(Range<i32>),
323}
324
325impl Parse for SequenceRange {
326    fn parse(input: ParseStream) -> syn::Result<Self> {
327        let start: syn::LitInt = input.parse()?;
328
329        if input.peek(Token![..=]) {
330            let _: Token![..=] = input.parse()?;
331
332            let end: syn::LitInt = input.parse()?;
333
334            Ok(Self::Inclusive(start.base10_parse()?..=end.base10_parse()?))
335        } else {
336            let _: Token![..] = input.parse()?;
337
338            let end: syn::LitInt = input.parse()?;
339
340            Ok(Self::NonInclusive(
341                start.base10_parse()?..end.base10_parse()?,
342            ))
343        }
344    }
345}
346
347/// Generates a sequence of integers based on a provided range.
348///
349/// The input stream is ignored.
350///
351/// # Arguments
352///
353/// This takes a single [`SequenceRange`] as argument (e.g., `[[ 0..4 ]]` or `[[ 1..=3 ]]`).
354///
355/// # Example
356///
357/// * `[< >]:sequence[[ 1..4 ]]` ->`1 2 3`
358/// * `[< >]:sequence[[ 1..=3 ]]` ->`1 2 3`
359#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
360pub struct Sequence;
361
362impl Pass for Sequence {
363    type Argument = SequenceRange;
364
365    fn through(
366        &mut self,
367        input: TokenStream,
368        target_range: Self::Argument,
369    ) -> syn::Result<TokenStream> {
370        let _: syn::parse::Nothing = syn::parse2(input)?;
371
372        fn fold_fn(mut target_output: TokenStream, target_literal: Literal) -> TokenStream {
373            target_output.extend(target_literal.into_token_stream());
374
375            target_output
376        }
377
378        Ok(match target_range {
379            SequenceRange::Inclusive(range_inclusive) => range_inclusive
380                .into_iter()
381                .map(Literal::i32_unsuffixed)
382                .fold(TokenStream::new(), fold_fn),
383            SequenceRange::NonInclusive(range) => range
384                .into_iter()
385                .map(Literal::i32_unsuffixed)
386                .fold(TokenStream::new(), fold_fn),
387        })
388    }
389}
390
391/// Inserts all `iter`-related [`Transformer`]s into the specified [`Registry`].
392///
393/// # Errors
394///
395/// This will fail if at least one standard `iter`-related [`Transformer`] is already present by-name in the [`Registry`].
396///
397/// On failure, there is no guarantee that other non-colliding transformers have not been registered.
398#[inline]
399pub fn register(registry: &mut Registry) -> Result<(), Box<dyn Transformer>> {
400    registry
401        .try_insert("reverse", Reverse)
402        .map_err(Box::new)
403        .map_err(|t| t as Box<dyn Transformer>)?;
404
405    registry
406        .try_insert("intersperse", Intersperse)
407        .map_err(Box::new)
408        .map_err(|t| t as Box<dyn Transformer>)?;
409
410    registry
411        .try_insert("push_left", PushLeft)
412        .map_err(Box::new)
413        .map_err(|t| t as Box<dyn Transformer>)?;
414
415    registry
416        .try_insert("push_right", PushRight)
417        .map_err(Box::new)
418        .map_err(|t| t as Box<dyn Transformer>)?;
419
420    registry
421        .try_insert("pop_left", PopLeft)
422        .map_err(Box::new)
423        .map_err(|t| t as Box<dyn Transformer>)?;
424
425    registry
426        .try_insert("pop_right", PopRight)
427        .map_err(Box::new)
428        .map_err(|t| t as Box<dyn Transformer>)?;
429
430    registry
431        .try_insert("take", Take)
432        .map_err(Box::new)
433        .map_err(|t| t as Box<dyn Transformer>)?;
434
435    registry
436        .try_insert("skip", Skip)
437        .map_err(Box::new)
438        .map_err(|t| t as Box<dyn Transformer>)?;
439
440    registry
441        .try_insert("repeat", Repeat)
442        .map_err(Box::new)
443        .map_err(|t| t as Box<dyn Transformer>)?;
444
445    registry
446        .try_insert("count", Count)
447        .map_err(Box::new)
448        .map_err(|t| t as Box<dyn Transformer>)?;
449
450    registry
451        .try_insert("sequence", Sequence)
452        .map_err(Box::new)
453        .map_err(|t| t as Box<dyn Transformer>)?;
454
455    Ok(())
456}