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