xref: /linux/rust/quote/runtime.rs (revision 54e3eae855629702c566bd2e130d9f40e7f35bde)
1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2 
3 use self::get_span::{GetSpan, GetSpanBase, GetSpanInner};
4 use crate::{IdentFragment, ToTokens, TokenStreamExt};
5 use core::fmt;
6 use core::iter;
7 use core::ops::BitOr;
8 use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree};
9 
10 #[doc(hidden)]
11 pub use alloc::format;
12 #[doc(hidden)]
13 pub use core::option::Option;
14 
15 #[doc(hidden)]
16 pub type Delimiter = proc_macro2::Delimiter;
17 #[doc(hidden)]
18 pub type Span = proc_macro2::Span;
19 #[doc(hidden)]
20 pub type TokenStream = proc_macro2::TokenStream;
21 
22 #[doc(hidden)]
23 pub struct HasIterator; // True
24 #[doc(hidden)]
25 pub struct ThereIsNoIteratorInRepetition; // False
26 
27 impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
28     type Output = ThereIsNoIteratorInRepetition;
29     fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
30         ThereIsNoIteratorInRepetition
31     }
32 }
33 
34 impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
35     type Output = HasIterator;
36     fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
37         HasIterator
38     }
39 }
40 
41 impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
42     type Output = HasIterator;
43     fn bitor(self, _rhs: HasIterator) -> HasIterator {
44         HasIterator
45     }
46 }
47 
48 impl 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)]
62 pub 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)]
168 pub struct RepInterp<T>(pub T);
169 
170 impl<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 
180 impl<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 
188 impl<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]
196 pub fn get_span<T>(span: T) -> GetSpan<T> {
197     GetSpan(GetSpanInner(GetSpanBase(span)))
198 }
199 
200 mod 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)]
252 pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
253     tokens.append(Group::new(delimiter, inner));
254 }
255 
256 #[doc(hidden)]
257 pub 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)]
269 pub 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)]
275 pub 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.
281 fn 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)]
298 pub 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)]
304 pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
305     tokens.append(ident_maybe_raw(s, span));
306 }
307 
308 #[doc(hidden)]
309 pub 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)]
317 pub 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 
328 macro_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 
379 push_punct!(push_add push_add_spanned '+');
380 push_punct!(push_add_eq push_add_eq_spanned '+' '=');
381 push_punct!(push_and push_and_spanned '&');
382 push_punct!(push_and_and push_and_and_spanned '&' '&');
383 push_punct!(push_and_eq push_and_eq_spanned '&' '=');
384 push_punct!(push_at push_at_spanned '@');
385 push_punct!(push_bang push_bang_spanned '!');
386 push_punct!(push_caret push_caret_spanned '^');
387 push_punct!(push_caret_eq push_caret_eq_spanned '^' '=');
388 push_punct!(push_colon push_colon_spanned ':');
389 push_punct!(push_colon2 push_colon2_spanned ':' ':');
390 push_punct!(push_comma push_comma_spanned ',');
391 push_punct!(push_div push_div_spanned '/');
392 push_punct!(push_div_eq push_div_eq_spanned '/' '=');
393 push_punct!(push_dot push_dot_spanned '.');
394 push_punct!(push_dot2 push_dot2_spanned '.' '.');
395 push_punct!(push_dot3 push_dot3_spanned '.' '.' '.');
396 push_punct!(push_dot_dot_eq push_dot_dot_eq_spanned '.' '.' '=');
397 push_punct!(push_eq push_eq_spanned '=');
398 push_punct!(push_eq_eq push_eq_eq_spanned '=' '=');
399 push_punct!(push_ge push_ge_spanned '>' '=');
400 push_punct!(push_gt push_gt_spanned '>');
401 push_punct!(push_le push_le_spanned '<' '=');
402 push_punct!(push_lt push_lt_spanned '<');
403 push_punct!(push_mul_eq push_mul_eq_spanned '*' '=');
404 push_punct!(push_ne push_ne_spanned '!' '=');
405 push_punct!(push_or push_or_spanned '|');
406 push_punct!(push_or_eq push_or_eq_spanned '|' '=');
407 push_punct!(push_or_or push_or_or_spanned '|' '|');
408 push_punct!(push_pound push_pound_spanned '#');
409 push_punct!(push_question push_question_spanned '?');
410 push_punct!(push_rarrow push_rarrow_spanned '-' '>');
411 push_punct!(push_larrow push_larrow_spanned '<' '-');
412 push_punct!(push_rem push_rem_spanned '%');
413 push_punct!(push_rem_eq push_rem_eq_spanned '%' '=');
414 push_punct!(push_fat_arrow push_fat_arrow_spanned '=' '>');
415 push_punct!(push_semi push_semi_spanned ';');
416 push_punct!(push_shl push_shl_spanned '<' '<');
417 push_punct!(push_shl_eq push_shl_eq_spanned '<' '<' '=');
418 push_punct!(push_shr push_shr_spanned '>' '>');
419 push_punct!(push_shr_eq push_shr_eq_spanned '>' '>' '=');
420 push_punct!(push_star push_star_spanned '*');
421 push_punct!(push_sub push_sub_spanned '-');
422 push_punct!(push_sub_eq push_sub_eq_spanned '-' '=');
423 
424 #[doc(hidden)]
425 pub fn push_underscore(tokens: &mut TokenStream) {
426     push_underscore_spanned(tokens, Span::call_site());
427 }
428 
429 #[doc(hidden)]
430 pub 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)]
437 pub 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 
442 fn 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)]
458 pub struct IdentFragmentAdapter<T: IdentFragment>(pub T);
459 
460 impl<T: IdentFragment> IdentFragmentAdapter<T> {
461     pub fn span(&self) -> Option<Span> {
462         self.0.span()
463     }
464 }
465 
466 impl<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 
472 impl<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 
478 impl<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 
484 impl<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 
490 impl<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 }
495