1 | use super::TokenStreamExt; |
2 | use alloc::borrow::Cow; |
3 | use alloc::rc::Rc; |
4 | use core::iter; |
5 | use proc_macro2::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree}; |
6 | use std::ffi::{CStr, CString}; |
7 | |
8 | /// Types that can be interpolated inside a `quote!` invocation. |
9 | pub trait ToTokens { |
10 | /// Write `self` to the given `TokenStream`. |
11 | /// |
12 | /// The token append methods provided by the [`TokenStreamExt`] extension |
13 | /// trait may be useful for implementing `ToTokens`. |
14 | /// |
15 | /// # Example |
16 | /// |
17 | /// Example implementation for a struct representing Rust paths like |
18 | /// `std::cmp::PartialEq`: |
19 | /// |
20 | /// ``` |
21 | /// use proc_macro2::{TokenTree, Spacing, Span, Punct, TokenStream}; |
22 | /// use quote::{TokenStreamExt, ToTokens}; |
23 | /// |
24 | /// pub struct Path { |
25 | /// pub global: bool, |
26 | /// pub segments: Vec<PathSegment>, |
27 | /// } |
28 | /// |
29 | /// impl ToTokens for Path { |
30 | /// fn to_tokens(&self, tokens: &mut TokenStream) { |
31 | /// for (i, segment) in self.segments.iter().enumerate() { |
32 | /// if i > 0 || self.global { |
33 | /// // Double colon `::` |
34 | /// tokens.append(Punct::new(':' , Spacing::Joint)); |
35 | /// tokens.append(Punct::new(':' , Spacing::Alone)); |
36 | /// } |
37 | /// segment.to_tokens(tokens); |
38 | /// } |
39 | /// } |
40 | /// } |
41 | /// # |
42 | /// # pub struct PathSegment; |
43 | /// # |
44 | /// # impl ToTokens for PathSegment { |
45 | /// # fn to_tokens(&self, tokens: &mut TokenStream) { |
46 | /// # unimplemented!() |
47 | /// # } |
48 | /// # } |
49 | /// ``` |
50 | fn to_tokens(&self, tokens: &mut TokenStream); |
51 | |
52 | /// Convert `self` directly into a `TokenStream` object. |
53 | /// |
54 | /// This method is implicitly implemented using `to_tokens`, and acts as a |
55 | /// convenience method for consumers of the `ToTokens` trait. |
56 | fn to_token_stream(&self) -> TokenStream { |
57 | let mut tokens = TokenStream::new(); |
58 | self.to_tokens(&mut tokens); |
59 | tokens |
60 | } |
61 | |
62 | /// Convert `self` directly into a `TokenStream` object. |
63 | /// |
64 | /// This method is implicitly implemented using `to_tokens`, and acts as a |
65 | /// convenience method for consumers of the `ToTokens` trait. |
66 | fn into_token_stream(self) -> TokenStream |
67 | where |
68 | Self: Sized, |
69 | { |
70 | self.to_token_stream() |
71 | } |
72 | } |
73 | |
74 | impl<T: ?Sized + ToTokens> ToTokens for &T { |
75 | fn to_tokens(&self, tokens: &mut TokenStream) { |
76 | (**self).to_tokens(tokens); |
77 | } |
78 | } |
79 | |
80 | impl<T: ?Sized + ToTokens> ToTokens for &mut T { |
81 | fn to_tokens(&self, tokens: &mut TokenStream) { |
82 | (**self).to_tokens(tokens); |
83 | } |
84 | } |
85 | |
86 | impl<'a, T: ?Sized + ToOwned + ToTokens> ToTokens for Cow<'a, T> { |
87 | fn to_tokens(&self, tokens: &mut TokenStream) { |
88 | (**self).to_tokens(tokens); |
89 | } |
90 | } |
91 | |
92 | impl<T: ?Sized + ToTokens> ToTokens for Box<T> { |
93 | fn to_tokens(&self, tokens: &mut TokenStream) { |
94 | (**self).to_tokens(tokens); |
95 | } |
96 | } |
97 | |
98 | impl<T: ?Sized + ToTokens> ToTokens for Rc<T> { |
99 | fn to_tokens(&self, tokens: &mut TokenStream) { |
100 | (**self).to_tokens(tokens); |
101 | } |
102 | } |
103 | |
104 | impl<T: ToTokens> ToTokens for Option<T> { |
105 | fn to_tokens(&self, tokens: &mut TokenStream) { |
106 | if let Some(t: &T) = self { |
107 | t.to_tokens(tokens); |
108 | } |
109 | } |
110 | } |
111 | |
112 | impl ToTokens for str { |
113 | fn to_tokens(&self, tokens: &mut TokenStream) { |
114 | tokens.append(token:Literal::string(self)); |
115 | } |
116 | } |
117 | |
118 | impl ToTokens for String { |
119 | fn to_tokens(&self, tokens: &mut TokenStream) { |
120 | self.as_str().to_tokens(tokens); |
121 | } |
122 | } |
123 | |
124 | impl ToTokens for i8 { |
125 | fn to_tokens(&self, tokens: &mut TokenStream) { |
126 | tokens.append(token:Literal::i8_suffixed(*self)); |
127 | } |
128 | } |
129 | |
130 | impl ToTokens for i16 { |
131 | fn to_tokens(&self, tokens: &mut TokenStream) { |
132 | tokens.append(token:Literal::i16_suffixed(*self)); |
133 | } |
134 | } |
135 | |
136 | impl ToTokens for i32 { |
137 | fn to_tokens(&self, tokens: &mut TokenStream) { |
138 | tokens.append(token:Literal::i32_suffixed(*self)); |
139 | } |
140 | } |
141 | |
142 | impl ToTokens for i64 { |
143 | fn to_tokens(&self, tokens: &mut TokenStream) { |
144 | tokens.append(token:Literal::i64_suffixed(*self)); |
145 | } |
146 | } |
147 | |
148 | impl ToTokens for i128 { |
149 | fn to_tokens(&self, tokens: &mut TokenStream) { |
150 | tokens.append(token:Literal::i128_suffixed(*self)); |
151 | } |
152 | } |
153 | |
154 | impl ToTokens for isize { |
155 | fn to_tokens(&self, tokens: &mut TokenStream) { |
156 | tokens.append(token:Literal::isize_suffixed(*self)); |
157 | } |
158 | } |
159 | |
160 | impl ToTokens for u8 { |
161 | fn to_tokens(&self, tokens: &mut TokenStream) { |
162 | tokens.append(token:Literal::u8_suffixed(*self)); |
163 | } |
164 | } |
165 | |
166 | impl ToTokens for u16 { |
167 | fn to_tokens(&self, tokens: &mut TokenStream) { |
168 | tokens.append(token:Literal::u16_suffixed(*self)); |
169 | } |
170 | } |
171 | |
172 | impl ToTokens for u32 { |
173 | fn to_tokens(&self, tokens: &mut TokenStream) { |
174 | tokens.append(token:Literal::u32_suffixed(*self)); |
175 | } |
176 | } |
177 | |
178 | impl ToTokens for u64 { |
179 | fn to_tokens(&self, tokens: &mut TokenStream) { |
180 | tokens.append(token:Literal::u64_suffixed(*self)); |
181 | } |
182 | } |
183 | |
184 | impl ToTokens for u128 { |
185 | fn to_tokens(&self, tokens: &mut TokenStream) { |
186 | tokens.append(token:Literal::u128_suffixed(*self)); |
187 | } |
188 | } |
189 | |
190 | impl ToTokens for usize { |
191 | fn to_tokens(&self, tokens: &mut TokenStream) { |
192 | tokens.append(token:Literal::usize_suffixed(*self)); |
193 | } |
194 | } |
195 | |
196 | impl ToTokens for f32 { |
197 | fn to_tokens(&self, tokens: &mut TokenStream) { |
198 | tokens.append(token:Literal::f32_suffixed(*self)); |
199 | } |
200 | } |
201 | |
202 | impl ToTokens for f64 { |
203 | fn to_tokens(&self, tokens: &mut TokenStream) { |
204 | tokens.append(token:Literal::f64_suffixed(*self)); |
205 | } |
206 | } |
207 | |
208 | impl ToTokens for char { |
209 | fn to_tokens(&self, tokens: &mut TokenStream) { |
210 | tokens.append(token:Literal::character(*self)); |
211 | } |
212 | } |
213 | |
214 | impl ToTokens for bool { |
215 | fn to_tokens(&self, tokens: &mut TokenStream) { |
216 | let word: &'static str = if *self { "true" } else { "false" }; |
217 | tokens.append(token:Ident::new(string:word, Span::call_site())); |
218 | } |
219 | } |
220 | |
221 | impl ToTokens for CStr { |
222 | fn to_tokens(&self, tokens: &mut TokenStream) { |
223 | tokens.append(token:Literal::c_string(self)); |
224 | } |
225 | } |
226 | |
227 | impl ToTokens for CString { |
228 | fn to_tokens(&self, tokens: &mut TokenStream) { |
229 | tokens.append(token:Literal::c_string(self)); |
230 | } |
231 | } |
232 | |
233 | impl ToTokens for Group { |
234 | fn to_tokens(&self, tokens: &mut TokenStream) { |
235 | tokens.append(self.clone()); |
236 | } |
237 | } |
238 | |
239 | impl ToTokens for Ident { |
240 | fn to_tokens(&self, tokens: &mut TokenStream) { |
241 | tokens.append(self.clone()); |
242 | } |
243 | } |
244 | |
245 | impl ToTokens for Punct { |
246 | fn to_tokens(&self, tokens: &mut TokenStream) { |
247 | tokens.append(self.clone()); |
248 | } |
249 | } |
250 | |
251 | impl ToTokens for Literal { |
252 | fn to_tokens(&self, tokens: &mut TokenStream) { |
253 | tokens.append(self.clone()); |
254 | } |
255 | } |
256 | |
257 | impl ToTokens for TokenTree { |
258 | fn to_tokens(&self, tokens: &mut TokenStream) { |
259 | tokens.append(self.clone()); |
260 | } |
261 | } |
262 | |
263 | impl ToTokens for TokenStream { |
264 | fn to_tokens(&self, tokens: &mut TokenStream) { |
265 | tokens.extend(iter:iter::once(self.clone())); |
266 | } |
267 | |
268 | fn into_token_stream(self) -> TokenStream { |
269 | self |
270 | } |
271 | } |
272 | |