quote/
runtime.rs

1use self::get_span::{GetSpan, GetSpanBase, GetSpanInner};
2use crate::{IdentFragment, ToTokens, TokenStreamExt};
3use core::fmt;
4use core::iter;
5use core::ops::BitOr;
6use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree};
7
8#[doc(hidden)]
9pub use alloc::format;
10#[doc(hidden)]
11pub use core::option::Option;
12
13#[doc(hidden)]
14pub type Delimiter = proc_macro2::Delimiter;
15#[doc(hidden)]
16pub type Span = proc_macro2::Span;
17#[doc(hidden)]
18pub type TokenStream = proc_macro2::TokenStream;
19
20#[doc(hidden)]
21pub struct HasIterator; // True
22#[doc(hidden)]
23pub struct ThereIsNoIteratorInRepetition; // False
24
25impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
26    type Output = ThereIsNoIteratorInRepetition;
27    fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
28        ThereIsNoIteratorInRepetition
29    }
30}
31
32impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
33    type Output = HasIterator;
34    fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
35        HasIterator
36    }
37}
38
39impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
40    type Output = HasIterator;
41    fn bitor(self, _rhs: HasIterator) -> HasIterator {
42        HasIterator
43    }
44}
45
46impl BitOr<HasIterator> for HasIterator {
47    type Output = HasIterator;
48    fn bitor(self, _rhs: HasIterator) -> HasIterator {
49        HasIterator
50    }
51}
52
53/// Extension traits used by the implementation of `quote!`. These are defined
54/// in separate traits, rather than as a single trait due to ambiguity issues.
55///
56/// These traits expose a `quote_into_iter` method which should allow calling
57/// whichever impl happens to be applicable. Calling that method repeatedly on
58/// the returned value should be idempotent.
59#[doc(hidden)]
60pub mod ext {
61    use super::RepInterp;
62    use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
63    use crate::ToTokens;
64    use alloc::collections::btree_set::{self, BTreeSet};
65    use core::slice;
66
67    /// Extension trait providing the `quote_into_iter` method on iterators.
68    #[doc(hidden)]
69    pub trait RepIteratorExt: Iterator + Sized {
70        fn quote_into_iter(self) -> (Self, HasIter) {
71            (self, HasIter)
72        }
73    }
74
75    impl<T: Iterator> RepIteratorExt for T {}
76
77    /// Extension trait providing the `quote_into_iter` method for
78    /// non-iterable types. These types interpolate the same value in each
79    /// iteration of the repetition.
80    #[doc(hidden)]
81    pub trait RepToTokensExt {
82        /// Pretend to be an iterator for the purposes of `quote_into_iter`.
83        /// This allows repeated calls to `quote_into_iter` to continue
84        /// correctly returning DoesNotHaveIter.
85        fn next(&self) -> Option<&Self> {
86            Some(self)
87        }
88
89        fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) {
90            (self, DoesNotHaveIter)
91        }
92    }
93
94    impl<T: ToTokens + ?Sized> RepToTokensExt for T {}
95
96    /// Extension trait providing the `quote_into_iter` method for types that
97    /// can be referenced as an iterator.
98    #[doc(hidden)]
99    pub trait RepAsIteratorExt<'q> {
100        type Iter: Iterator;
101
102        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
103    }
104
105    impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &T {
106        type Iter = T::Iter;
107
108        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
109            <T as RepAsIteratorExt>::quote_into_iter(*self)
110        }
111    }
112
113    impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &mut T {
114        type Iter = T::Iter;
115
116        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
117            <T as RepAsIteratorExt>::quote_into_iter(*self)
118        }
119    }
120
121    impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
122        type Iter = slice::Iter<'q, T>;
123
124        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
125            (self.iter(), HasIter)
126        }
127    }
128
129    impl<'q, T: 'q, const N: usize> RepAsIteratorExt<'q> for [T; N] {
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    impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
138        type Iter = slice::Iter<'q, T>;
139
140        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
141            (self.iter(), HasIter)
142        }
143    }
144
145    impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
146        type Iter = btree_set::Iter<'q, T>;
147
148        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
149            (self.iter(), HasIter)
150        }
151    }
152
153    impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
154        type Iter = T::Iter;
155
156        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
157            self.0.quote_into_iter()
158        }
159    }
160}
161
162// Helper type used within interpolations to allow for repeated binding names.
163// Implements the relevant traits, and exports a dummy `next()` method.
164#[derive(Copy, Clone)]
165#[doc(hidden)]
166pub struct RepInterp<T>(pub T);
167
168impl<T> RepInterp<T> {
169    // This method is intended to look like `Iterator::next`, and is called when
170    // a name is bound multiple times, as the previous binding will shadow the
171    // original `Iterator` object. This allows us to avoid advancing the
172    // iterator multiple times per iteration.
173    pub fn next(self) -> Option<T> {
174        Some(self.0)
175    }
176}
177
178impl<T: Iterator> Iterator for RepInterp<T> {
179    type Item = T::Item;
180
181    fn next(&mut self) -> Option<Self::Item> {
182        self.0.next()
183    }
184}
185
186impl<T: ToTokens> ToTokens for RepInterp<T> {
187    fn to_tokens(&self, tokens: &mut TokenStream) {
188        self.0.to_tokens(tokens);
189    }
190}
191
192#[doc(hidden)]
193#[inline]
194pub fn get_span<T>(span: T) -> GetSpan<T> {
195    GetSpan(GetSpanInner(GetSpanBase(span)))
196}
197
198mod get_span {
199    use core::ops::Deref;
200    use proc_macro2::extra::DelimSpan;
201    use proc_macro2::Span;
202
203    pub struct GetSpan<T>(pub(crate) GetSpanInner<T>);
204
205    pub struct GetSpanInner<T>(pub(crate) GetSpanBase<T>);
206
207    pub struct GetSpanBase<T>(pub(crate) T);
208
209    impl GetSpan<Span> {
210        #[inline]
211        pub fn __into_span(self) -> Span {
212            ((self.0).0).0
213        }
214    }
215
216    impl GetSpanInner<DelimSpan> {
217        #[inline]
218        pub fn __into_span(&self) -> Span {
219            (self.0).0.join()
220        }
221    }
222
223    impl<T> GetSpanBase<T> {
224        #[allow(clippy::unused_self)]
225        pub fn __into_span(&self) -> T {
226            unreachable!()
227        }
228    }
229
230    impl<T> Deref for GetSpan<T> {
231        type Target = GetSpanInner<T>;
232
233        #[inline]
234        fn deref(&self) -> &Self::Target {
235            &self.0
236        }
237    }
238
239    impl<T> Deref for GetSpanInner<T> {
240        type Target = GetSpanBase<T>;
241
242        #[inline]
243        fn deref(&self) -> &Self::Target {
244            &self.0
245        }
246    }
247}
248
249#[doc(hidden)]
250pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
251    tokens.append(Group::new(delimiter, inner));
252}
253
254#[doc(hidden)]
255pub fn push_group_spanned(
256    tokens: &mut TokenStream,
257    span: Span,
258    delimiter: Delimiter,
259    inner: TokenStream,
260) {
261    let mut g = Group::new(delimiter, inner);
262    g.set_span(span);
263    tokens.append(g);
264}
265
266#[doc(hidden)]
267pub fn parse(tokens: &mut TokenStream, s: &str) {
268    let s: TokenStream = s.parse().expect("invalid token stream");
269    tokens.extend(iter::once(s));
270}
271
272#[doc(hidden)]
273pub fn parse_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
274    let s: TokenStream = s.parse().expect("invalid token stream");
275    tokens.extend(s.into_iter().map(|t| respan_token_tree(t, span)));
276}
277
278// Token tree with every span replaced by the given one.
279fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
280    match &mut token {
281        TokenTree::Group(g) => {
282            let stream = g
283                .stream()
284                .into_iter()
285                .map(|token| respan_token_tree(token, span))
286                .collect();
287            *g = Group::new(g.delimiter(), stream);
288            g.set_span(span);
289        }
290        other => other.set_span(span),
291    }
292    token
293}
294
295#[doc(hidden)]
296pub fn push_ident(tokens: &mut TokenStream, s: &str) {
297    let span = Span::call_site();
298    push_ident_spanned(tokens, span, s);
299}
300
301#[doc(hidden)]
302pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
303    tokens.append(ident_maybe_raw(s, span));
304}
305
306#[doc(hidden)]
307pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) {
308    struct Lifetime<'a> {
309        name: &'a str,
310        state: u8,
311    }
312
313    impl<'a> Iterator for Lifetime<'a> {
314        type Item = TokenTree;
315
316        fn next(&mut self) -> Option<Self::Item> {
317            match self.state {
318                0 => {
319                    self.state = 1;
320                    Some(TokenTree::Punct(Punct::new('\'', Spacing::Joint)))
321                }
322                1 => {
323                    self.state = 2;
324                    Some(TokenTree::Ident(Ident::new(self.name, Span::call_site())))
325                }
326                _ => None,
327            }
328        }
329    }
330
331    tokens.extend(Lifetime {
332        name: &lifetime[1..],
333        state: 0,
334    });
335}
336
337#[doc(hidden)]
338pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str) {
339    struct Lifetime<'a> {
340        name: &'a str,
341        span: Span,
342        state: u8,
343    }
344
345    impl<'a> Iterator for Lifetime<'a> {
346        type Item = TokenTree;
347
348        fn next(&mut self) -> Option<Self::Item> {
349            match self.state {
350                0 => {
351                    self.state = 1;
352                    let mut apostrophe = Punct::new('\'', Spacing::Joint);
353                    apostrophe.set_span(self.span);
354                    Some(TokenTree::Punct(apostrophe))
355                }
356                1 => {
357                    self.state = 2;
358                    Some(TokenTree::Ident(Ident::new(self.name, self.span)))
359                }
360                _ => None,
361            }
362        }
363    }
364
365    tokens.extend(Lifetime {
366        name: &lifetime[1..],
367        span,
368        state: 0,
369    });
370}
371
372macro_rules! push_punct {
373    ($name:ident $spanned:ident $char1:tt) => {
374        #[doc(hidden)]
375        pub fn $name(tokens: &mut TokenStream) {
376            tokens.append(Punct::new($char1, Spacing::Alone));
377        }
378        #[doc(hidden)]
379        pub fn $spanned(tokens: &mut TokenStream, span: Span) {
380            let mut punct = Punct::new($char1, Spacing::Alone);
381            punct.set_span(span);
382            tokens.append(punct);
383        }
384    };
385    ($name:ident $spanned:ident $char1:tt $char2:tt) => {
386        #[doc(hidden)]
387        pub fn $name(tokens: &mut TokenStream) {
388            tokens.append(Punct::new($char1, Spacing::Joint));
389            tokens.append(Punct::new($char2, Spacing::Alone));
390        }
391        #[doc(hidden)]
392        pub fn $spanned(tokens: &mut TokenStream, span: Span) {
393            let mut punct = Punct::new($char1, Spacing::Joint);
394            punct.set_span(span);
395            tokens.append(punct);
396            let mut punct = Punct::new($char2, Spacing::Alone);
397            punct.set_span(span);
398            tokens.append(punct);
399        }
400    };
401    ($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => {
402        #[doc(hidden)]
403        pub fn $name(tokens: &mut TokenStream) {
404            tokens.append(Punct::new($char1, Spacing::Joint));
405            tokens.append(Punct::new($char2, Spacing::Joint));
406            tokens.append(Punct::new($char3, Spacing::Alone));
407        }
408        #[doc(hidden)]
409        pub fn $spanned(tokens: &mut TokenStream, span: Span) {
410            let mut punct = Punct::new($char1, Spacing::Joint);
411            punct.set_span(span);
412            tokens.append(punct);
413            let mut punct = Punct::new($char2, Spacing::Joint);
414            punct.set_span(span);
415            tokens.append(punct);
416            let mut punct = Punct::new($char3, Spacing::Alone);
417            punct.set_span(span);
418            tokens.append(punct);
419        }
420    };
421}
422
423push_punct!(push_add push_add_spanned '+');
424push_punct!(push_add_eq push_add_eq_spanned '+' '=');
425push_punct!(push_and push_and_spanned '&');
426push_punct!(push_and_and push_and_and_spanned '&' '&');
427push_punct!(push_and_eq push_and_eq_spanned '&' '=');
428push_punct!(push_at push_at_spanned '@');
429push_punct!(push_bang push_bang_spanned '!');
430push_punct!(push_caret push_caret_spanned '^');
431push_punct!(push_caret_eq push_caret_eq_spanned '^' '=');
432push_punct!(push_colon push_colon_spanned ':');
433push_punct!(push_colon2 push_colon2_spanned ':' ':');
434push_punct!(push_comma push_comma_spanned ',');
435push_punct!(push_div push_div_spanned '/');
436push_punct!(push_div_eq push_div_eq_spanned '/' '=');
437push_punct!(push_dot push_dot_spanned '.');
438push_punct!(push_dot2 push_dot2_spanned '.' '.');
439push_punct!(push_dot3 push_dot3_spanned '.' '.' '.');
440push_punct!(push_dot_dot_eq push_dot_dot_eq_spanned '.' '.' '=');
441push_punct!(push_eq push_eq_spanned '=');
442push_punct!(push_eq_eq push_eq_eq_spanned '=' '=');
443push_punct!(push_ge push_ge_spanned '>' '=');
444push_punct!(push_gt push_gt_spanned '>');
445push_punct!(push_le push_le_spanned '<' '=');
446push_punct!(push_lt push_lt_spanned '<');
447push_punct!(push_mul_eq push_mul_eq_spanned '*' '=');
448push_punct!(push_ne push_ne_spanned '!' '=');
449push_punct!(push_or push_or_spanned '|');
450push_punct!(push_or_eq push_or_eq_spanned '|' '=');
451push_punct!(push_or_or push_or_or_spanned '|' '|');
452push_punct!(push_pound push_pound_spanned '#');
453push_punct!(push_question push_question_spanned '?');
454push_punct!(push_rarrow push_rarrow_spanned '-' '>');
455push_punct!(push_larrow push_larrow_spanned '<' '-');
456push_punct!(push_rem push_rem_spanned '%');
457push_punct!(push_rem_eq push_rem_eq_spanned '%' '=');
458push_punct!(push_fat_arrow push_fat_arrow_spanned '=' '>');
459push_punct!(push_semi push_semi_spanned ';');
460push_punct!(push_shl push_shl_spanned '<' '<');
461push_punct!(push_shl_eq push_shl_eq_spanned '<' '<' '=');
462push_punct!(push_shr push_shr_spanned '>' '>');
463push_punct!(push_shr_eq push_shr_eq_spanned '>' '>' '=');
464push_punct!(push_star push_star_spanned '*');
465push_punct!(push_sub push_sub_spanned '-');
466push_punct!(push_sub_eq push_sub_eq_spanned '-' '=');
467
468#[doc(hidden)]
469pub fn push_underscore(tokens: &mut TokenStream) {
470    push_underscore_spanned(tokens, Span::call_site());
471}
472
473#[doc(hidden)]
474pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) {
475    tokens.append(Ident::new("_", span));
476}
477
478// Helper method for constructing identifiers from the `format_ident!` macro,
479// handling `r#` prefixes.
480#[doc(hidden)]
481pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
482    let span = span.unwrap_or_else(Span::call_site);
483    ident_maybe_raw(id, span)
484}
485
486fn ident_maybe_raw(id: &str, span: Span) -> Ident {
487    if let Some(id) = id.strip_prefix("r#") {
488        Ident::new_raw(id, span)
489    } else {
490        Ident::new(id, span)
491    }
492}
493
494// Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!`
495// macro, and exposes span information from these fragments.
496//
497// This struct also has forwarding implementations of the formatting traits
498// `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within
499// `format_ident!`.
500#[derive(Copy, Clone)]
501#[doc(hidden)]
502pub struct IdentFragmentAdapter<T: IdentFragment>(pub T);
503
504impl<T: IdentFragment> IdentFragmentAdapter<T> {
505    pub fn span(&self) -> Option<Span> {
506        self.0.span()
507    }
508}
509
510impl<T: IdentFragment> fmt::Display for IdentFragmentAdapter<T> {
511    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
512        IdentFragment::fmt(&self.0, f)
513    }
514}
515
516impl<T: IdentFragment + fmt::Octal> fmt::Octal for IdentFragmentAdapter<T> {
517    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
518        fmt::Octal::fmt(&self.0, f)
519    }
520}
521
522impl<T: IdentFragment + fmt::LowerHex> fmt::LowerHex for IdentFragmentAdapter<T> {
523    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
524        fmt::LowerHex::fmt(&self.0, f)
525    }
526}
527
528impl<T: IdentFragment + fmt::UpperHex> fmt::UpperHex for IdentFragmentAdapter<T> {
529    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
530        fmt::UpperHex::fmt(&self.0, f)
531    }
532}
533
534impl<T: IdentFragment + fmt::Binary> fmt::Binary for IdentFragmentAdapter<T> {
535    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
536        fmt::Binary::fmt(&self.0, f)
537    }
538}