• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{IdentFragment, ToTokens, TokenStreamExt};
2 use std::fmt;
3 use std::ops::BitOr;
4 
5 pub use proc_macro2::*;
6 
7 pub struct HasIterator; // True
8 pub struct ThereIsNoIteratorInRepetition; // False
9 
10 impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
11     type Output = ThereIsNoIteratorInRepetition;
bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition12     fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
13         ThereIsNoIteratorInRepetition
14     }
15 }
16 
17 impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
18     type Output = HasIterator;
bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator19     fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
20         HasIterator
21     }
22 }
23 
24 impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
25     type Output = HasIterator;
bitor(self, _rhs: HasIterator) -> HasIterator26     fn bitor(self, _rhs: HasIterator) -> HasIterator {
27         HasIterator
28     }
29 }
30 
31 impl BitOr<HasIterator> for HasIterator {
32     type Output = HasIterator;
bitor(self, _rhs: HasIterator) -> HasIterator33     fn bitor(self, _rhs: HasIterator) -> HasIterator {
34         HasIterator
35     }
36 }
37 
38 /// Extension traits used by the implementation of `quote!`. These are defined
39 /// in separate traits, rather than as a single trait due to ambiguity issues.
40 ///
41 /// These traits expose a `quote_into_iter` method which should allow calling
42 /// whichever impl happens to be applicable. Calling that method repeatedly on
43 /// the returned value should be idempotent.
44 pub mod ext {
45     use super::RepInterp;
46     use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
47     use crate::ToTokens;
48     use std::collections::btree_set::{self, BTreeSet};
49     use std::slice;
50 
51     /// Extension trait providing the `quote_into_iter` method on iterators.
52     pub trait RepIteratorExt: Iterator + Sized {
quote_into_iter(self) -> (Self, HasIter)53         fn quote_into_iter(self) -> (Self, HasIter) {
54             (self, HasIter)
55         }
56     }
57 
58     impl<T: Iterator> RepIteratorExt for T {}
59 
60     /// Extension trait providing the `quote_into_iter` method for
61     /// non-iterable types. These types interpolate the same value in each
62     /// iteration of the repetition.
63     pub trait RepToTokensExt {
64         /// Pretend to be an iterator for the purposes of `quote_into_iter`.
65         /// This allows repeated calls to `quote_into_iter` to continue
66         /// correctly returning DoesNotHaveIter.
next(&self) -> Option<&Self>67         fn next(&self) -> Option<&Self> {
68             Some(self)
69         }
70 
quote_into_iter(&self) -> (&Self, DoesNotHaveIter)71         fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) {
72             (self, DoesNotHaveIter)
73         }
74     }
75 
76     impl<T: ToTokens + ?Sized> RepToTokensExt for T {}
77 
78     /// Extension trait providing the `quote_into_iter` method for types that
79     /// can be referenced as an iterator.
80     pub trait RepAsIteratorExt<'q> {
81         type Iter: Iterator;
82 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)83         fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
84     }
85 
86     impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a T {
87         type Iter = T::Iter;
88 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)89         fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
90             <T as RepAsIteratorExt>::quote_into_iter(*self)
91         }
92     }
93 
94     impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a mut T {
95         type Iter = T::Iter;
96 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)97         fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
98             <T as RepAsIteratorExt>::quote_into_iter(*self)
99         }
100     }
101 
102     impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
103         type Iter = slice::Iter<'q, T>;
104 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)105         fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
106             (self.iter(), HasIter)
107         }
108     }
109 
110     impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
111         type Iter = slice::Iter<'q, T>;
112 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)113         fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
114             (self.iter(), HasIter)
115         }
116     }
117 
118     impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
119         type Iter = btree_set::Iter<'q, T>;
120 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)121         fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
122             (self.iter(), HasIter)
123         }
124     }
125 
126     macro_rules! array_rep_slice {
127         ($($l:tt)*) => {
128             $(
129                 impl<'q, T: 'q> RepAsIteratorExt<'q> for [T; $l] {
130                     type Iter = slice::Iter<'q, T>;
131 
132                     fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
133                         (self.iter(), HasIter)
134                     }
135                 }
136             )*
137         }
138     }
139 
140     array_rep_slice!(
141         0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
142         17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
143     );
144 
145     impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
146         type Iter = T::Iter;
147 
quote_into_iter(&'q self) -> (Self::Iter, HasIter)148         fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
149             self.0.quote_into_iter()
150         }
151     }
152 }
153 
154 // Helper type used within interpolations to allow for repeated binding names.
155 // Implements the relevant traits, and exports a dummy `next()` method.
156 #[derive(Copy, Clone)]
157 pub struct RepInterp<T>(pub T);
158 
159 impl<T> RepInterp<T> {
160     // This method is intended to look like `Iterator::next`, and is called when
161     // a name is bound multiple times, as the previous binding will shadow the
162     // original `Iterator` object. This allows us to avoid advancing the
163     // iterator multiple times per iteration.
next(self) -> Option<T>164     pub fn next(self) -> Option<T> {
165         Some(self.0)
166     }
167 }
168 
169 impl<T: Iterator> Iterator for RepInterp<T> {
170     type Item = T::Item;
171 
next(&mut self) -> Option<Self::Item>172     fn next(&mut self) -> Option<Self::Item> {
173         self.0.next()
174     }
175 }
176 
177 impl<T: ToTokens> ToTokens for RepInterp<T> {
to_tokens(&self, tokens: &mut TokenStream)178     fn to_tokens(&self, tokens: &mut TokenStream) {
179         self.0.to_tokens(tokens);
180     }
181 }
182 
push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream)183 pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
184     tokens.append(Group::new(delimiter, inner));
185 }
186 
push_group_spanned( tokens: &mut TokenStream, span: Span, delimiter: Delimiter, inner: TokenStream, )187 pub fn push_group_spanned(
188     tokens: &mut TokenStream,
189     span: Span,
190     delimiter: Delimiter,
191     inner: TokenStream,
192 ) {
193     let mut g = Group::new(delimiter, inner);
194     g.set_span(span);
195     tokens.append(g);
196 }
197 
parse(tokens: &mut TokenStream, s: &str)198 pub fn parse(tokens: &mut TokenStream, s: &str) {
199     let s: TokenStream = s.parse().expect("invalid token stream");
200     tokens.extend(s);
201 }
202 
parse_spanned(tokens: &mut TokenStream, span: Span, s: &str)203 pub fn parse_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
204     let s: TokenStream = s.parse().expect("invalid token stream");
205     tokens.extend(s.into_iter().map(|mut t| {
206         t.set_span(span);
207         t
208     }));
209 }
210 
push_ident(tokens: &mut TokenStream, s: &str)211 pub fn push_ident(tokens: &mut TokenStream, s: &str) {
212     // Optimization over `mk_ident`, as `s` is guaranteed to be a valid ident.
213     //
214     // FIXME: When `Ident::new_raw` becomes stable, this method should be
215     // updated to call it when available.
216     if s.starts_with("r#") {
217         parse(tokens, s);
218     } else {
219         tokens.append(Ident::new(s, Span::call_site()));
220     }
221 }
222 
push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str)223 pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
224     // Optimization over `mk_ident`, as `s` is guaranteed to be a valid ident.
225     //
226     // FIXME: When `Ident::new_raw` becomes stable, this method should be
227     // updated to call it when available.
228     if s.starts_with("r#") {
229         parse_spanned(tokens, span, s);
230     } else {
231         tokens.append(Ident::new(s, span));
232     }
233 }
234 
235 macro_rules! push_punct {
236     ($name:ident $spanned:ident $char1:tt) => {
237         pub fn $name(tokens: &mut TokenStream) {
238             tokens.append(Punct::new($char1, Spacing::Alone));
239         }
240         pub fn $spanned(tokens: &mut TokenStream, span: Span) {
241             let mut punct = Punct::new($char1, Spacing::Alone);
242             punct.set_span(span);
243             tokens.append(punct);
244         }
245     };
246     ($name:ident $spanned:ident $char1:tt $char2:tt) => {
247         pub fn $name(tokens: &mut TokenStream) {
248             tokens.append(Punct::new($char1, Spacing::Joint));
249             tokens.append(Punct::new($char2, Spacing::Alone));
250         }
251         pub fn $spanned(tokens: &mut TokenStream, span: Span) {
252             let mut punct = Punct::new($char1, Spacing::Joint);
253             punct.set_span(span);
254             tokens.append(punct);
255             let mut punct = Punct::new($char2, Spacing::Alone);
256             punct.set_span(span);
257             tokens.append(punct);
258         }
259     };
260     ($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => {
261         pub fn $name(tokens: &mut TokenStream) {
262             tokens.append(Punct::new($char1, Spacing::Joint));
263             tokens.append(Punct::new($char2, Spacing::Joint));
264             tokens.append(Punct::new($char3, Spacing::Alone));
265         }
266         pub fn $spanned(tokens: &mut TokenStream, span: Span) {
267             let mut punct = Punct::new($char1, Spacing::Joint);
268             punct.set_span(span);
269             tokens.append(punct);
270             let mut punct = Punct::new($char2, Spacing::Joint);
271             punct.set_span(span);
272             tokens.append(punct);
273             let mut punct = Punct::new($char3, Spacing::Alone);
274             punct.set_span(span);
275             tokens.append(punct);
276         }
277     };
278 }
279 
280 push_punct!(push_add push_add_spanned '+');
281 push_punct!(push_add_eq push_add_eq_spanned '+' '=');
282 push_punct!(push_and push_and_spanned '&');
283 push_punct!(push_and_and push_and_and_spanned '&' '&');
284 push_punct!(push_and_eq push_and_eq_spanned '&' '=');
285 push_punct!(push_at push_at_spanned '@');
286 push_punct!(push_bang push_bang_spanned '!');
287 push_punct!(push_caret push_caret_spanned '^');
288 push_punct!(push_caret_eq push_caret_eq_spanned '^' '=');
289 push_punct!(push_colon push_colon_spanned ':');
290 push_punct!(push_colon2 push_colon2_spanned ':' ':');
291 push_punct!(push_comma push_comma_spanned ',');
292 push_punct!(push_div push_div_spanned '/');
293 push_punct!(push_div_eq push_div_eq_spanned '/' '=');
294 push_punct!(push_dot push_dot_spanned '.');
295 push_punct!(push_dot2 push_dot2_spanned '.' '.');
296 push_punct!(push_dot3 push_dot3_spanned '.' '.' '.');
297 push_punct!(push_dot_dot_eq push_dot_dot_eq_spanned '.' '.' '=');
298 push_punct!(push_eq push_eq_spanned '=');
299 push_punct!(push_eq_eq push_eq_eq_spanned '=' '=');
300 push_punct!(push_ge push_ge_spanned '>' '=');
301 push_punct!(push_gt push_gt_spanned '>');
302 push_punct!(push_le push_le_spanned '<' '=');
303 push_punct!(push_lt push_lt_spanned '<');
304 push_punct!(push_mul_eq push_mul_eq_spanned '*' '=');
305 push_punct!(push_ne push_ne_spanned '!' '=');
306 push_punct!(push_or push_or_spanned '|');
307 push_punct!(push_or_eq push_or_eq_spanned '|' '=');
308 push_punct!(push_or_or push_or_or_spanned '|' '|');
309 push_punct!(push_pound push_pound_spanned '#');
310 push_punct!(push_question push_question_spanned '?');
311 push_punct!(push_rarrow push_rarrow_spanned '-' '>');
312 push_punct!(push_larrow push_larrow_spanned '<' '-');
313 push_punct!(push_rem push_rem_spanned '%');
314 push_punct!(push_rem_eq push_rem_eq_spanned '%' '=');
315 push_punct!(push_fat_arrow push_fat_arrow_spanned '=' '>');
316 push_punct!(push_semi push_semi_spanned ';');
317 push_punct!(push_shl push_shl_spanned '<' '<');
318 push_punct!(push_shl_eq push_shl_eq_spanned '<' '<' '=');
319 push_punct!(push_shr push_shr_spanned '>' '>');
320 push_punct!(push_shr_eq push_shr_eq_spanned '>' '>' '=');
321 push_punct!(push_star push_star_spanned '*');
322 push_punct!(push_sub push_sub_spanned '-');
323 push_punct!(push_sub_eq push_sub_eq_spanned '-' '=');
324 
325 // Helper method for constructing identifiers from the `format_ident!` macro,
326 // handling `r#` prefixes.
327 //
328 // Directly parsing the input string may produce a valid identifier,
329 // although the input string was invalid, due to ignored characters such as
330 // whitespace and comments. Instead, we always create a non-raw identifier
331 // to validate that the string is OK, and only parse again if needed.
mk_ident(id: &str, span: Option<Span>) -> Ident332 pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
333     let span = span.unwrap_or_else(Span::call_site);
334 
335     let is_raw = id.starts_with("r#");
336     let unraw = Ident::new(if is_raw { &id[2..] } else { id }, span);
337     if !is_raw {
338         return unraw;
339     }
340 
341     // At this point, the identifier is raw, and the unraw-ed version of it was
342     // successfully converted into an identifier. Try to produce a valid raw
343     // identifier by running the `TokenStream` parser, and unwrapping the first
344     // token as an `Ident`.
345     //
346     // FIXME: When `Ident::new_raw` becomes stable, this method should be
347     // updated to call it when available.
348     if let Ok(ts) = id.parse::<TokenStream>() {
349         let mut iter = ts.into_iter();
350         if let (Some(TokenTree::Ident(mut id)), None) = (iter.next(), iter.next()) {
351             id.set_span(span);
352             return id;
353         }
354     }
355 
356     panic!("not allowed as a raw identifier: `{}`", id);
357 }
358 
359 // Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!`
360 // macro, and exposes span information from these fragments.
361 //
362 // This struct also has forwarding implementations of the formatting traits
363 // `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within
364 // `format_ident!`.
365 #[derive(Copy, Clone)]
366 pub struct IdentFragmentAdapter<T: IdentFragment>(pub T);
367 
368 impl<T: IdentFragment> IdentFragmentAdapter<T> {
span(&self) -> Option<Span>369     pub fn span(&self) -> Option<Span> {
370         self.0.span()
371     }
372 }
373 
374 impl<T: IdentFragment> fmt::Display for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result375     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
376         IdentFragment::fmt(&self.0, f)
377     }
378 }
379 
380 impl<T: IdentFragment + fmt::Octal> fmt::Octal for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result381     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382         fmt::Octal::fmt(&self.0, f)
383     }
384 }
385 
386 impl<T: IdentFragment + fmt::LowerHex> fmt::LowerHex for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result387     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
388         fmt::LowerHex::fmt(&self.0, f)
389     }
390 }
391 
392 impl<T: IdentFragment + fmt::UpperHex> fmt::UpperHex for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result393     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394         fmt::UpperHex::fmt(&self.0, f)
395     }
396 }
397 
398 impl<T: IdentFragment + fmt::Binary> fmt::Binary for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result399     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400         fmt::Binary::fmt(&self.0, f)
401     }
402 }
403