quote/
to_tokens.rs

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