• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use self::get_span::{GetSpan, GetSpanBase, GetSpanInner};
2 use crate::{IdentFragment, ToTokens, TokenStreamExt};
3 use core::fmt;
4 use core::iter;
5 use core::ops::BitOr;
6 use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree};
7 
8 #[doc(hidden)]
9 pub use alloc::format;
10 #[doc(hidden)]
11 pub use core::option::Option;
12 
13 #[doc(hidden)]
14 pub type Delimiter = proc_macro2::Delimiter;
15 #[doc(hidden)]
16 pub type Span = proc_macro2::Span;
17 #[doc(hidden)]
18 pub type TokenStream = proc_macro2::TokenStream;
19 
20 #[doc(hidden)]
21 pub struct HasIterator; // True
22 #[doc(hidden)]
23 pub struct ThereIsNoIteratorInRepetition; // False
24 
25 impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
26     type Output = ThereIsNoIteratorInRepetition;
bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition27     fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
28         ThereIsNoIteratorInRepetition
29     }
30 }
31 
32 impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
33     type Output = HasIterator;
bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator34     fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
35         HasIterator
36     }
37 }
38 
39 impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
40     type Output = HasIterator;
bitor(self, _rhs: HasIterator) -> HasIterator41     fn bitor(self, _rhs: HasIterator) -> HasIterator {
42         HasIterator
43     }
44 }
45 
46 impl BitOr<HasIterator> for HasIterator {
47     type Output = HasIterator;
bitor(self, _rhs: HasIterator) -> HasIterator48     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)]
60 pub 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 {
quote_into_iter(self) -> (Self, HasIter)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.
next(&self) -> Option<&Self>85         fn next(&self) -> Option<&Self> {
86             Some(self)
87         }
88 
quote_into_iter(&self) -> (&Self, DoesNotHaveIter)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 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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)]
166 pub struct RepInterp<T>(pub T);
167 
168 impl<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.
next(self) -> Option<T>173     pub fn next(self) -> Option<T> {
174         Some(self.0)
175     }
176 }
177 
178 impl<T: Iterator> Iterator for RepInterp<T> {
179     type Item = T::Item;
180 
next(&mut self) -> Option<Self::Item>181     fn next(&mut self) -> Option<Self::Item> {
182         self.0.next()
183     }
184 }
185 
186 impl<T: ToTokens> ToTokens for RepInterp<T> {
to_tokens(&self, tokens: &mut TokenStream)187     fn to_tokens(&self, tokens: &mut TokenStream) {
188         self.0.to_tokens(tokens);
189     }
190 }
191 
192 #[doc(hidden)]
193 #[inline]
get_span<T>(span: T) -> GetSpan<T>194 pub fn get_span<T>(span: T) -> GetSpan<T> {
195     GetSpan(GetSpanInner(GetSpanBase(span)))
196 }
197 
198 mod 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]
__into_span(self) -> Span211         pub fn __into_span(self) -> Span {
212             ((self.0).0).0
213         }
214     }
215 
216     impl GetSpanInner<DelimSpan> {
217         #[inline]
__into_span(&self) -> Span218         pub fn __into_span(&self) -> Span {
219             (self.0).0.join()
220         }
221     }
222 
223     impl<T> GetSpanBase<T> {
224         #[allow(clippy::unused_self)]
__into_span(&self) -> T225         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]
deref(&self) -> &Self::Target234         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]
deref(&self) -> &Self::Target243         fn deref(&self) -> &Self::Target {
244             &self.0
245         }
246     }
247 }
248 
249 #[doc(hidden)]
push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream)250 pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
251     tokens.append(Group::new(delimiter, inner));
252 }
253 
254 #[doc(hidden)]
push_group_spanned( tokens: &mut TokenStream, span: Span, delimiter: Delimiter, inner: TokenStream, )255 pub 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)]
parse(tokens: &mut TokenStream, s: &str)267 pub 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)]
parse_spanned(tokens: &mut TokenStream, span: Span, s: &str)273 pub 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.
respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree279 fn 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)]
push_ident(tokens: &mut TokenStream, s: &str)296 pub 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)]
push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str)302 pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
303     tokens.append(ident_maybe_raw(s, span));
304 }
305 
306 #[doc(hidden)]
push_lifetime(tokens: &mut TokenStream, lifetime: &str)307 pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) {
308     tokens.extend([
309         TokenTree::Punct(Punct::new('\'', Spacing::Joint)),
310         TokenTree::Ident(Ident::new(&lifetime[1..], Span::call_site())),
311     ]);
312 }
313 
314 #[doc(hidden)]
push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str)315 pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str) {
316     tokens.extend([
317         TokenTree::Punct({
318             let mut apostrophe = Punct::new('\'', Spacing::Joint);
319             apostrophe.set_span(span);
320             apostrophe
321         }),
322         TokenTree::Ident(Ident::new(&lifetime[1..], span)),
323     ]);
324 }
325 
326 macro_rules! push_punct {
327     ($name:ident $spanned:ident $char1:tt) => {
328         #[doc(hidden)]
329         pub fn $name(tokens: &mut TokenStream) {
330             tokens.append(Punct::new($char1, Spacing::Alone));
331         }
332         #[doc(hidden)]
333         pub fn $spanned(tokens: &mut TokenStream, span: Span) {
334             let mut punct = Punct::new($char1, Spacing::Alone);
335             punct.set_span(span);
336             tokens.append(punct);
337         }
338     };
339     ($name:ident $spanned:ident $char1:tt $char2:tt) => {
340         #[doc(hidden)]
341         pub fn $name(tokens: &mut TokenStream) {
342             tokens.append(Punct::new($char1, Spacing::Joint));
343             tokens.append(Punct::new($char2, Spacing::Alone));
344         }
345         #[doc(hidden)]
346         pub fn $spanned(tokens: &mut TokenStream, span: Span) {
347             let mut punct = Punct::new($char1, Spacing::Joint);
348             punct.set_span(span);
349             tokens.append(punct);
350             let mut punct = Punct::new($char2, Spacing::Alone);
351             punct.set_span(span);
352             tokens.append(punct);
353         }
354     };
355     ($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => {
356         #[doc(hidden)]
357         pub fn $name(tokens: &mut TokenStream) {
358             tokens.append(Punct::new($char1, Spacing::Joint));
359             tokens.append(Punct::new($char2, Spacing::Joint));
360             tokens.append(Punct::new($char3, Spacing::Alone));
361         }
362         #[doc(hidden)]
363         pub fn $spanned(tokens: &mut TokenStream, span: Span) {
364             let mut punct = Punct::new($char1, Spacing::Joint);
365             punct.set_span(span);
366             tokens.append(punct);
367             let mut punct = Punct::new($char2, Spacing::Joint);
368             punct.set_span(span);
369             tokens.append(punct);
370             let mut punct = Punct::new($char3, Spacing::Alone);
371             punct.set_span(span);
372             tokens.append(punct);
373         }
374     };
375 }
376 
377 push_punct!(push_add push_add_spanned '+');
378 push_punct!(push_add_eq push_add_eq_spanned '+' '=');
379 push_punct!(push_and push_and_spanned '&');
380 push_punct!(push_and_and push_and_and_spanned '&' '&');
381 push_punct!(push_and_eq push_and_eq_spanned '&' '=');
382 push_punct!(push_at push_at_spanned '@');
383 push_punct!(push_bang push_bang_spanned '!');
384 push_punct!(push_caret push_caret_spanned '^');
385 push_punct!(push_caret_eq push_caret_eq_spanned '^' '=');
386 push_punct!(push_colon push_colon_spanned ':');
387 push_punct!(push_colon2 push_colon2_spanned ':' ':');
388 push_punct!(push_comma push_comma_spanned ',');
389 push_punct!(push_div push_div_spanned '/');
390 push_punct!(push_div_eq push_div_eq_spanned '/' '=');
391 push_punct!(push_dot push_dot_spanned '.');
392 push_punct!(push_dot2 push_dot2_spanned '.' '.');
393 push_punct!(push_dot3 push_dot3_spanned '.' '.' '.');
394 push_punct!(push_dot_dot_eq push_dot_dot_eq_spanned '.' '.' '=');
395 push_punct!(push_eq push_eq_spanned '=');
396 push_punct!(push_eq_eq push_eq_eq_spanned '=' '=');
397 push_punct!(push_ge push_ge_spanned '>' '=');
398 push_punct!(push_gt push_gt_spanned '>');
399 push_punct!(push_le push_le_spanned '<' '=');
400 push_punct!(push_lt push_lt_spanned '<');
401 push_punct!(push_mul_eq push_mul_eq_spanned '*' '=');
402 push_punct!(push_ne push_ne_spanned '!' '=');
403 push_punct!(push_or push_or_spanned '|');
404 push_punct!(push_or_eq push_or_eq_spanned '|' '=');
405 push_punct!(push_or_or push_or_or_spanned '|' '|');
406 push_punct!(push_pound push_pound_spanned '#');
407 push_punct!(push_question push_question_spanned '?');
408 push_punct!(push_rarrow push_rarrow_spanned '-' '>');
409 push_punct!(push_larrow push_larrow_spanned '<' '-');
410 push_punct!(push_rem push_rem_spanned '%');
411 push_punct!(push_rem_eq push_rem_eq_spanned '%' '=');
412 push_punct!(push_fat_arrow push_fat_arrow_spanned '=' '>');
413 push_punct!(push_semi push_semi_spanned ';');
414 push_punct!(push_shl push_shl_spanned '<' '<');
415 push_punct!(push_shl_eq push_shl_eq_spanned '<' '<' '=');
416 push_punct!(push_shr push_shr_spanned '>' '>');
417 push_punct!(push_shr_eq push_shr_eq_spanned '>' '>' '=');
418 push_punct!(push_star push_star_spanned '*');
419 push_punct!(push_sub push_sub_spanned '-');
420 push_punct!(push_sub_eq push_sub_eq_spanned '-' '=');
421 
422 #[doc(hidden)]
push_underscore(tokens: &mut TokenStream)423 pub fn push_underscore(tokens: &mut TokenStream) {
424     push_underscore_spanned(tokens, Span::call_site());
425 }
426 
427 #[doc(hidden)]
push_underscore_spanned(tokens: &mut TokenStream, span: Span)428 pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) {
429     tokens.append(Ident::new("_", span));
430 }
431 
432 // Helper method for constructing identifiers from the `format_ident!` macro,
433 // handling `r#` prefixes.
434 #[doc(hidden)]
mk_ident(id: &str, span: Option<Span>) -> Ident435 pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
436     let span = span.unwrap_or_else(Span::call_site);
437     ident_maybe_raw(id, span)
438 }
439 
ident_maybe_raw(id: &str, span: Span) -> Ident440 fn ident_maybe_raw(id: &str, span: Span) -> Ident {
441     if let Some(id) = id.strip_prefix("r#") {
442         Ident::new_raw(id, span)
443     } else {
444         Ident::new(id, span)
445     }
446 }
447 
448 // Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!`
449 // macro, and exposes span information from these fragments.
450 //
451 // This struct also has forwarding implementations of the formatting traits
452 // `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within
453 // `format_ident!`.
454 #[derive(Copy, Clone)]
455 #[doc(hidden)]
456 pub struct IdentFragmentAdapter<T: IdentFragment>(pub T);
457 
458 impl<T: IdentFragment> IdentFragmentAdapter<T> {
span(&self) -> Option<Span>459     pub fn span(&self) -> Option<Span> {
460         self.0.span()
461     }
462 }
463 
464 impl<T: IdentFragment> fmt::Display for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result465     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
466         IdentFragment::fmt(&self.0, f)
467     }
468 }
469 
470 impl<T: IdentFragment + fmt::Octal> fmt::Octal for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result471     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
472         fmt::Octal::fmt(&self.0, f)
473     }
474 }
475 
476 impl<T: IdentFragment + fmt::LowerHex> fmt::LowerHex for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result477     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
478         fmt::LowerHex::fmt(&self.0, f)
479     }
480 }
481 
482 impl<T: IdentFragment + fmt::UpperHex> fmt::UpperHex for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result483     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
484         fmt::UpperHex::fmt(&self.0, f)
485     }
486 }
487 
488 impl<T: IdentFragment + fmt::Binary> fmt::Binary for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result489     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
490         fmt::Binary::fmt(&self.0, f)
491     }
492 }
493