use self::get_span::{GetSpan, GetSpanBase, GetSpanInner}; use crate::{IdentFragment, ToTokens, TokenStreamExt}; use core::fmt; use core::iter; use core::ops::BitOr; use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree}; pub use alloc::format; pub use core::option::Option; pub use proc_macro2::{Delimiter, Span, TokenStream}; pub struct HasIterator; // True pub struct ThereIsNoIteratorInRepetition; // False impl BitOr for ThereIsNoIteratorInRepetition { type Output = ThereIsNoIteratorInRepetition; fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition { ThereIsNoIteratorInRepetition } } impl BitOr for HasIterator { type Output = HasIterator; fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator { HasIterator } } impl BitOr for ThereIsNoIteratorInRepetition { type Output = HasIterator; fn bitor(self, _rhs: HasIterator) -> HasIterator { HasIterator } } impl BitOr for HasIterator { type Output = HasIterator; fn bitor(self, _rhs: HasIterator) -> HasIterator { HasIterator } } /// Extension traits used by the implementation of `quote!`. These are defined /// in separate traits, rather than as a single trait due to ambiguity issues. /// /// These traits expose a `quote_into_iter` method which should allow calling /// whichever impl happens to be applicable. Calling that method repeatedly on /// the returned value should be idempotent. pub mod ext { use super::RepInterp; use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter}; use crate::ToTokens; use alloc::collections::btree_set::{self, BTreeSet}; use core::slice; /// Extension trait providing the `quote_into_iter` method on iterators. pub trait RepIteratorExt: Iterator + Sized { fn quote_into_iter(self) -> (Self, HasIter) { (self, HasIter) } } impl RepIteratorExt for T {} /// Extension trait providing the `quote_into_iter` method for /// non-iterable types. These types interpolate the same value in each /// iteration of the repetition. pub trait RepToTokensExt { /// Pretend to be an iterator for the purposes of `quote_into_iter`. /// This allows repeated calls to `quote_into_iter` to continue /// correctly returning DoesNotHaveIter. fn next(&self) -> Option<&Self> { Some(self) } fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) { (self, DoesNotHaveIter) } } impl RepToTokensExt for T {} /// Extension trait providing the `quote_into_iter` method for types that /// can be referenced as an iterator. pub trait RepAsIteratorExt<'q> { type Iter: Iterator; fn quote_into_iter(&'q self) -> (Self::Iter, HasIter); } impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a T { type Iter = T::Iter; fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { ::quote_into_iter(*self) } } impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a mut T { type Iter = T::Iter; fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { ::quote_into_iter(*self) } } impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] { type Iter = slice::Iter<'q, T>; fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { (self.iter(), HasIter) } } impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec { type Iter = slice::Iter<'q, T>; fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { (self.iter(), HasIter) } } impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet { type Iter = btree_set::Iter<'q, T>; fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { (self.iter(), HasIter) } } impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp { type Iter = T::Iter; fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { self.0.quote_into_iter() } } } // Helper type used within interpolations to allow for repeated binding names. // Implements the relevant traits, and exports a dummy `next()` method. #[derive(Copy, Clone)] pub struct RepInterp(pub T); impl RepInterp { // This method is intended to look like `Iterator::next`, and is called when // a name is bound multiple times, as the previous binding will shadow the // original `Iterator` object. This allows us to avoid advancing the // iterator multiple times per iteration. pub fn next(self) -> Option { Some(self.0) } } impl Iterator for RepInterp { type Item = T::Item; fn next(&mut self) -> Option { self.0.next() } } impl ToTokens for RepInterp { fn to_tokens(&self, tokens: &mut TokenStream) { self.0.to_tokens(tokens); } } #[inline] pub fn get_span(span: T) -> GetSpan { GetSpan(GetSpanInner(GetSpanBase(span))) } mod get_span { use core::ops::Deref; use proc_macro2::extra::DelimSpan; use proc_macro2::Span; pub struct GetSpan(pub(crate) GetSpanInner); pub struct GetSpanInner(pub(crate) GetSpanBase); pub struct GetSpanBase(pub(crate) T); impl GetSpan { #[inline] pub fn __into_span(self) -> Span { ((self.0).0).0 } } impl GetSpanInner { #[inline] pub fn __into_span(&self) -> Span { (self.0).0.join() } } impl GetSpanBase { #[allow(clippy::unused_self)] pub fn __into_span(&self) -> T { unreachable!() } } impl Deref for GetSpan { type Target = GetSpanInner; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl Deref for GetSpanInner { type Target = GetSpanBase; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } } pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) { tokens.append(Group::new(delimiter, inner)); } pub fn push_group_spanned( tokens: &mut TokenStream, span: Span, delimiter: Delimiter, inner: TokenStream, ) { let mut g = Group::new(delimiter, inner); g.set_span(span); tokens.append(g); } pub fn parse(tokens: &mut TokenStream, s: &str) { let s: TokenStream = s.parse().expect("invalid token stream"); tokens.extend(iter::once(s)); } pub fn parse_spanned(tokens: &mut TokenStream, span: Span, s: &str) { let s: TokenStream = s.parse().expect("invalid token stream"); tokens.extend(s.into_iter().map(|t| respan_token_tree(t, span))); } // Token tree with every span replaced by the given one. fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree { match &mut token { TokenTree::Group(g) => { let stream = g .stream() .into_iter() .map(|token| respan_token_tree(token, span)) .collect(); *g = Group::new(g.delimiter(), stream); g.set_span(span); } other => other.set_span(span), } token } pub fn push_ident(tokens: &mut TokenStream, s: &str) { let span = Span::call_site(); push_ident_spanned(tokens, span, s); } pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) { tokens.append(ident_maybe_raw(s, span)); } pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) { struct Lifetime<'a> { name: &'a str, state: u8, } impl<'a> Iterator for Lifetime<'a> { type Item = TokenTree; fn next(&mut self) -> Option { match self.state { 0 => { self.state = 1; Some(TokenTree::Punct(Punct::new('\'', Spacing::Joint))) } 1 => { self.state = 2; Some(TokenTree::Ident(Ident::new(self.name, Span::call_site()))) } _ => None, } } } tokens.extend(Lifetime { name: &lifetime[1..], state: 0, }); } pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str) { struct Lifetime<'a> { name: &'a str, span: Span, state: u8, } impl<'a> Iterator for Lifetime<'a> { type Item = TokenTree; fn next(&mut self) -> Option { match self.state { 0 => { self.state = 1; let mut apostrophe = Punct::new('\'', Spacing::Joint); apostrophe.set_span(self.span); Some(TokenTree::Punct(apostrophe)) } 1 => { self.state = 2; Some(TokenTree::Ident(Ident::new(self.name, self.span))) } _ => None, } } } tokens.extend(Lifetime { name: &lifetime[1..], span, state: 0, }); } macro_rules! push_punct { ($name:ident $spanned:ident $char1:tt) => { pub fn $name(tokens: &mut TokenStream) { tokens.append(Punct::new($char1, Spacing::Alone)); } pub fn $spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new($char1, Spacing::Alone); punct.set_span(span); tokens.append(punct); } }; ($name:ident $spanned:ident $char1:tt $char2:tt) => { pub fn $name(tokens: &mut TokenStream) { tokens.append(Punct::new($char1, Spacing::Joint)); tokens.append(Punct::new($char2, Spacing::Alone)); } pub fn $spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new($char1, Spacing::Joint); punct.set_span(span); tokens.append(punct); let mut punct = Punct::new($char2, Spacing::Alone); punct.set_span(span); tokens.append(punct); } }; ($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => { pub fn $name(tokens: &mut TokenStream) { tokens.append(Punct::new($char1, Spacing::Joint)); tokens.append(Punct::new($char2, Spacing::Joint)); tokens.append(Punct::new($char3, Spacing::Alone)); } pub fn $spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new($char1, Spacing::Joint); punct.set_span(span); tokens.append(punct); let mut punct = Punct::new($char2, Spacing::Joint); punct.set_span(span); tokens.append(punct); let mut punct = Punct::new($char3, Spacing::Alone); punct.set_span(span); tokens.append(punct); } }; } push_punct!(push_add push_add_spanned '+'); push_punct!(push_add_eq push_add_eq_spanned '+' '='); push_punct!(push_and push_and_spanned '&'); push_punct!(push_and_and push_and_and_spanned '&' '&'); push_punct!(push_and_eq push_and_eq_spanned '&' '='); push_punct!(push_at push_at_spanned '@'); push_punct!(push_bang push_bang_spanned '!'); push_punct!(push_caret push_caret_spanned '^'); push_punct!(push_caret_eq push_caret_eq_spanned '^' '='); push_punct!(push_colon push_colon_spanned ':'); push_punct!(push_colon2 push_colon2_spanned ':' ':'); push_punct!(push_comma push_comma_spanned ','); push_punct!(push_div push_div_spanned '/'); push_punct!(push_div_eq push_div_eq_spanned '/' '='); push_punct!(push_dot push_dot_spanned '.'); push_punct!(push_dot2 push_dot2_spanned '.' '.'); push_punct!(push_dot3 push_dot3_spanned '.' '.' '.'); push_punct!(push_dot_dot_eq push_dot_dot_eq_spanned '.' '.' '='); push_punct!(push_eq push_eq_spanned '='); push_punct!(push_eq_eq push_eq_eq_spanned '=' '='); push_punct!(push_ge push_ge_spanned '>' '='); push_punct!(push_gt push_gt_spanned '>'); push_punct!(push_le push_le_spanned '<' '='); push_punct!(push_lt push_lt_spanned '<'); push_punct!(push_mul_eq push_mul_eq_spanned '*' '='); push_punct!(push_ne push_ne_spanned '!' '='); push_punct!(push_or push_or_spanned '|'); push_punct!(push_or_eq push_or_eq_spanned '|' '='); push_punct!(push_or_or push_or_or_spanned '|' '|'); push_punct!(push_pound push_pound_spanned '#'); push_punct!(push_question push_question_spanned '?'); push_punct!(push_rarrow push_rarrow_spanned '-' '>'); push_punct!(push_larrow push_larrow_spanned '<' '-'); push_punct!(push_rem push_rem_spanned '%'); push_punct!(push_rem_eq push_rem_eq_spanned '%' '='); push_punct!(push_fat_arrow push_fat_arrow_spanned '=' '>'); push_punct!(push_semi push_semi_spanned ';'); push_punct!(push_shl push_shl_spanned '<' '<'); push_punct!(push_shl_eq push_shl_eq_spanned '<' '<' '='); push_punct!(push_shr push_shr_spanned '>' '>'); push_punct!(push_shr_eq push_shr_eq_spanned '>' '>' '='); push_punct!(push_star push_star_spanned '*'); push_punct!(push_sub push_sub_spanned '-'); push_punct!(push_sub_eq push_sub_eq_spanned '-' '='); pub fn push_underscore(tokens: &mut TokenStream) { push_underscore_spanned(tokens, Span::call_site()); } pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) { tokens.append(Ident::new("_", span)); } // Helper method for constructing identifiers from the `format_ident!` macro, // handling `r#` prefixes. pub fn mk_ident(id: &str, span: Option) -> Ident { let span = span.unwrap_or_else(Span::call_site); ident_maybe_raw(id, span) } fn ident_maybe_raw(id: &str, span: Span) -> Ident { if let Some(id) = id.strip_prefix("r#") { Ident::new_raw(id, span) } else { Ident::new(id, span) } } // Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!` // macro, and exposes span information from these fragments. // // This struct also has forwarding implementations of the formatting traits // `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within // `format_ident!`. #[derive(Copy, Clone)] pub struct IdentFragmentAdapter(pub T); impl IdentFragmentAdapter { pub fn span(&self) -> Option { self.0.span() } } impl fmt::Display for IdentFragmentAdapter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { IdentFragment::fmt(&self.0, f) } } impl fmt::Octal for IdentFragmentAdapter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Octal::fmt(&self.0, f) } } impl fmt::LowerHex for IdentFragmentAdapter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) } } impl fmt::UpperHex for IdentFragmentAdapter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) } } impl fmt::Binary for IdentFragmentAdapter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Binary::fmt(&self.0, f) } }