1 // SPDX-License-Identifier: Apache-2.0 OR MIT 2 3 use proc_macro::{TokenStream, TokenTree}; 4 5 #[allow(dead_code)] 6 pub(crate) trait ToTokens { to_tokens(&self, tokens: &mut TokenStream)7 fn to_tokens(&self, tokens: &mut TokenStream); 8 } 9 10 impl<T: ToTokens> ToTokens for Option<T> { to_tokens(&self, tokens: &mut TokenStream)11 fn to_tokens(&self, tokens: &mut TokenStream) { 12 if let Some(v) = self { 13 v.to_tokens(tokens); 14 } 15 } 16 } 17 18 impl ToTokens for proc_macro::Group { to_tokens(&self, tokens: &mut TokenStream)19 fn to_tokens(&self, tokens: &mut TokenStream) { 20 tokens.extend([TokenTree::from(self.clone())]); 21 } 22 } 23 24 impl ToTokens for proc_macro::Ident { to_tokens(&self, tokens: &mut TokenStream)25 fn to_tokens(&self, tokens: &mut TokenStream) { 26 tokens.extend([TokenTree::from(self.clone())]); 27 } 28 } 29 30 impl ToTokens for TokenTree { to_tokens(&self, tokens: &mut TokenStream)31 fn to_tokens(&self, tokens: &mut TokenStream) { 32 tokens.extend([self.clone()]); 33 } 34 } 35 36 impl ToTokens for TokenStream { to_tokens(&self, tokens: &mut TokenStream)37 fn to_tokens(&self, tokens: &mut TokenStream) { 38 tokens.extend(self.clone()); 39 } 40 } 41 42 /// Converts tokens into [`proc_macro::TokenStream`] and performs variable interpolations with 43 /// the given span. 44 /// 45 /// This is a similar to the 46 /// [`quote_spanned!`](https://docs.rs/quote/latest/quote/macro.quote_spanned.html) macro from the 47 /// `quote` crate but provides only just enough functionality needed by the current `macros` crate. 48 macro_rules! quote_spanned { 49 ($span:expr => $($tt:tt)*) => {{ 50 let mut tokens: ::std::vec::Vec<::proc_macro::TokenTree>; 51 #[allow(clippy::vec_init_then_push)] 52 { 53 tokens = ::std::vec::Vec::new(); 54 let span = $span; 55 quote_spanned!(@proc tokens span $($tt)*); 56 } 57 ::proc_macro::TokenStream::from_iter(tokens) 58 }}; 59 (@proc $v:ident $span:ident) => {}; 60 (@proc $v:ident $span:ident #$id:ident $($tt:tt)*) => { 61 let mut ts = ::proc_macro::TokenStream::new(); 62 $crate::quote::ToTokens::to_tokens(&$id, &mut ts); 63 $v.extend(ts); 64 quote_spanned!(@proc $v $span $($tt)*); 65 }; 66 (@proc $v:ident $span:ident #(#$id:ident)* $($tt:tt)*) => { 67 for token in $id { 68 let mut ts = ::proc_macro::TokenStream::new(); 69 $crate::quote::ToTokens::to_tokens(&token, &mut ts); 70 $v.extend(ts); 71 } 72 quote_spanned!(@proc $v $span $($tt)*); 73 }; 74 (@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => { 75 #[allow(unused_mut)] 76 let mut tokens = ::std::vec::Vec::<::proc_macro::TokenTree>::new(); 77 quote_spanned!(@proc tokens $span $($inner)*); 78 $v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new( 79 ::proc_macro::Delimiter::Parenthesis, 80 ::proc_macro::TokenStream::from_iter(tokens) 81 ))); 82 quote_spanned!(@proc $v $span $($tt)*); 83 }; 84 (@proc $v:ident $span:ident [ $($inner:tt)* ] $($tt:tt)*) => { 85 let mut tokens = ::std::vec::Vec::new(); 86 quote_spanned!(@proc tokens $span $($inner)*); 87 $v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new( 88 ::proc_macro::Delimiter::Bracket, 89 ::proc_macro::TokenStream::from_iter(tokens) 90 ))); 91 quote_spanned!(@proc $v $span $($tt)*); 92 }; 93 (@proc $v:ident $span:ident { $($inner:tt)* } $($tt:tt)*) => { 94 let mut tokens = ::std::vec::Vec::new(); 95 quote_spanned!(@proc tokens $span $($inner)*); 96 $v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new( 97 ::proc_macro::Delimiter::Brace, 98 ::proc_macro::TokenStream::from_iter(tokens) 99 ))); 100 quote_spanned!(@proc $v $span $($tt)*); 101 }; 102 (@proc $v:ident $span:ident :: $($tt:tt)*) => { 103 $v.push(::proc_macro::TokenTree::Punct( 104 ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Joint) 105 )); 106 $v.push(::proc_macro::TokenTree::Punct( 107 ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone) 108 )); 109 quote_spanned!(@proc $v $span $($tt)*); 110 }; 111 (@proc $v:ident $span:ident : $($tt:tt)*) => { 112 $v.push(::proc_macro::TokenTree::Punct( 113 ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone) 114 )); 115 quote_spanned!(@proc $v $span $($tt)*); 116 }; 117 (@proc $v:ident $span:ident , $($tt:tt)*) => { 118 $v.push(::proc_macro::TokenTree::Punct( 119 ::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone) 120 )); 121 quote_spanned!(@proc $v $span $($tt)*); 122 }; 123 (@proc $v:ident $span:ident @ $($tt:tt)*) => { 124 $v.push(::proc_macro::TokenTree::Punct( 125 ::proc_macro::Punct::new('@', ::proc_macro::Spacing::Alone) 126 )); 127 quote_spanned!(@proc $v $span $($tt)*); 128 }; 129 (@proc $v:ident $span:ident ! $($tt:tt)*) => { 130 $v.push(::proc_macro::TokenTree::Punct( 131 ::proc_macro::Punct::new('!', ::proc_macro::Spacing::Alone) 132 )); 133 quote_spanned!(@proc $v $span $($tt)*); 134 }; 135 (@proc $v:ident $span:ident ; $($tt:tt)*) => { 136 $v.push(::proc_macro::TokenTree::Punct( 137 ::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone) 138 )); 139 quote_spanned!(@proc $v $span $($tt)*); 140 }; 141 (@proc $v:ident $span:ident + $($tt:tt)*) => { 142 $v.push(::proc_macro::TokenTree::Punct( 143 ::proc_macro::Punct::new('+', ::proc_macro::Spacing::Alone) 144 )); 145 quote_spanned!(@proc $v $span $($tt)*); 146 }; 147 (@proc $v:ident $span:ident = $($tt:tt)*) => { 148 $v.push(::proc_macro::TokenTree::Punct( 149 ::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone) 150 )); 151 quote_spanned!(@proc $v $span $($tt)*); 152 }; 153 (@proc $v:ident $span:ident # $($tt:tt)*) => { 154 $v.push(::proc_macro::TokenTree::Punct( 155 ::proc_macro::Punct::new('#', ::proc_macro::Spacing::Alone) 156 )); 157 quote_spanned!(@proc $v $span $($tt)*); 158 }; 159 (@proc $v:ident $span:ident _ $($tt:tt)*) => { 160 $v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new("_", $span))); 161 quote_spanned!(@proc $v $span $($tt)*); 162 }; 163 (@proc $v:ident $span:ident $id:ident $($tt:tt)*) => { 164 $v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span))); 165 quote_spanned!(@proc $v $span $($tt)*); 166 }; 167 } 168 169 /// Converts tokens into [`proc_macro::TokenStream`] and performs variable interpolations with 170 /// mixed site span ([`Span::mixed_site()`]). 171 /// 172 /// This is a similar to the [`quote!`](https://docs.rs/quote/latest/quote/macro.quote.html) macro 173 /// from the `quote` crate but provides only just enough functionality needed by the current 174 /// `macros` crate. 175 /// 176 /// [`Span::mixed_site()`]: https://doc.rust-lang.org/proc_macro/struct.Span.html#method.mixed_site 177 macro_rules! quote { 178 ($($tt:tt)*) => { 179 quote_spanned!(::proc_macro::Span::mixed_site() => $($tt)*) 180 } 181 } 182