1use core::{iter::once, mem::take};
2use std::convert::identity;
3
4use crate::{
5 puncts, puncts_spanned, ParseIter, ParseIterExt as _, SetSpan as _,
6 TokenKind,
7};
8use proc_macro::{
9 Delimiter, Group, Ident, Literal, Punct,
10 Spacing::{self, *},
11 Span, TokenStream, TokenTree,
12};
13
14pub trait StreamIterExt: Iterator + Sized {
15 fn join<I>(self, sep: I) -> TokenStream
16 where I: Clone,
17 TokenStream: Extend<I> + Extend<Self::Item>,
18 {
19 self.map(Ok::<_, ()>)
20 .try_join(sep)
21 .unwrap()
22 }
23
24 fn try_join<I, T, E>(mut self, sep: I) -> Result<TokenStream, E>
25 where Self: Iterator<Item = Result<T, E>>,
26 I: Clone,
27 TokenStream: Extend<I> + Extend<T>,
28 {
29 let mut result = TokenStream::new();
30
31 if let Some(first) = self.next() {
32 result.extend(once(first?));
33
34 for rest in self {
35 result.extend(once(sep.clone()));
36 result.extend(once(rest?));
37 }
38 }
39
40 Ok(result)
41 }
42}
43impl<T: Iterator> StreamIterExt for T { }
44
45pub trait TokenStreamExt
46 : Default
47 + Extend<TokenTree>
48 + Extend<TokenStream>
49 + IntoIterator<Item = TokenTree>
50 + Sized
51{
52 fn push(&mut self, tt: TokenTree) -> &mut Self {
54 self.extend(once(tt));
55 self
56 }
57
58 fn add(&mut self, stream: TokenStream) -> &mut Self {
60 self.extend(once(stream));
61 self
62 }
63
64 #[must_use]
66 fn take(&mut self) -> Self {
67 take(self)
68 }
69
70 fn grouped(self, delimiter: Delimiter) -> Group;
72
73 fn grouped_paren(self) -> Group {
74 self.grouped(Delimiter::Parenthesis)
75 }
76
77 fn grouped_brace(self) -> Group {
78 self.grouped(Delimiter::Brace)
79 }
80
81 fn grouped_bracket(self) -> Group {
82 self.grouped(Delimiter::Bracket)
83 }
84
85 fn grouped_none(self) -> Group {
86 self.grouped(Delimiter::None)
87 }
88
89 fn split_puncts(self, puncts: impl AsRef<[u8]>) -> Option<(
93 Self,
94 ParseIter<Self::IntoIter>,
95 )>;
96
97 fn split_puncts_all(self, puncts: impl AsRef<[u8]>) -> Vec<Self>;
101}
102impl TokenStreamExt for TokenStream {
103 fn grouped(self, delimiter: Delimiter) -> Group {
104 Group::new(delimiter, self)
105 }
106
107 fn split_puncts(self, puncts: impl AsRef<[u8]>) -> Option<(
108 Self,
109 ParseIter<Self::IntoIter>,
110 )>
111 {
112 let mut iter = self.parse_iter();
113 Some((iter.split_puncts(puncts)?, iter))
114 }
115
116 fn split_puncts_all(self, puncts: impl AsRef<[u8]>) -> Vec<Self> {
117 self.parse_iter()
118 .split_puncts_all(puncts)
119 .collect()
120 }
121
122}
123
124pub trait WalkExt
126 : IntoIterator<Item = TokenTree>
127 + FromIterator<TokenTree>
128{
129 #[must_use]
133 fn walk<F>(self, mut f: F) -> Self
134 where F: FnMut(TokenTree) -> TokenTree
135 {
136 fn walk_impl<I, F>(this: I, f: &mut F) -> I
137 where I: IntoIterator<Item = TokenTree> + FromIterator<TokenTree>,
138 F: FnMut(TokenTree) -> TokenTree
139 {
140 this.into_iter()
141 .map(|tt| {
142 let tt = match tt {
143 TokenTree::Group(g) => {
144 g.map(|this| walk_impl(this, f)).tt()
145 },
146 _ => tt,
147 };
148 f(tt)
149 })
150 .collect()
151 }
152 walk_impl(self, &mut f)
153 }
154}
155impl<I: IntoIterator<Item = TokenTree> + FromIterator<TokenTree>> WalkExt for I { }
156
157pub trait TokenTreeExt: Into<TokenTree> + Sized {
158 fn as_ident(&self) -> Option<&Ident> { None }
159 fn as_punct(&self) -> Option<&Punct> { None }
160 fn as_group(&self) -> Option<&Group> { None }
161 fn as_literal(&self) -> Option<&Literal> { None }
162 fn into_ident(self) -> Result<Ident, Self> { Err(self) }
163 fn into_punct(self) -> Result<Punct, Self> { Err(self) }
164 fn into_group(self) -> Result<Group, Self> { Err(self) }
165 fn into_literal(self) -> Result<Literal, Self> { Err(self) }
166
167 fn to_ident(&self) -> Result<&Ident, &Self> {
168 self.as_ident().ok_or(self)
169 }
170
171 fn to_punct(&self) -> Result<&Punct, &Self> {
172 self.as_punct().ok_or(self)
173 }
174
175 fn to_group(&self) -> Result<&Group, &Self> {
176 self.as_group().ok_or(self)
177 }
178
179 fn to_literal(&self) -> Result<&Literal, &Self> {
180 self.as_literal().ok_or(self)
181 }
182
183 fn is_ident(&self) -> bool {
184 self.as_ident().is_some()
185 }
186
187 fn is_punct(&self) -> bool {
188 self.as_punct().is_some()
189 }
190
191 fn is_group(&self) -> bool {
192 self.as_group().is_some()
193 }
194
195 fn is_literal(&self) -> bool {
196 self.as_literal().is_some()
197 }
198
199 #[allow(clippy::return_self_not_must_use)]
200 fn map_ident<F: FnOnce(Ident) -> R, R: Into<Self>>(self, op: F) -> Self {
201 self.into_ident()
202 .map(op)
203 .map_or_else(identity, Into::into)
204 }
205
206 #[allow(clippy::return_self_not_must_use)]
207 fn map_punct<F: FnOnce(Punct) -> R, R: Into<Self>>(self, op: F) -> Self {
208 self.into_punct()
209 .map(op)
210 .map_or_else(identity, Into::into)
211 }
212
213 #[allow(clippy::return_self_not_must_use)]
214 fn map_group<F: FnOnce(Group) -> R, R: Into<Self>>(self, op: F) -> Self {
215 self.into_group()
216 .map(op)
217 .map_or_else(identity, Into::into)
218 }
219
220 #[allow(clippy::return_self_not_must_use)]
221 fn map_literal<F: FnOnce(Literal) -> R, R: Into<Self>>(self, op: F) -> Self {
222 self.into_literal()
223 .map(op)
224 .map_or_else(identity, Into::into)
225 }
226
227 fn kind(&self) -> TokenKind {
228 if self.is_literal() {
229 TokenKind::Literal
230 } else if self.is_punct() {
231 TokenKind::Punct
232 } else if self.is_group() {
233 TokenKind::Group
234 } else if self.is_ident() {
235 TokenKind::Ident
236 } else {
237 unimplemented!()
238 }
239 }
240
241 fn is_keyword(&self, keyword: &str) -> bool {
245 self.as_ident().is_some_and(|i| i.to_string() == keyword)
246 }
247
248 fn is_punch(&self, ch: char) -> bool {
252 self.as_punct().is_some_and(|p| p.as_char() == ch)
253 }
254
255 fn is_solid_group(&self) -> bool {
259 self.as_group().is_some_and(|g| g.is_solid_group())
260 }
261
262 fn is_delimiter(&self, delimiter: Delimiter) -> bool {
266 self.as_group().is_some_and(|g| g.is_delimiter(delimiter))
267 }
268
269 fn is_delimiter_paren(&self) -> bool {
271 self.is_delimiter(Delimiter::Parenthesis)
272 }
273
274 fn is_delimiter_brace(&self) -> bool {
276 self.is_delimiter(Delimiter::Brace)
277 }
278
279 fn is_delimiter_bracket(&self) -> bool {
281 self.is_delimiter(Delimiter::Bracket)
282 }
283
284 fn is_delimiter_none(&self) -> bool {
286 self.is_delimiter(Delimiter::None)
287 }
288
289 fn to_paren_stream(&self) -> Result<TokenStream, &Self> {
295 self.as_group()
296 .and_then(|g| g.is_delimiter_paren().then(|| g.stream()))
297 .ok_or(self)
298 }
299
300 fn to_brace_stream(&self) -> Result<TokenStream, &Self> {
306 self.as_group()
307 .and_then(|g| g.is_delimiter_brace().then(|| g.stream()))
308 .ok_or(self)
309 }
310
311 fn to_bracket_stream(&self) -> Result<TokenStream, &Self> {
317 self.as_group()
318 .and_then(|g| g.is_delimiter_bracket().then(|| g.stream()))
319 .ok_or(self)
320 }
321
322 fn to_none_stream(&self) -> Result<TokenStream, &Self> {
328 self.as_group()
329 .and_then(|g| g.is_delimiter_none().then(|| g.stream()))
330 .ok_or(self)
331 }
332
333 fn into_paren_stream(self) -> Result<TokenStream, Self> {
336 self.to_paren_stream()
337 .ok().ok_or(self)
338 }
339
340 fn into_brace_stream(self) -> Result<TokenStream, Self> {
343 self.to_brace_stream()
344 .ok().ok_or(self)
345 }
346
347 fn into_bracket_stream(self) -> Result<TokenStream, Self> {
350 self.to_bracket_stream()
351 .ok().ok_or(self)
352 }
353
354 fn into_none_stream(self) -> Result<TokenStream, Self> {
357 self.to_none_stream()
358 .ok().ok_or(self)
359 }
360
361 fn is_joint(&self) -> bool {
365 self.as_punct().is_some_and(|p| p.spacing() == Joint)
366 }
367
368 fn as_punct_char(&self) -> Option<char> {
369 self.as_punct().map(|p| p.as_char())
370 }
371
372 fn tt(self) -> TokenTree {
376 self.into()
377 }
378
379 fn unit_stream(self) -> TokenStream {
381 self.tt().into()
382 }
383}
384impl TokenTreeExt for TokenTree {
385 fn as_ident(&self) -> Option<&Ident> {
386 match self {
387 TokenTree::Ident(i) => Some(i),
388 _ => None,
389 }
390 }
391
392 fn as_punct(&self) -> Option<&Punct> {
393 match self {
394 TokenTree::Punct(i) => Some(i),
395 _ => None,
396 }
397 }
398
399 fn as_group(&self) -> Option<&Group> {
400 match self {
401 TokenTree::Group(i) => Some(i),
402 _ => None,
403 }
404 }
405
406 fn as_literal(&self) -> Option<&Literal> {
407 match self {
408 TokenTree::Literal(i) => Some(i),
409 _ => None,
410 }
411 }
412
413 fn into_ident(self) -> Result<Ident, Self> {
414 match self {
415 TokenTree::Ident(i) => Ok(i),
416 _ => Err(self),
417 }
418 }
419
420 fn into_punct(self) -> Result<Punct, Self> {
421 match self {
422 TokenTree::Punct(i) => Ok(i),
423 _ => Err(self),
424 }
425 }
426
427 fn into_group(self) -> Result<Group, Self> {
428 match self {
429 TokenTree::Group(i) => Ok(i),
430 _ => Err(self),
431 }
432 }
433
434 fn into_literal(self) -> Result<Literal, Self> {
435 match self {
436 TokenTree::Literal(i) => Ok(i),
437 _ => Err(self),
438 }
439 }
440
441 fn kind(&self) -> TokenKind {
442 self.into()
443 }
444}
445macro_rules! impl_token_tree_ext {
446 ($as:ident, $into:ident, $ty:ident) => {
447 impl TokenTreeExt for $ty {
448 fn $as(&self) -> Option<&$ty> {
449 Some(self)
450 }
451 fn $into(self) -> Result<$ty, Self> {
452 Ok(self)
453 }
454 fn kind(&self) -> TokenKind {
455 TokenKind::$ty
456 }
457 }
458 };
459}
460impl_token_tree_ext!(as_ident, into_ident, Ident);
461impl_token_tree_ext!(as_punct, into_punct, Punct);
462impl_token_tree_ext!(as_literal, into_literal, Literal);
463impl TokenTreeExt for Group {
464 fn as_group(&self) -> Option<&Group> {
465 Some(self)
466 }
467
468 fn into_group(self) -> Result<Group, Self> {
469 Ok(self)
470 }
471
472 fn kind(&self) -> TokenKind {
473 TokenKind::Group
474 }
475
476 fn is_solid_group(&self) -> bool {
477 self.delimiter() != Delimiter::None
478 }
479
480 fn is_delimiter(&self, delimiter: Delimiter) -> bool {
481 self.delimiter() == delimiter
482 }
483}
484
485pub trait Unsuffixed {
487 fn unsuffixed(self) -> Literal;
488}
489pub trait Suffixed {
491 fn suffixed(self) -> Literal;
492}
493macro_rules! impl_unsuffixes {
494 ( $($ty:ty: $unsuffixed:ident $($suffixed:ident)?);+ $(;)? ) => {
495 $(
496 #[doc = concat!(
497 "Call [`Literal::",
498 stringify!($unsuffixed),
499 "`]",
500 )]
501 impl Unsuffixed for $ty {
502 fn unsuffixed(self) -> Literal {
503 Literal::$unsuffixed(self)
504 }
505 }
506
507 $(
508 #[doc = concat!(
509 "Call [`Literal::",
510 stringify!($suffixed),
511 "`]",
512 )]
513 impl Suffixed for $ty {
514 fn suffixed(self) -> Literal {
515 Literal::$suffixed(self)
516 }
517 }
518 )?
519 )*
520 };
521}
522impl_unsuffixes! {
523 i8: i8_unsuffixed i8_suffixed;
524 i16: i16_unsuffixed i16_suffixed;
525 i32: i32_unsuffixed i32_suffixed;
526 i64: i64_unsuffixed i64_suffixed;
527 i128: i128_unsuffixed i128_suffixed;
528 u8: u8_unsuffixed u8_suffixed;
529 u16: u16_unsuffixed u16_suffixed;
530 u32: u32_unsuffixed u32_suffixed;
531 u64: u64_unsuffixed u64_suffixed;
532 u128: u128_unsuffixed u128_suffixed;
533 f32: f32_unsuffixed f32_suffixed;
534 f64: f64_unsuffixed f64_suffixed;
535 usize: usize_unsuffixed usize_suffixed;
536 isize: isize_unsuffixed isize_suffixed;
537 char: character;
538 &str: string;
539 &[u8]: byte_string;
540}
541
542pub trait PunctsExt: AsRef<[u8]> {
543 fn puncts(&self) -> TokenStream {
545 puncts(self)
546 }
547
548 fn puncts_spanned(&self, span: Span) -> TokenStream {
550 puncts_spanned(self, span)
551 }
552}
553impl<T: AsRef<[u8]> + ?Sized> PunctsExt for T { }
554
555pub trait PunctExt: Sized {
556 fn punct(self, spacing: Spacing) -> Punct;
557
558 fn joint(self) -> Punct {
560 self.punct(Joint)
561 }
562
563 fn alone(self) -> Punct {
565 self.punct(Alone)
566 }
567}
568impl PunctExt for char {
569 fn punct(self, spacing: Spacing) -> Punct {
571 Punct::new(self, spacing)
572 }
573}
574
575pub trait StrExt {
576 fn ident(&self, span: Span) -> Ident;
577}
578impl StrExt for str {
579 fn ident(&self, span: Span) -> Ident {
581 Ident::new(self, span)
582 }
583}
584
585pub trait GroupExt {
586 #[must_use]
587 fn map<F>(&self, f: F) -> Self
588 where F: FnOnce(TokenStream) -> TokenStream;
589}
590impl GroupExt for Group {
591 fn map<F>(&self, f: F) -> Self
592 where F: FnOnce(TokenStream) -> TokenStream,
593 {
594 f(self.stream())
595 .grouped(self.delimiter())
596 .set_spaned(self.span())
597 }
598}
599
600pub trait SpacingExt {
602 #[doc(hidden)]
604 #[deprecated = "renaming to `punch`"]
605 fn punct(self, ch: char) -> Punct where Self: Sized {
606 self.punch(ch)
607 }
608
609 fn punch(self, ch: char) -> Punct where Self: Sized {
611 #[allow(deprecated)]
612 self.punct(ch)
613 }
614
615 fn is_joint(&self) -> bool;
617
618 fn is_alone(&self) -> bool;
620}
621impl SpacingExt for Spacing {
622 fn punch(self, ch: char) -> Punct {
623 Punct::new(ch, self)
624 }
625
626 fn is_joint(&self) -> bool {
627 *self == Joint
628 }
629
630 fn is_alone(&self) -> bool {
631 *self == Alone
632 }
633}