quote/
runtime.rs

1use crate::{IdentFragment, ToTokens, TokenStreamExt};
2use std::fmt;
3use std::ops::BitOr;
4
5pub use proc_macro2::*;
6
7pub struct HasIterator; // True
8pub struct ThereIsNoIteratorInRepetition; // False
9
10impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
11    type Output = ThereIsNoIteratorInRepetition;
12    fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
13        ThereIsNoIteratorInRepetition
14    }
15}
16
17impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
18    type Output = HasIterator;
19    fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
20        HasIterator
21    }
22}
23
24impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
25    type Output = HasIterator;
26    fn bitor(self, _rhs: HasIterator) -> HasIterator {
27        HasIterator
28    }
29}
30
31impl BitOr<HasIterator> for HasIterator {
32    type Output = HasIterator;
33    fn bitor(self, _rhs: HasIterator) -> HasIterator {
34        HasIterator
35    }
36}
37
38/// Extension traits used by the implementation of `quote!`. These are defined
39/// in separate traits, rather than as a single trait due to ambiguity issues.
40///
41/// These traits expose a `quote_into_iter` method which should allow calling
42/// whichever impl happens to be applicable. Calling that method repeatedly on
43/// the returned value should be idempotent.
44pub mod ext {
45    use super::RepInterp;
46    use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
47    use crate::ToTokens;
48    use std::collections::btree_set::{self, BTreeSet};
49    use std::slice;
50
51    /// Extension trait providing the `quote_into_iter` method on iterators.
52    pub trait RepIteratorExt: Iterator + Sized {
53        fn quote_into_iter(self) -> (Self, HasIter) {
54            (self, HasIter)
55        }
56    }
57
58    impl<T: Iterator> RepIteratorExt for T {}
59
60    /// Extension trait providing the `quote_into_iter` method for
61    /// non-iterable types. These types interpolate the same value in each
62    /// iteration of the repetition.
63    pub trait RepToTokensExt {
64        /// Pretend to be an iterator for the purposes of `quote_into_iter`.
65        /// This allows repeated calls to `quote_into_iter` to continue
66        /// correctly returning DoesNotHaveIter.
67        fn next(&self) -> Option<&Self> {
68            Some(self)
69        }
70
71        fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) {
72            (self, DoesNotHaveIter)
73        }
74    }
75
76    impl<T: ToTokens + ?Sized> RepToTokensExt for T {}
77
78    /// Extension trait providing the `quote_into_iter` method for types that
79    /// can be referenced as an iterator.
80    pub trait RepAsIteratorExt<'q> {
81        type Iter: Iterator;
82
83        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
84    }
85
86    impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a T {
87        type Iter = T::Iter;
88
89        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
90            <T as RepAsIteratorExt>::quote_into_iter(*self)
91        }
92    }
93
94    impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a mut T {
95        type Iter = T::Iter;
96
97        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
98            <T as RepAsIteratorExt>::quote_into_iter(*self)
99        }
100    }
101
102    impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
103        type Iter = slice::Iter<'q, T>;
104
105        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
106            (self.iter(), HasIter)
107        }
108    }
109
110    impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
111        type Iter = slice::Iter<'q, T>;
112
113        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
114            (self.iter(), HasIter)
115        }
116    }
117
118    impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
119        type Iter = btree_set::Iter<'q, T>;
120
121        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
122            (self.iter(), HasIter)
123        }
124    }
125
126    macro_rules! array_rep_slice {
127        ($($l:tt)*) => {
128            $(
129                impl<'q, T: 'q> RepAsIteratorExt<'q> for [T; $l] {
130                    type Iter = slice::Iter<'q, T>;
131
132                    fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
133                        (self.iter(), HasIter)
134                    }
135                }
136            )*
137        }
138    }
139
140    array_rep_slice!(
141        0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
142        17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
143    );
144
145    impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
146        type Iter = T::Iter;
147
148        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
149            self.0.quote_into_iter()
150        }
151    }
152}
153
154// Helper type used within interpolations to allow for repeated binding names.
155// Implements the relevant traits, and exports a dummy `next()` method.
156#[derive(Copy, Clone)]
157pub struct RepInterp<T>(pub T);
158
159impl<T> RepInterp<T> {
160    // This method is intended to look like `Iterator::next`, and is called when
161    // a name is bound multiple times, as the previous binding will shadow the
162    // original `Iterator` object. This allows us to avoid advancing the
163    // iterator multiple times per iteration.
164    pub fn next(self) -> Option<T> {
165        Some(self.0)
166    }
167}
168
169impl<T: Iterator> Iterator for RepInterp<T> {
170    type Item = T::Item;
171
172    fn next(&mut self) -> Option<Self::Item> {
173        self.0.next()
174    }
175}
176
177impl<T: ToTokens> ToTokens for RepInterp<T> {
178    fn to_tokens(&self, tokens: &mut TokenStream) {
179        self.0.to_tokens(tokens);
180    }
181}
182
183fn is_ident_start(c: u8) -> bool {
184    (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_'
185}
186
187fn is_ident_continue(c: u8) -> bool {
188    (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_' || (b'0' <= c && c <= b'9')
189}
190
191fn is_ident(token: &str) -> bool {
192    let mut iter = token.bytes();
193    let first_ok = iter.next().map(is_ident_start).unwrap_or(false);
194
195    first_ok && iter.all(is_ident_continue)
196}
197
198pub fn parse(tokens: &mut TokenStream, span: Span, s: &str) {
199    if is_ident(s) {
200        // Fast path, since idents are the most common token.
201        tokens.append(Ident::new(s, span));
202    } else {
203        let s: TokenStream = s.parse().expect("invalid token stream");
204        tokens.extend(s.into_iter().map(|mut t| {
205            t.set_span(span);
206            t
207        }));
208    }
209}
210
211macro_rules! push_punct {
212    ($name:ident $char1:tt) => {
213        pub fn $name(tokens: &mut TokenStream, span: Span) {
214            let mut punct = Punct::new($char1, Spacing::Alone);
215            punct.set_span(span);
216            tokens.append(punct);
217        }
218    };
219    ($name:ident $char1:tt $char2:tt) => {
220        pub fn $name(tokens: &mut TokenStream, span: Span) {
221            let mut punct = Punct::new($char1, Spacing::Joint);
222            punct.set_span(span);
223            tokens.append(punct);
224            let mut punct = Punct::new($char2, Spacing::Alone);
225            punct.set_span(span);
226            tokens.append(punct);
227        }
228    };
229    ($name:ident $char1:tt $char2:tt $char3:tt) => {
230        pub fn $name(tokens: &mut TokenStream, span: Span) {
231            let mut punct = Punct::new($char1, Spacing::Joint);
232            punct.set_span(span);
233            tokens.append(punct);
234            let mut punct = Punct::new($char2, Spacing::Joint);
235            punct.set_span(span);
236            tokens.append(punct);
237            let mut punct = Punct::new($char3, Spacing::Alone);
238            punct.set_span(span);
239            tokens.append(punct);
240        }
241    };
242}
243
244push_punct!(push_add '+');
245push_punct!(push_add_eq '+' '=');
246push_punct!(push_and '&');
247push_punct!(push_and_and '&' '&');
248push_punct!(push_and_eq '&' '=');
249push_punct!(push_at '@');
250push_punct!(push_bang '!');
251push_punct!(push_caret '^');
252push_punct!(push_caret_eq '^' '=');
253push_punct!(push_colon ':');
254push_punct!(push_colon2 ':' ':');
255push_punct!(push_comma ',');
256push_punct!(push_div '/');
257push_punct!(push_div_eq '/' '=');
258push_punct!(push_dot '.');
259push_punct!(push_dot2 '.' '.');
260push_punct!(push_dot3 '.' '.' '.');
261push_punct!(push_dot_dot_eq '.' '.' '=');
262push_punct!(push_eq '=');
263push_punct!(push_eq_eq '=' '=');
264push_punct!(push_ge '>' '=');
265push_punct!(push_gt '>');
266push_punct!(push_le '<' '=');
267push_punct!(push_lt '<');
268push_punct!(push_mul_eq '*' '=');
269push_punct!(push_ne '!' '=');
270push_punct!(push_or '|');
271push_punct!(push_or_eq '|' '=');
272push_punct!(push_or_or '|' '|');
273push_punct!(push_pound '#');
274push_punct!(push_question '?');
275push_punct!(push_rarrow '-' '>');
276push_punct!(push_larrow '<' '-');
277push_punct!(push_rem '%');
278push_punct!(push_rem_eq '%' '=');
279push_punct!(push_fat_arrow '=' '>');
280push_punct!(push_semi ';');
281push_punct!(push_shl '<' '<');
282push_punct!(push_shl_eq '<' '<' '=');
283push_punct!(push_shr '>' '>');
284push_punct!(push_shr_eq '>' '>' '=');
285push_punct!(push_star '*');
286push_punct!(push_sub '-');
287push_punct!(push_sub_eq '-' '=');
288
289// Helper method for constructing identifiers from the `format_ident!` macro,
290// handling `r#` prefixes.
291//
292// Directly parsing the input string may produce a valid identifier,
293// although the input string was invalid, due to ignored characters such as
294// whitespace and comments. Instead, we always create a non-raw identifier
295// to validate that the string is OK, and only parse again if needed.
296//
297// The `is_ident` method defined above is insufficient for validation, as it
298// will reject non-ASCII identifiers.
299pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
300    let span = span.unwrap_or_else(Span::call_site);
301
302    let is_raw = id.starts_with("r#");
303    let unraw = Ident::new(if is_raw { &id[2..] } else { id }, span);
304    if !is_raw {
305        return unraw;
306    }
307
308    // At this point, the identifier is raw, and the unraw-ed version of it was
309    // successfully converted into an identifier. Try to produce a valid raw
310    // identifier by running the `TokenStream` parser, and unwrapping the first
311    // token as an `Ident`.
312    //
313    // FIXME: When `Ident::new_raw` becomes stable, this method should be
314    // updated to call it when available.
315    match id.parse::<TokenStream>() {
316        Ok(ts) => {
317            let mut iter = ts.into_iter();
318            match (iter.next(), iter.next()) {
319                (Some(TokenTree::Ident(mut id)), None) => {
320                    id.set_span(span);
321                    id
322                }
323                _ => unreachable!("valid raw ident fails to parse"),
324            }
325        }
326        Err(_) => unreachable!("valid raw ident fails to parse"),
327    }
328}
329
330// Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!`
331// macro, and exposes span information from these fragments.
332//
333// This struct also has forwarding implementations of the formatting traits
334// `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within
335// `format_ident!`.
336#[derive(Copy, Clone)]
337pub struct IdentFragmentAdapter<T: IdentFragment>(pub T);
338
339impl<T: IdentFragment> IdentFragmentAdapter<T> {
340    pub fn span(&self) -> Option<Span> {
341        self.0.span()
342    }
343}
344
345impl<T: IdentFragment> fmt::Display for IdentFragmentAdapter<T> {
346    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
347        IdentFragment::fmt(&self.0, f)
348    }
349}
350
351impl<T: IdentFragment + fmt::Octal> fmt::Octal for IdentFragmentAdapter<T> {
352    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
353        fmt::Octal::fmt(&self.0, f)
354    }
355}
356
357impl<T: IdentFragment + fmt::LowerHex> fmt::LowerHex for IdentFragmentAdapter<T> {
358    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
359        fmt::LowerHex::fmt(&self.0, f)
360    }
361}
362
363impl<T: IdentFragment + fmt::UpperHex> fmt::UpperHex for IdentFragmentAdapter<T> {
364    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
365        fmt::UpperHex::fmt(&self.0, f)
366    }
367}
368
369impl<T: IdentFragment + fmt::Binary> fmt::Binary for IdentFragmentAdapter<T> {
370    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
371        fmt::Binary::fmt(&self.0, f)
372    }
373}