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