proc_quote/
repeat.rs

1use super::ToTokens;
2use std::borrow::Borrow;
3use std::slice;
4
5/// Defines the behavior of types that can be interpolated inside repeating patterns (`#(...)*`).
6///
7/// ### Which types *do* `Repeat`
8///   - [`Iterator<T>`] consumes the iterator, iterating through every element.
9///   - <a href="https://doc.rust-lang.org/std/borrow/trait.Borrow.html">`Borrow<[T]>`</a>
10/// (includes [`Vec`], [`array`], and [`slice`]) iterates with the [`slice::iter`] method,
11/// thus not consuming the original data.
12///   - [`ToTokens`], interpolates the variable in every iteration.
13///
14/// ### Which types *do NOT* `Repeat`
15///   - [`IntoIterator`], to avoid ambiguity (Ex. "Which behavior would have been used for [`Vec`],
16/// which implements both [`IntoIterator`] and <a href="https://doc.rust-lang.org/std/borrow/trait.Borrow.html">
17/// `Borrow<[T]>`</a>?"; "Which behavior would have been used for [`TokenStream`], which implements both
18/// [`IntoIterator`] and [`ToTokens`]?"). To use the iterator, you may call [`IntoIterator::into_iter`]
19/// explicitly.
20///   - Ambiguous types that implement at least two of the `Repeat` traits. In the very unlikely case
21/// this happens, disambiguate the type by wrapping it under some structure that only implements the
22/// trait you desire to use.
23///
24/// [`Iterator<T>`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
25/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
26/// [`array`]: https://doc.rust-lang.org/std/primitive.array.html
27/// [`slice`]: https://doc.rust-lang.org/std/slice/index.html
28/// [`slice::iter`]: https://doc.rust-lang.org/std/primitive.slice.html#method.iter
29/// [`ToTokens`]: https://docs.rs/proc-quote/0/proc_quote/trait.ToTokens.html
30/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
31/// [`IntoIterator::into_iter`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html#tymethod.into_iter
32pub trait Repeat<T: Iterator>: private::Sealed<T> {
33    // Long name to avoid collision
34    // TODO(Blocked on #7): rename to `as_repeat` once collision is solved
35    #[allow(non_snake_case)]
36    #[doc(hidden)]
37    fn __proc_quote__as_repeat(self) -> T;
38}
39
40mod private {
41    use super::*;
42    pub trait Sealed<T> {}
43
44    impl<T, I: Iterator<Item = T>> Sealed<I> for I {}
45    impl<'a, T: 'a, S: Borrow<[T]>> Sealed<slice::Iter<'a, T>> for &'a S {}
46    impl<'a, T: ToTokens + 'a> Sealed<ToTokensRepeat<'a, T>> for &'a T {}
47}
48
49/// Types that implement `Iterator` may be used in repeating patterns.
50///
51/// They, will be consumed, so they can only be used in one pattern.
52impl<T, I: Iterator<Item = T>> Repeat<I> for I {
53    fn __proc_quote__as_repeat(self) -> I {
54        self
55    }
56}
57
58/// Types that implement `Borrow<[T]>` may be used in repeating patterns.
59///
60/// This includes, but is not necessarily limited to, `Vec`, `array` and `slice`.
61///
62/// They, will not be consumed. Instead `slice::iter` will be implicitly called.
63impl<'a, T: 'a, S: Borrow<[T]>> Repeat<slice::Iter<'a, T>> for &'a S {
64    fn __proc_quote__as_repeat(self) -> slice::Iter<'a, T> {
65        (*self).borrow().iter()
66    }
67}
68
69/// Types that implement `ToTokens` may be used in repeating patterns.
70///
71/// The variable will be interpolated in every iteration.
72impl<'a, T: ToTokens + 'a> Repeat<ToTokensRepeat<'a, T>> for &'a T {
73    fn __proc_quote__as_repeat(self) -> ToTokensRepeat<'a, T> {
74        ToTokensRepeat(self)
75    }
76}
77
78/// Struct that wraps a reference to `ToTokens` in order to use it in repeating patterns.
79pub struct ToTokensRepeat<'a, T: ToTokens + 'a>(&'a T);
80impl<'a, T: ToTokens + 'a> Iterator for ToTokensRepeat<'a, T> {
81    type Item = &'a T;
82    fn next(&mut self) -> Option<Self::Item> {
83        Some(self.0)
84    }
85}