pin_init_internal/macros/
quote.rs

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