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