litrs/impls.rs
1use std::convert::TryFrom;
2
3use crate::{Literal, err::{InvalidToken, TokenKind}};
4
5
6/// Helper macro to call a `callback` macro four times for all combinations of
7/// `proc_macro`/`proc_macro2` and `&`/owned.
8macro_rules! helper {
9 ($callback:ident, $($input:tt)*) => {
10 $callback!([proc_macro::] => $($input)*);
11 $callback!([&proc_macro::] => $($input)*);
12 #[cfg(feature = "proc-macro2")]
13 $callback!([proc_macro2::] => $($input)*);
14 #[cfg(feature = "proc-macro2")]
15 $callback!([&proc_macro2::] => $($input)*);
16 };
17}
18
19
20// ==============================================================================================
21// ===== `From<*Lit> for Literal`
22// ==============================================================================================
23
24macro_rules! impl_specific_lit_to_lit {
25 ($ty:ty, $variant:ident) => {
26 impl<B: crate::Buffer> From<$ty> for Literal<B> {
27 fn from(src: $ty) -> Self {
28 Literal::$variant(src)
29 }
30 }
31 };
32}
33
34impl_specific_lit_to_lit!(crate::BoolLit, Bool);
35impl_specific_lit_to_lit!(crate::IntegerLit<B>, Integer);
36impl_specific_lit_to_lit!(crate::FloatLit<B>, Float);
37impl_specific_lit_to_lit!(crate::CharLit<B>, Char);
38impl_specific_lit_to_lit!(crate::StringLit<B>, String);
39impl_specific_lit_to_lit!(crate::ByteLit<B>, Byte);
40impl_specific_lit_to_lit!(crate::ByteStringLit<B>, ByteString);
41
42
43
44// ==============================================================================================
45// ===== `From<pm::Literal> for Literal`
46// ==============================================================================================
47
48
49macro_rules! impl_tt_to_lit {
50 ([$($prefix:tt)*] => ) => {
51 impl From<$($prefix)* Literal> for Literal<String> {
52 fn from(src: $($prefix)* Literal) -> Self {
53 // We call `expect` in all these impls: this library aims to implement exactly
54 // the Rust grammar, so if we have a valid Rust literal, we should always be
55 // able to parse it.
56 Self::parse(src.to_string())
57 .expect("bug: failed to parse output of `Literal::to_string`")
58 }
59 }
60 }
61}
62
63helper!(impl_tt_to_lit, );
64
65
66// ==============================================================================================
67// ===== `TryFrom<pm::TokenTree> for Literal`
68// ==============================================================================================
69
70macro_rules! impl_tt_to_lit {
71 ([$($prefix:tt)*] => ) => {
72 impl TryFrom<$($prefix)* TokenTree> for Literal<String> {
73 type Error = InvalidToken;
74 fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
75 let span = tt.span();
76 let res = match tt {
77 $($prefix)* TokenTree::Group(_) => Err(TokenKind::Group),
78 $($prefix)* TokenTree::Punct(_) => Err(TokenKind::Punct),
79 $($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "true"
80 => return Ok(Literal::Bool(crate::BoolLit::True)),
81 $($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "false"
82 => return Ok(Literal::Bool(crate::BoolLit::False)),
83 $($prefix)* TokenTree::Ident(_) => Err(TokenKind::Ident),
84 $($prefix)* TokenTree::Literal(ref lit) => Ok(lit),
85 };
86
87 match res {
88 Ok(lit) => Ok(From::from(lit)),
89 Err(actual) => Err(InvalidToken {
90 actual,
91 expected: TokenKind::Literal,
92 span: span.into(),
93 }),
94 }
95 }
96 }
97 }
98}
99
100helper!(impl_tt_to_lit, );
101
102
103// ==============================================================================================
104// ===== `TryFrom<pm::Literal> for *Lit` and `TryFrom<pm::TokenTree> for *Lit`
105// ==============================================================================================
106
107fn kind_of(lit: &Literal<String>) -> TokenKind {
108 match lit {
109 Literal::String(_) => TokenKind::StringLit,
110 Literal::Bool(_) => TokenKind::BoolLit,
111 Literal::Integer(_) => TokenKind::IntegerLit,
112 Literal::Float(_) => TokenKind::FloatLit,
113 Literal::Char(_) => TokenKind::CharLit,
114 Literal::Byte(_) => TokenKind::ByteLit,
115 Literal::ByteString(_) => TokenKind::ByteStringLit,
116 }
117}
118
119macro_rules! impl_for_specific_lit {
120 ([$($prefix:tt)*] => $ty:ty, $variant:ident, $kind:ident) => {
121 impl TryFrom<$($prefix)* Literal> for $ty {
122 type Error = InvalidToken;
123 fn try_from(src: $($prefix)* Literal) -> Result<Self, Self::Error> {
124 let span = src.span();
125 let lit: Literal<String> = src.into();
126 match lit {
127 Literal::$variant(s) => Ok(s),
128 other => Err(InvalidToken {
129 expected: TokenKind::$kind,
130 actual: kind_of(&other),
131 span: span.into(),
132 }),
133 }
134 }
135 }
136
137 impl TryFrom<$($prefix)* TokenTree> for $ty {
138 type Error = InvalidToken;
139 fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
140 let span = tt.span();
141 let res = match tt {
142 $($prefix)* TokenTree::Group(_) => Err(TokenKind::Group),
143 $($prefix)* TokenTree::Punct(_) => Err(TokenKind::Punct),
144 $($prefix)* TokenTree::Ident(_) => Err(TokenKind::Ident),
145 $($prefix)* TokenTree::Literal(ref lit) => Ok(lit),
146 };
147
148 match res {
149 Ok(lit) => <$ty>::try_from(lit),
150 Err(actual) => Err(InvalidToken {
151 actual,
152 expected: TokenKind::$kind,
153 span: span.into(),
154 }),
155 }
156 }
157 }
158 };
159}
160
161helper!(impl_for_specific_lit, crate::IntegerLit<String>, Integer, IntegerLit);
162helper!(impl_for_specific_lit, crate::FloatLit<String>, Float, FloatLit);
163helper!(impl_for_specific_lit, crate::CharLit<String>, Char, CharLit);
164helper!(impl_for_specific_lit, crate::StringLit<String>, String, StringLit);
165helper!(impl_for_specific_lit, crate::ByteLit<String>, Byte, ByteLit);
166helper!(impl_for_specific_lit, crate::ByteStringLit<String>, ByteString, ByteStringLit);
167
168macro_rules! impl_from_tt_for_bool {
169 ([$($prefix:tt)*] => ) => {
170 impl TryFrom<$($prefix)* TokenTree> for crate::BoolLit {
171 type Error = InvalidToken;
172 fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
173 let span = tt.span();
174 let actual = match tt {
175 $($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "true"
176 => return Ok(crate::BoolLit::True),
177 $($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "false"
178 => return Ok(crate::BoolLit::False),
179
180 $($prefix)* TokenTree::Group(_) => TokenKind::Group,
181 $($prefix)* TokenTree::Punct(_) => TokenKind::Punct,
182 $($prefix)* TokenTree::Ident(_) => TokenKind::Ident,
183 $($prefix)* TokenTree::Literal(ref lit) => kind_of(&Literal::from(lit)),
184 };
185
186 Err(InvalidToken {
187 actual,
188 expected: TokenKind::BoolLit,
189 span: span.into(),
190 })
191 }
192 }
193 };
194}
195
196helper!(impl_from_tt_for_bool, );
197
198
199mod tests {
200 //! # Tests
201 //!
202 //! ```no_run
203 //! extern crate proc_macro;
204 //!
205 //! use std::convert::TryFrom;
206 //! use litrs::Literal;
207 //!
208 //! fn give<T>() -> T {
209 //! panic!()
210 //! }
211 //!
212 //! let _ = litrs::Literal::<String>::from(give::<litrs::BoolLit>());
213 //! let _ = litrs::Literal::<String>::from(give::<litrs::IntegerLit<String>>());
214 //! let _ = litrs::Literal::<String>::from(give::<litrs::FloatLit<String>>());
215 //! let _ = litrs::Literal::<String>::from(give::<litrs::CharLit<String>>());
216 //! let _ = litrs::Literal::<String>::from(give::<litrs::StringLit<String>>());
217 //! let _ = litrs::Literal::<String>::from(give::<litrs::ByteLit<String>>());
218 //! let _ = litrs::Literal::<String>::from(give::<litrs::ByteStringLit<String>>());
219 //!
220 //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::BoolLit>());
221 //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::IntegerLit<&'static str>>());
222 //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::FloatLit<&'static str>>());
223 //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::CharLit<&'static str>>());
224 //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::StringLit<&'static str>>());
225 //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::ByteLit<&'static str>>());
226 //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::ByteStringLit<&'static str>>());
227 //!
228 //!
229 //! let _ = litrs::Literal::from(give::<proc_macro::Literal>());
230 //! let _ = litrs::Literal::from(give::<&proc_macro::Literal>());
231 //!
232 //! let _ = litrs::Literal::try_from(give::<proc_macro::TokenTree>());
233 //! let _ = litrs::Literal::try_from(give::<&proc_macro::TokenTree>());
234 //!
235 //!
236 //! let _ = litrs::IntegerLit::try_from(give::<proc_macro::Literal>());
237 //! let _ = litrs::IntegerLit::try_from(give::<&proc_macro::Literal>());
238 //!
239 //! let _ = litrs::FloatLit::try_from(give::<proc_macro::Literal>());
240 //! let _ = litrs::FloatLit::try_from(give::<&proc_macro::Literal>());
241 //!
242 //! let _ = litrs::CharLit::try_from(give::<proc_macro::Literal>());
243 //! let _ = litrs::CharLit::try_from(give::<&proc_macro::Literal>());
244 //!
245 //! let _ = litrs::StringLit::try_from(give::<proc_macro::Literal>());
246 //! let _ = litrs::StringLit::try_from(give::<&proc_macro::Literal>());
247 //!
248 //! let _ = litrs::ByteLit::try_from(give::<proc_macro::Literal>());
249 //! let _ = litrs::ByteLit::try_from(give::<&proc_macro::Literal>());
250 //!
251 //! let _ = litrs::ByteStringLit::try_from(give::<proc_macro::Literal>());
252 //! let _ = litrs::ByteStringLit::try_from(give::<&proc_macro::Literal>());
253 //!
254 //!
255 //! let _ = litrs::BoolLit::try_from(give::<proc_macro::TokenTree>());
256 //! let _ = litrs::BoolLit::try_from(give::<&proc_macro::TokenTree>());
257 //!
258 //! let _ = litrs::IntegerLit::try_from(give::<proc_macro::TokenTree>());
259 //! let _ = litrs::IntegerLit::try_from(give::<&proc_macro::TokenTree>());
260 //!
261 //! let _ = litrs::FloatLit::try_from(give::<proc_macro::TokenTree>());
262 //! let _ = litrs::FloatLit::try_from(give::<&proc_macro::TokenTree>());
263 //!
264 //! let _ = litrs::CharLit::try_from(give::<proc_macro::TokenTree>());
265 //! let _ = litrs::CharLit::try_from(give::<&proc_macro::TokenTree>());
266 //!
267 //! let _ = litrs::StringLit::try_from(give::<proc_macro::TokenTree>());
268 //! let _ = litrs::StringLit::try_from(give::<&proc_macro::TokenTree>());
269 //!
270 //! let _ = litrs::ByteLit::try_from(give::<proc_macro::TokenTree>());
271 //! let _ = litrs::ByteLit::try_from(give::<&proc_macro::TokenTree>());
272 //!
273 //! let _ = litrs::ByteStringLit::try_from(give::<proc_macro::TokenTree>());
274 //! let _ = litrs::ByteStringLit::try_from(give::<&proc_macro::TokenTree>());
275 //! ```
276}
277
278#[cfg(feature = "proc-macro2")]
279mod tests_proc_macro2 {
280 //! # Tests
281 //!
282 //! ```no_run
283 //! extern crate proc_macro;
284 //!
285 //! use std::convert::TryFrom;
286 //! use litrs::Literal;
287 //!
288 //! fn give<T>() -> T {
289 //! panic!()
290 //! }
291 //!
292 //! let _ = litrs::Literal::from(give::<proc_macro2::Literal>());
293 //! let _ = litrs::Literal::from(give::<&proc_macro2::Literal>());
294 //!
295 //! let _ = litrs::Literal::try_from(give::<proc_macro2::TokenTree>());
296 //! let _ = litrs::Literal::try_from(give::<&proc_macro2::TokenTree>());
297 //!
298 //!
299 //! let _ = litrs::IntegerLit::try_from(give::<proc_macro2::Literal>());
300 //! let _ = litrs::IntegerLit::try_from(give::<&proc_macro2::Literal>());
301 //!
302 //! let _ = litrs::FloatLit::try_from(give::<proc_macro2::Literal>());
303 //! let _ = litrs::FloatLit::try_from(give::<&proc_macro2::Literal>());
304 //!
305 //! let _ = litrs::CharLit::try_from(give::<proc_macro2::Literal>());
306 //! let _ = litrs::CharLit::try_from(give::<&proc_macro2::Literal>());
307 //!
308 //! let _ = litrs::StringLit::try_from(give::<proc_macro2::Literal>());
309 //! let _ = litrs::StringLit::try_from(give::<&proc_macro2::Literal>());
310 //!
311 //! let _ = litrs::ByteLit::try_from(give::<proc_macro2::Literal>());
312 //! let _ = litrs::ByteLit::try_from(give::<&proc_macro2::Literal>());
313 //!
314 //! let _ = litrs::ByteStringLit::try_from(give::<proc_macro2::Literal>());
315 //! let _ = litrs::ByteStringLit::try_from(give::<&proc_macro2::Literal>());
316 //!
317 //!
318 //! let _ = litrs::BoolLit::try_from(give::<proc_macro2::TokenTree>());
319 //! let _ = litrs::BoolLit::try_from(give::<&proc_macro2::TokenTree>());
320 //!
321 //! let _ = litrs::IntegerLit::try_from(give::<proc_macro2::TokenTree>());
322 //! let _ = litrs::IntegerLit::try_from(give::<&proc_macro2::TokenTree>());
323 //!
324 //! let _ = litrs::FloatLit::try_from(give::<proc_macro2::TokenTree>());
325 //! let _ = litrs::FloatLit::try_from(give::<&proc_macro2::TokenTree>());
326 //!
327 //! let _ = litrs::CharLit::try_from(give::<proc_macro2::TokenTree>());
328 //! let _ = litrs::CharLit::try_from(give::<&proc_macro2::TokenTree>());
329 //!
330 //! let _ = litrs::StringLit::try_from(give::<proc_macro2::TokenTree>());
331 //! let _ = litrs::StringLit::try_from(give::<&proc_macro2::TokenTree>());
332 //!
333 //! let _ = litrs::ByteLit::try_from(give::<proc_macro2::TokenTree>());
334 //! let _ = litrs::ByteLit::try_from(give::<&proc_macro2::TokenTree>());
335 //!
336 //! let _ = litrs::ByteStringLit::try_from(give::<proc_macro2::TokenTree>());
337 //! let _ = litrs::ByteStringLit::try_from(give::<&proc_macro2::TokenTree>());
338 //! ```
339}