1 | use super::{Delimiter, ToTokens, TokenStream}; |
2 | use core::ops::BitOr; |
3 | |
4 | pub struct HasIterator; // True |
5 | pub struct ThereIsNoIteratorInRepetition; // False |
6 | |
7 | impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition { |
8 | type Output = ThereIsNoIteratorInRepetition; |
9 | fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition { |
10 | ThereIsNoIteratorInRepetition |
11 | } |
12 | } |
13 | |
14 | impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator { |
15 | type Output = HasIterator; |
16 | fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator { |
17 | HasIterator |
18 | } |
19 | } |
20 | |
21 | impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition { |
22 | type Output = HasIterator; |
23 | fn bitor(self, _rhs: HasIterator) -> HasIterator { |
24 | HasIterator |
25 | } |
26 | } |
27 | |
28 | impl 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. |
41 | pub 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)] |
154 | pub struct RepInterp<T>(pub T); |
155 | |
156 | impl<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 | |
166 | impl<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 | |
174 | impl<T: ToTokens> ToTokens for RepInterp<T> { |
175 | fn to_tokens(&self, tokens: &mut TokenStream) { |
176 | self.0.to_tokens(tokens); |
177 | } |
178 | } |
179 | |
180 | pub 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 | |
188 | pub fn parse(tokens: &mut TokenStream, s: &str) { |
189 | tokens.push_space(); |
190 | tokens.push_str(s); |
191 | } |
192 | |
193 | pub 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 | |
201 | pub fn push_colon2(tokens: &mut TokenStream) { |
202 | match tokens.0.chars().last() { |
203 | Some(':' ) => tokens.push_str(" ::" ), |
204 | _ => tokens.push_str("::" ), |
205 | } |
206 | } |
207 | |
208 | macro_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 | |
232 | push_punct!(push_add '+' ); |
233 | push_punct!(push_add_eq '+' '=' ); |
234 | push_punct!(push_and '&' ); |
235 | push_punct!(push_and_and '&' '&' ); |
236 | push_punct!(push_and_eq '&' '=' ); |
237 | push_punct!(push_at '@' ); |
238 | push_punct!(push_bang '!' ); |
239 | push_punct!(push_caret '^' ); |
240 | push_punct!(push_caret_eq '^' '=' ); |
241 | push_punct!(push_colon ':' ); |
242 | push_punct!(push_comma ',' ); |
243 | push_punct!(push_div '/' ); |
244 | push_punct!(push_div_eq '/' '=' ); |
245 | push_punct!(push_dot '.' ); |
246 | push_punct!(push_dot2 '.' '.' ); |
247 | push_punct!(push_dot3 '.' '.' '.' ); |
248 | push_punct!(push_dot_dot_eq '.' '.' '=' ); |
249 | push_punct!(push_eq '=' ); |
250 | push_punct!(push_eq_eq '=' '=' ); |
251 | push_punct!(push_ge '>' '=' ); |
252 | push_punct!(push_gt '>' ); |
253 | push_punct!(push_le '<' '=' ); |
254 | push_punct!(push_lt '<' ); |
255 | push_punct!(push_mul_eq '*' '=' ); |
256 | push_punct!(push_ne '!' '=' ); |
257 | push_punct!(push_or '|' ); |
258 | push_punct!(push_or_eq '|' '=' ); |
259 | push_punct!(push_or_or '|' '|' ); |
260 | push_punct!(push_pound '#' ); |
261 | push_punct!(push_question '?' ); |
262 | push_punct!(push_rarrow '-' '>' ); |
263 | push_punct!(push_larrow '<' '-' ); |
264 | push_punct!(push_rem '%' ); |
265 | push_punct!(push_rem_eq '%' '=' ); |
266 | push_punct!(push_fat_arrow '=' '>' ); |
267 | push_punct!(push_semi ';' ); |
268 | push_punct!(push_shl '<' '<' ); |
269 | push_punct!(push_shl_eq '<' '<' '=' ); |
270 | push_punct!(push_shr '>' '>' ); |
271 | push_punct!(push_shr_eq '>' '>' '=' ); |
272 | push_punct!(push_star '*' ); |
273 | push_punct!(push_sub '-' ); |
274 | push_punct!(push_sub_eq '-' '=' ); |
275 | |