quote/
to_tokens.rs

1use super::TokenStreamExt;
2
3use std::borrow::Cow;
4use std::iter;
5use std::rc::Rc;
6
7use proc_macro2::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
8
9/// Types that can be interpolated inside a `quote!` invocation.
10///
11/// [`quote!`]: macro.quote.html
12pub trait ToTokens {
13    /// Write `self` to the given `TokenStream`.
14    ///
15    /// The token append methods provided by the [`TokenStreamExt`] extension
16    /// trait may be useful for implementing `ToTokens`.
17    ///
18    /// [`TokenStreamExt`]: trait.TokenStreamExt.html
19    ///
20    /// # Example
21    ///
22    /// Example implementation for a struct representing Rust paths like
23    /// `std::cmp::PartialEq`:
24    ///
25    /// ```
26    /// use proc_macro2::{TokenTree, Spacing, Span, Punct, TokenStream};
27    /// use quote::{TokenStreamExt, ToTokens};
28    ///
29    /// pub struct Path {
30    ///     pub global: bool,
31    ///     pub segments: Vec<PathSegment>,
32    /// }
33    ///
34    /// impl ToTokens for Path {
35    ///     fn to_tokens(&self, tokens: &mut TokenStream) {
36    ///         for (i, segment) in self.segments.iter().enumerate() {
37    ///             if i > 0 || self.global {
38    ///                 // Double colon `::`
39    ///                 tokens.append(Punct::new(':', Spacing::Joint));
40    ///                 tokens.append(Punct::new(':', Spacing::Alone));
41    ///             }
42    ///             segment.to_tokens(tokens);
43    ///         }
44    ///     }
45    /// }
46    /// #
47    /// # pub struct PathSegment;
48    /// #
49    /// # impl ToTokens for PathSegment {
50    /// #     fn to_tokens(&self, tokens: &mut TokenStream) {
51    /// #         unimplemented!()
52    /// #     }
53    /// # }
54    /// ```
55    fn to_tokens(&self, tokens: &mut TokenStream);
56
57    /// Convert `self` directly into a `TokenStream` object.
58    ///
59    /// This method is implicitly implemented using `to_tokens`, and acts as a
60    /// convenience method for consumers of the `ToTokens` trait.
61    fn to_token_stream(&self) -> TokenStream {
62        let mut tokens = TokenStream::new();
63        self.to_tokens(&mut tokens);
64        tokens
65    }
66
67    /// Convert `self` directly into a `TokenStream` object.
68    ///
69    /// This method is implicitly implemented using `to_tokens`, and acts as a
70    /// convenience method for consumers of the `ToTokens` trait.
71    fn into_token_stream(self) -> TokenStream
72    where
73        Self: Sized,
74    {
75        self.to_token_stream()
76    }
77}
78
79impl<'a, T: ?Sized + ToTokens> ToTokens for &'a T {
80    fn to_tokens(&self, tokens: &mut TokenStream) {
81        (**self).to_tokens(tokens);
82    }
83}
84
85impl<'a, T: ?Sized + ToTokens> ToTokens for &'a mut T {
86    fn to_tokens(&self, tokens: &mut TokenStream) {
87        (**self).to_tokens(tokens);
88    }
89}
90
91impl<'a, T: ?Sized + ToOwned + ToTokens> ToTokens for Cow<'a, T> {
92    fn to_tokens(&self, tokens: &mut TokenStream) {
93        (**self).to_tokens(tokens);
94    }
95}
96
97impl<T: ?Sized + ToTokens> ToTokens for Box<T> {
98    fn to_tokens(&self, tokens: &mut TokenStream) {
99        (**self).to_tokens(tokens);
100    }
101}
102
103impl<T: ?Sized + ToTokens> ToTokens for Rc<T> {
104    fn to_tokens(&self, tokens: &mut TokenStream) {
105        (**self).to_tokens(tokens);
106    }
107}
108
109impl<T: ToTokens> ToTokens for Option<T> {
110    fn to_tokens(&self, tokens: &mut TokenStream) {
111        if let Some(ref t) = *self {
112            t.to_tokens(tokens);
113        }
114    }
115}
116
117impl ToTokens for str {
118    fn to_tokens(&self, tokens: &mut TokenStream) {
119        tokens.append(Literal::string(self));
120    }
121}
122
123impl ToTokens for String {
124    fn to_tokens(&self, tokens: &mut TokenStream) {
125        self.as_str().to_tokens(tokens);
126    }
127}
128
129macro_rules! primitive {
130    ($($t:ident => $name:ident)*) => ($(
131        impl ToTokens for $t {
132            fn to_tokens(&self, tokens: &mut TokenStream) {
133                tokens.append(Literal::$name(*self));
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}