Skip to main content

quote/
runtime.rs

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