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