1use super::{Delimiter, ToTokens, TokenStream};
2use core::ops::BitOr;
3
4pub struct HasIterator; // True
5pub struct ThereIsNoIteratorInRepetition; // False
6
7impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
8 type Output = ThereIsNoIteratorInRepetition;
9 fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
10 ThereIsNoIteratorInRepetition
11 }
12}
13
14impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
15 type Output = HasIterator;
16 fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
17 HasIterator
18 }
19}
20
21impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
22 type Output = HasIterator;
23 fn bitor(self, _rhs: HasIterator) -> HasIterator {
24 HasIterator
25 }
26}
27
28impl BitOr<HasIterator> for HasIterator {
29 type Output = HasIterator;
30 fn bitor(self, _rhs: HasIterator) -> HasIterator {
31 HasIterator
32 }
33}
34
35/// Extension traits used by the implementation of `quote!`. These are defined
36/// in separate traits, rather than as a single trait due to ambiguity issues.
37///
38/// These traits expose a `quote_into_iter` method which should allow calling
39/// whichever impl happens to be applicable. Calling that method repeatedly on
40/// the returned value should be idempotent.
41pub mod ext {
42 use super::RepInterp;
43 use super::ToTokens;
44 use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
45 use core::slice;
46 use std::collections::btree_set::{self, BTreeSet};
47
48 /// Extension trait providing the `quote_into_iter` method on iterators.
49 pub trait RepIteratorExt: Iterator + Sized {
50 fn quote_into_iter(self) -> (Self, HasIter) {
51 (self, HasIter)
52 }
53 }
54
55 impl<T: Iterator> RepIteratorExt for T {}
56
57 /// Extension trait providing the `quote_into_iter` method for
58 /// non-iterable types. These types interpolate the same value in each
59 /// iteration of the repetition.
60 pub trait RepToTokensExt {
61 /// Pretend to be an iterator for the purposes of `quote_into_iter`.
62 /// This allows repeated calls to `quote_into_iter` to continue
63 /// correctly returning DoesNotHaveIter.
64 fn next(&self) -> Option<&Self> {
65 Some(self)
66 }
67
68 fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) {
69 (self, DoesNotHaveIter)
70 }
71 }
72
73 impl<T: ToTokens + ?Sized> RepToTokensExt for T {}
74
75 /// Extension trait providing the `quote_into_iter` method for types that
76 /// can be referenced as an iterator.
77 pub trait RepAsIteratorExt<'q> {
78 type Iter: Iterator;
79
80 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
81 }
82
83 impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a T {
84 type Iter = T::Iter;
85
86 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
87 <T as RepAsIteratorExt>::quote_into_iter(*self)
88 }
89 }
90
91 impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a mut T {
92 type Iter = T::Iter;
93
94 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
95 <T as RepAsIteratorExt>::quote_into_iter(*self)
96 }
97 }
98
99 impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
100 type Iter = slice::Iter<'q, T>;
101
102 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
103 (self.iter(), HasIter)
104 }
105 }
106
107 impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
108 type Iter = slice::Iter<'q, T>;
109
110 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
111 (self.iter(), HasIter)
112 }
113 }
114
115 impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
116 type Iter = btree_set::Iter<'q, T>;
117
118 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
119 (self.iter(), HasIter)
120 }
121 }
122
123 macro_rules! array_rep_slice {
124 ($($l:tt)*) => {
125 $(
126 impl<'q, T: 'q> RepAsIteratorExt<'q> for [T; $l] {
127 type Iter = slice::Iter<'q, T>;
128
129 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
130 (self.iter(), HasIter)
131 }
132 }
133 )*
134 }
135 }
136
137 array_rep_slice!(
138 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
139 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
140 );
141
142 impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
143 type Iter = T::Iter;
144
145 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
146 self.0.quote_into_iter()
147 }
148 }
149}
150
151// Helper type used within interpolations to allow for repeated binding names.
152// Implements the relevant traits, and exports a dummy `next()` method.
153#[derive(Copy, Clone)]
154pub struct RepInterp<T>(pub T);
155
156impl<T> RepInterp<T> {
157 // This method is intended to look like `Iterator::next`, and is called when
158 // a name is bound multiple times, as the previous binding will shadow the
159 // original `Iterator` object. This allows us to avoid advancing the
160 // iterator multiple times per iteration.
161 pub fn next(self) -> Option<T> {
162 Some(self.0)
163 }
164}
165
166impl<T: Iterator> Iterator for RepInterp<T> {
167 type Item = T::Item;
168
169 fn next(&mut self) -> Option<Self::Item> {
170 self.0.next()
171 }
172}
173
174impl<T: ToTokens> ToTokens for RepInterp<T> {
175 fn to_tokens(&self, tokens: &mut TokenStream) {
176 self.0.to_tokens(tokens);
177 }
178}
179
180pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
181 tokens.push_space();
182 tokens.push(delimiter.open());
183 tokens.combine(&inner);
184 tokens.push_space();
185 tokens.push(delimiter.close());
186}
187
188pub fn parse(tokens: &mut TokenStream, s: &str) {
189 tokens.push_space();
190 tokens.push_str(s);
191}
192
193pub fn push_ident(tokens: &mut TokenStream, s: &str) {
194 match tokens.0.chars().last() {
195 None | Some(':') => {}
196 _ => tokens.0.push(ch:' '),
197 }
198 tokens.push_str(s);
199}
200
201pub fn push_colon2(tokens: &mut TokenStream) {
202 match tokens.0.chars().last() {
203 Some(':') => tokens.push_str(" ::"),
204 _ => tokens.push_str("::"),
205 }
206}
207
208macro_rules! push_punct {
209 ($name:ident $char1:tt) => {
210 pub fn $name(tokens: &mut TokenStream) {
211 tokens.push_space();
212 tokens.push($char1);
213 }
214 };
215 ($name:ident $char1:tt $char2:tt) => {
216 pub fn $name(tokens: &mut TokenStream) {
217 tokens.push_space();
218 tokens.push($char1);
219 tokens.push($char2);
220 }
221 };
222 ($name:ident $char1:tt $char2:tt $char3:tt) => {
223 pub fn $name(tokens: &mut TokenStream) {
224 tokens.push(' ');
225 tokens.push($char1);
226 tokens.push($char2);
227 tokens.push($char3);
228 }
229 };
230}
231
232push_punct!(push_add '+');
233push_punct!(push_add_eq '+' '=');
234push_punct!(push_and '&');
235push_punct!(push_and_and '&' '&');
236push_punct!(push_and_eq '&' '=');
237push_punct!(push_at '@');
238push_punct!(push_bang '!');
239push_punct!(push_caret '^');
240push_punct!(push_caret_eq '^' '=');
241push_punct!(push_colon ':');
242push_punct!(push_comma ',');
243push_punct!(push_div '/');
244push_punct!(push_div_eq '/' '=');
245push_punct!(push_dot '.');
246push_punct!(push_dot2 '.' '.');
247push_punct!(push_dot3 '.' '.' '.');
248push_punct!(push_dot_dot_eq '.' '.' '=');
249push_punct!(push_eq '=');
250push_punct!(push_eq_eq '=' '=');
251push_punct!(push_ge '>' '=');
252push_punct!(push_gt '>');
253push_punct!(push_le '<' '=');
254push_punct!(push_lt '<');
255push_punct!(push_mul_eq '*' '=');
256push_punct!(push_ne '!' '=');
257push_punct!(push_or '|');
258push_punct!(push_or_eq '|' '=');
259push_punct!(push_or_or '|' '|');
260push_punct!(push_pound '#');
261push_punct!(push_question '?');
262push_punct!(push_rarrow '-' '>');
263push_punct!(push_larrow '<' '-');
264push_punct!(push_rem '%');
265push_punct!(push_rem_eq '%' '=');
266push_punct!(push_fat_arrow '=' '>');
267push_punct!(push_semi ';');
268push_punct!(push_shl '<' '<');
269push_punct!(push_shl_eq '<' '<' '=');
270push_punct!(push_shr '>' '>');
271push_punct!(push_shr_eq '>' '>' '=');
272push_punct!(push_star '*');
273push_punct!(push_sub '-');
274push_punct!(push_sub_eq '-' '=');
275