]> git.proxmox.com Git - cargo.git/blob - vendor/quote/src/runtime.rs
New upstream version 0.52.0
[cargo.git] / vendor / quote / src / runtime.rs
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;
12 fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
13 ThereIsNoIteratorInRepetition
14 }
15 }
16
17 impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
18 type Output = HasIterator;
19 fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
20 HasIterator
21 }
22 }
23
24 impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
25 type Output = HasIterator;
26 fn bitor(self, _rhs: HasIterator) -> HasIterator {
27 HasIterator
28 }
29 }
30
31 impl BitOr<HasIterator> for HasIterator {
32 type Output = HasIterator;
33 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 {
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.
67 fn next(&self) -> Option<&Self> {
68 Some(self)
69 }
70
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
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
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
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
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
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
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
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.
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
172 fn next(&mut self) -> Option<Self::Item> {
173 self.0.next()
174 }
175 }
176
177 impl<T: ToTokens> ToTokens for RepInterp<T> {
178 fn to_tokens(&self, tokens: &mut TokenStream) {
179 self.0.to_tokens(tokens);
180 }
181 }
182
183 pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
184 tokens.append(Group::new(delimiter, inner));
185 }
186
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
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
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
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
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.
332 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> {
369 pub fn span(&self) -> Option<Span> {
370 self.0.span()
371 }
372 }
373
374 impl<T: IdentFragment> fmt::Display for IdentFragmentAdapter<T> {
375 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> {
381 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> {
387 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> {
393 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> {
399 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400 fmt::Binary::fmt(&self.0, f)
401 }
402 }