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}