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}