syn_serde/
token_stream.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3use core::fmt::{self, Write};
4
5use super::*;
6
7ast_struct! {
8    /// An adapter for [`struct@proc_macro2::TokenStream`].
9    #[derive(Clone, Default)]
10    #[serde(transparent)]
11    pub struct TokenStream {
12        inner: Vec<TokenTree>,
13    }
14}
15
16impl TokenStream {
17    fn _new(inner: Vec<TokenTree>) -> Self {
18        Self { inner }
19    }
20}
21
22ast_enum! {
23    /// An adapter for [`enum@proc_macro2::TokenTree`].
24    #[derive(Clone)]
25    pub enum TokenTree {
26        Group(Group),
27        Ident(Ident),
28        Punct(Punct),
29        #[serde(rename = "lit")]
30        Literal(Literal),
31    }
32}
33
34ast_struct! {
35    /// An adapter for [`struct@proc_macro2::Group`].
36    #[derive(Clone)]
37    pub struct Group {
38        delimiter: Delimiter,
39        stream: TokenStream,
40    }
41}
42
43ast_enum! {
44    /// An adapter for [`enum@proc_macro2::Delimiter`].
45    #[derive(Clone, Copy)]
46    pub enum Delimiter {
47        Parenthesis,
48        Brace,
49        Bracket,
50        None,
51    }
52}
53
54ast_struct! {
55    /// An adapter for [`struct@proc_macro2::Punct`].
56    #[derive(Clone, Copy)]
57    pub struct Punct {
58        op: char,
59        spacing: Spacing,
60    }
61}
62
63ast_enum! {
64    /// An adapter for [`enum@proc_macro2::Spacing`].
65    #[derive(Clone, Copy)]
66    pub enum Spacing {
67        Alone,
68        Joint,
69    }
70}
71
72ast_struct! {
73    /// An adapter for [`struct@proc_macro2::Ident`].
74    #[derive(Clone, Eq, PartialEq)]
75    #[serde(transparent)]
76    pub struct Ident {
77        inner: String,
78    }
79}
80
81ast_struct! {
82    /// An adapter for [`struct@proc_macro2::Literal`].
83    #[derive(Clone)]
84    #[serde(transparent)]
85    pub struct Literal {
86        pub(crate) text: String,
87    }
88}
89
90impl Literal {
91    fn _new(text: String) -> Self {
92        Self { text }
93    }
94
95    pub(crate) fn u8_suffixed(n: u8) -> Self {
96        Self::_new(format!(concat!("{}", stringify!(u8)), n))
97    }
98
99    pub(crate) fn string(t: &str) -> Self {
100        let mut s = t.chars().flat_map(char::escape_default).collect::<String>();
101        s.push('"');
102        s.insert(0, '"');
103        Self::_new(s)
104    }
105
106    pub(crate) fn character(t: char) -> Self {
107        Self::_new(format!("'{}'", t.escape_default().collect::<String>()))
108    }
109
110    #[allow(clippy::match_overlapping_arm)]
111    pub(crate) fn byte_string(bytes: &[u8]) -> Self {
112        let mut escaped = "b\"".to_string();
113        for b in bytes {
114            match *b {
115                b'\0' => escaped.push_str(r"\0"),
116                b'\t' => escaped.push_str(r"\t"),
117                b'\n' => escaped.push_str(r"\n"),
118                b'\r' => escaped.push_str(r"\r"),
119                b'"' => escaped.push_str("\\\""),
120                b'\\' => escaped.push_str("\\\\"),
121                b'\x20'..=b'\x7E' => escaped.push(*b as char),
122                _ => {
123                    let _ = write!(escaped, "\\x{:02X}", b);
124                }
125            }
126        }
127        escaped.push('"');
128        Self::_new(escaped)
129    }
130}
131
132// TODO: when release the next minor version, remove this.
133impl fmt::Display for Literal {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        fmt::Display::fmt(&self.text, f)
136    }
137}
138
139mod convert {
140    use super::*;
141
142    // TokenStream
143    syn_trait_impl!(proc_macro2::TokenStream);
144    impl From<&proc_macro2::TokenStream> for TokenStream {
145        fn from(other: &proc_macro2::TokenStream) -> Self {
146            Self::_new(other.clone().into_iter().map::<TokenTree, _>(|x| x.ref_into()).collect())
147        }
148    }
149    impl From<&TokenStream> for proc_macro2::TokenStream {
150        fn from(other: &TokenStream) -> Self {
151            other.inner.iter().map::<proc_macro2::TokenTree, _>(Into::into).collect()
152        }
153    }
154
155    // TokenTree
156    syn_trait_impl!(proc_macro2::TokenTree);
157    impl From<&proc_macro2::TokenTree> for TokenTree {
158        fn from(other: &proc_macro2::TokenTree) -> Self {
159            use super::TokenTree::*;
160            match other {
161                proc_macro2::TokenTree::Group(t) => Group(t.into()),
162                proc_macro2::TokenTree::Ident(t) => Ident(t.into()),
163                proc_macro2::TokenTree::Punct(t) => Punct(t.into()),
164                proc_macro2::TokenTree::Literal(t) => Literal(t.into()),
165            }
166        }
167    }
168    impl From<&TokenTree> for proc_macro2::TokenTree {
169        fn from(other: &TokenTree) -> Self {
170            use proc_macro2::TokenTree::*;
171            match other {
172                TokenTree::Group(t) => Group(t.into()),
173                TokenTree::Ident(t) => Ident(t.into()),
174                TokenTree::Punct(t) => Punct(t.into()),
175                TokenTree::Literal(t) => Literal(t.into()),
176            }
177        }
178    }
179
180    // Group
181    syn_trait_impl!(proc_macro2::Group);
182    impl From<&proc_macro2::Group> for Group {
183        fn from(other: &proc_macro2::Group) -> Self {
184            Self { delimiter: other.delimiter().ref_into(), stream: other.stream().ref_into() }
185        }
186    }
187    impl From<&Group> for proc_macro2::Group {
188        fn from(other: &Group) -> Self {
189            Self::new(other.delimiter.ref_into(), other.stream.ref_into())
190        }
191    }
192
193    // Delimiter
194    syn_trait_impl!(proc_macro2::Delimiter);
195    impl From<&proc_macro2::Delimiter> for Delimiter {
196        fn from(other: &proc_macro2::Delimiter) -> Self {
197            use super::Delimiter::*;
198            match other {
199                proc_macro2::Delimiter::Parenthesis => Parenthesis,
200                proc_macro2::Delimiter::Brace => Brace,
201                proc_macro2::Delimiter::Bracket => Bracket,
202                proc_macro2::Delimiter::None => None,
203            }
204        }
205    }
206    impl From<&Delimiter> for proc_macro2::Delimiter {
207        fn from(other: &Delimiter) -> Self {
208            use proc_macro2::Delimiter::*;
209            match other {
210                Delimiter::Parenthesis => Parenthesis,
211                Delimiter::Brace => Brace,
212                Delimiter::Bracket => Bracket,
213                Delimiter::None => None,
214            }
215        }
216    }
217
218    // Ident
219    syn_trait_impl!(proc_macro2::Ident);
220    impl From<&proc_macro2::Ident> for Ident {
221        fn from(other: &proc_macro2::Ident) -> Self {
222            Self { inner: other.to_string() }
223        }
224    }
225    impl From<&Ident> for proc_macro2::Ident {
226        fn from(other: &Ident) -> Self {
227            Self::new(&other.inner, Span::call_site())
228        }
229    }
230
231    // Punct
232    syn_trait_impl!(proc_macro2::Punct);
233    impl From<&proc_macro2::Punct> for Punct {
234        fn from(other: &proc_macro2::Punct) -> Self {
235            Self { op: other.as_char(), spacing: other.spacing().ref_into() }
236        }
237    }
238    impl From<&Punct> for proc_macro2::Punct {
239        fn from(other: &Punct) -> Self {
240            Self::new(other.op, other.spacing.ref_into())
241        }
242    }
243
244    // Spacing
245    syn_trait_impl!(proc_macro2::Spacing);
246    impl From<&proc_macro2::Spacing> for Spacing {
247        fn from(other: &proc_macro2::Spacing) -> Self {
248            use super::Spacing::*;
249            match other {
250                proc_macro2::Spacing::Alone => Alone,
251                proc_macro2::Spacing::Joint => Joint,
252            }
253        }
254    }
255    impl From<&Spacing> for proc_macro2::Spacing {
256        fn from(other: &Spacing) -> Self {
257            use proc_macro2::Spacing::*;
258            match other {
259                Spacing::Alone => Alone,
260                Spacing::Joint => Joint,
261            }
262        }
263    }
264
265    // Literal
266    syn_trait_impl!(proc_macro2::Literal);
267    impl From<&proc_macro2::Literal> for Literal {
268        fn from(other: &proc_macro2::Literal) -> Self {
269            Self { text: other.to_string() }
270        }
271    }
272    impl From<&Literal> for proc_macro2::Literal {
273        fn from(other: &Literal) -> Self {
274            use proc_macro2::*;
275            let stream = other.text.parse::<TokenStream>().unwrap();
276            match stream.into_iter().next().unwrap() {
277                TokenTree::Literal(l) => l,
278                _ => unreachable!(),
279            }
280        }
281    }
282}