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}