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;
bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition29 fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
30 ThereIsNoIteratorInRepetition
31 }
32 }
33
34 impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
35 type Output = HasIterator;
bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator36 fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
37 HasIterator
38 }
39 }
40
41 impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
42 type Output = HasIterator;
bitor(self, _rhs: HasIterator) -> HasIterator43 fn bitor(self, _rhs: HasIterator) -> HasIterator {
44 HasIterator
45 }
46 }
47
48 impl BitOr<HasIterator> for HasIterator {
49 type Output = HasIterator;
bitor(self, _rhs: HasIterator) -> HasIterator50 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 {
quote_into_iter(self) -> (Self, HasIter)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.
next(&self) -> Option<&Self>87 fn next(&self) -> Option<&Self> {
88 Some(self)
89 }
90
quote_into_iter(&self) -> (&Self, DoesNotHaveIter)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
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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
quote_into_iter(&'q self) -> (Self::Iter, HasIter)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.
next(self) -> Option<T>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
next(&mut self) -> Option<Self::Item>183 fn next(&mut self) -> Option<Self::Item> {
184 self.0.next()
185 }
186 }
187
188 impl<T: ToTokens> ToTokens for RepInterp<T> {
to_tokens(&self, tokens: &mut TokenStream)189 fn to_tokens(&self, tokens: &mut TokenStream) {
190 self.0.to_tokens(tokens);
191 }
192 }
193
194 #[doc(hidden)]
195 #[inline]
get_span<T>(span: T) -> GetSpan<T>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]
__into_span(self) -> Span213 pub fn __into_span(self) -> Span {
214 ((self.0).0).0
215 }
216 }
217
218 impl GetSpanInner<DelimSpan> {
219 #[inline]
__into_span(&self) -> Span220 pub fn __into_span(&self) -> Span {
221 (self.0).0.join()
222 }
223 }
224
225 impl<T> GetSpanBase<T> {
226 #[allow(clippy::unused_self)]
__into_span(&self) -> T227 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]
deref(&self) -> &Self::Target236 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]
deref(&self) -> &Self::Target245 fn deref(&self) -> &Self::Target {
246 &self.0
247 }
248 }
249 }
250
251 #[doc(hidden)]
push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream)252 pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
253 tokens.append(Group::new(delimiter, inner));
254 }
255
256 #[doc(hidden)]
push_group_spanned( tokens: &mut TokenStream, span: Span, delimiter: Delimiter, inner: TokenStream, )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)]
parse(tokens: &mut TokenStream, s: &str)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)]
parse_spanned(tokens: &mut TokenStream, span: Span, s: &str)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.
respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree281 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)]
push_ident(tokens: &mut TokenStream, s: &str)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)]
push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str)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)]
push_lifetime(tokens: &mut TokenStream, lifetime: &str)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)]
push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str)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)]
push_underscore(tokens: &mut TokenStream)425 pub fn push_underscore(tokens: &mut TokenStream) {
426 push_underscore_spanned(tokens, Span::call_site());
427 }
428
429 #[doc(hidden)]
push_underscore_spanned(tokens: &mut TokenStream, span: Span)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)]
mk_ident(id: &str, span: Option<Span>) -> Ident437 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
ident_maybe_raw(id: &str, span: Span) -> Ident442 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> {
span(&self) -> Option<Span>461 pub fn span(&self) -> Option<Span> {
462 self.0.span()
463 }
464 }
465
466 impl<T: IdentFragment> fmt::Display for IdentFragmentAdapter<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result467 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> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result473 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> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result479 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> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result485 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> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result491 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
492 fmt::Binary::fmt(&self.0, f)
493 }
494 }
495