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