| 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, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &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, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &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 | |