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