Skip to main content

quote/
to_tokens.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3use super::TokenStreamExt;
4use alloc::borrow::Cow;
5use alloc::rc::Rc;
6use core::iter;
7use proc_macro2::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
8use std::ffi::{CStr, CString};
9
10/// Types that can be interpolated inside a `quote!` invocation.
11pub 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    /// ```
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.
58    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.
68    fn into_token_stream(self) -> TokenStream
69    where
70        Self: Sized,
71    {
72        self.to_token_stream()
73    }
74}
75
76impl<T: ?Sized + ToTokens> ToTokens for &T {
77    fn to_tokens(&self, tokens: &mut TokenStream) {
78        (**self).to_tokens(tokens);
79    }
80}
81
82impl<T: ?Sized + ToTokens> ToTokens for &mut T {
83    fn to_tokens(&self, tokens: &mut TokenStream) {
84        (**self).to_tokens(tokens);
85    }
86}
87
88impl<'a, T: ?Sized + ToOwned + ToTokens> ToTokens for Cow<'a, T> {
89    fn to_tokens(&self, tokens: &mut TokenStream) {
90        (**self).to_tokens(tokens);
91    }
92}
93
94impl<T: ?Sized + ToTokens> ToTokens for Box<T> {
95    fn to_tokens(&self, tokens: &mut TokenStream) {
96        (**self).to_tokens(tokens);
97    }
98}
99
100impl<T: ?Sized + ToTokens> ToTokens for Rc<T> {
101    fn to_tokens(&self, tokens: &mut TokenStream) {
102        (**self).to_tokens(tokens);
103    }
104}
105
106impl<T: ToTokens> ToTokens for Option<T> {
107    fn to_tokens(&self, tokens: &mut TokenStream) {
108        if let Some(t) = self {
109            t.to_tokens(tokens);
110        }
111    }
112}
113
114impl ToTokens for str {
115    fn to_tokens(&self, tokens: &mut TokenStream) {
116        tokens.append(Literal::string(self));
117    }
118}
119
120impl ToTokens for String {
121    fn to_tokens(&self, tokens: &mut TokenStream) {
122        self.as_str().to_tokens(tokens);
123    }
124}
125
126impl ToTokens for i8 {
127    fn to_tokens(&self, tokens: &mut TokenStream) {
128        tokens.append(Literal::i8_suffixed(*self));
129    }
130}
131
132impl ToTokens for i16 {
133    fn to_tokens(&self, tokens: &mut TokenStream) {
134        tokens.append(Literal::i16_suffixed(*self));
135    }
136}
137
138impl ToTokens for i32 {
139    fn to_tokens(&self, tokens: &mut TokenStream) {
140        tokens.append(Literal::i32_suffixed(*self));
141    }
142}
143
144impl ToTokens for i64 {
145    fn to_tokens(&self, tokens: &mut TokenStream) {
146        tokens.append(Literal::i64_suffixed(*self));
147    }
148}
149
150impl ToTokens for i128 {
151    fn to_tokens(&self, tokens: &mut TokenStream) {
152        tokens.append(Literal::i128_suffixed(*self));
153    }
154}
155
156impl ToTokens for isize {
157    fn to_tokens(&self, tokens: &mut TokenStream) {
158        tokens.append(Literal::isize_suffixed(*self));
159    }
160}
161
162impl ToTokens for u8 {
163    fn to_tokens(&self, tokens: &mut TokenStream) {
164        tokens.append(Literal::u8_suffixed(*self));
165    }
166}
167
168impl ToTokens for u16 {
169    fn to_tokens(&self, tokens: &mut TokenStream) {
170        tokens.append(Literal::u16_suffixed(*self));
171    }
172}
173
174impl ToTokens for u32 {
175    fn to_tokens(&self, tokens: &mut TokenStream) {
176        tokens.append(Literal::u32_suffixed(*self));
177    }
178}
179
180impl ToTokens for u64 {
181    fn to_tokens(&self, tokens: &mut TokenStream) {
182        tokens.append(Literal::u64_suffixed(*self));
183    }
184}
185
186impl ToTokens for u128 {
187    fn to_tokens(&self, tokens: &mut TokenStream) {
188        tokens.append(Literal::u128_suffixed(*self));
189    }
190}
191
192impl ToTokens for usize {
193    fn to_tokens(&self, tokens: &mut TokenStream) {
194        tokens.append(Literal::usize_suffixed(*self));
195    }
196}
197
198impl ToTokens for f32 {
199    fn to_tokens(&self, tokens: &mut TokenStream) {
200        tokens.append(Literal::f32_suffixed(*self));
201    }
202}
203
204impl ToTokens for f64 {
205    fn to_tokens(&self, tokens: &mut TokenStream) {
206        tokens.append(Literal::f64_suffixed(*self));
207    }
208}
209
210impl ToTokens for char {
211    fn to_tokens(&self, tokens: &mut TokenStream) {
212        tokens.append(Literal::character(*self));
213    }
214}
215
216impl ToTokens for bool {
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
223impl ToTokens for CStr {
224    fn to_tokens(&self, tokens: &mut TokenStream) {
225        tokens.append(Literal::c_string(self));
226    }
227}
228
229impl ToTokens for CString {
230    fn to_tokens(&self, tokens: &mut TokenStream) {
231        tokens.append(Literal::c_string(self));
232    }
233}
234
235impl ToTokens for Group {
236    fn to_tokens(&self, tokens: &mut TokenStream) {
237        tokens.append(self.clone());
238    }
239}
240
241impl ToTokens for Ident {
242    fn to_tokens(&self, tokens: &mut TokenStream) {
243        tokens.append(self.clone());
244    }
245}
246
247impl ToTokens for Punct {
248    fn to_tokens(&self, tokens: &mut TokenStream) {
249        tokens.append(self.clone());
250    }
251}
252
253impl ToTokens for Literal {
254    fn to_tokens(&self, tokens: &mut TokenStream) {
255        tokens.append(self.clone());
256    }
257}
258
259impl ToTokens for TokenTree {
260    fn to_tokens(&self, tokens: &mut TokenStream) {
261        tokens.append(self.clone());
262    }
263}
264
265impl ToTokens for TokenStream {
266    fn to_tokens(&self, tokens: &mut TokenStream) {
267        tokens.extend(iter::once(self.clone()));
268    }
269
270    fn into_token_stream(self) -> TokenStream {
271        self
272    }
273}