pin_init_internal/macros/
quote.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3use proc_macro::{TokenStream, TokenTree};
4
5#[allow(dead_code)]
6pub(crate) trait ToTokens {
7    fn to_tokens(&self, tokens: &mut TokenStream);
8}
9
10impl<T: ToTokens> ToTokens for Option<T> {
11    fn to_tokens(&self, tokens: &mut TokenStream) {
12        if let Some(v) = self {
13            v.to_tokens(tokens);
14        }
15    }
16}
17
18impl ToTokens for proc_macro::Group {
19    fn to_tokens(&self, tokens: &mut TokenStream) {
20        tokens.extend([TokenTree::from(self.clone())]);
21    }
22}
23
24impl ToTokens for proc_macro::Ident {
25    fn to_tokens(&self, tokens: &mut TokenStream) {
26        tokens.extend([TokenTree::from(self.clone())]);
27    }
28}
29
30impl ToTokens for TokenTree {
31    fn to_tokens(&self, tokens: &mut TokenStream) {
32        tokens.extend([self.clone()]);
33    }
34}
35
36impl ToTokens for 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.
48macro_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
177macro_rules! quote {
178    ($($tt:tt)*) => {
179        quote_spanned!(::proc_macro::Span::mixed_site() => $($tt)*)
180    }
181}