unsynn/
rust_types.rs

1//! Parsers for rusts types.
2//!
3//! **Note**: When the `proc_macro2` feature is disabled, `ToTokens` implementations for
4//! `&str` and `String` are not available.
5
6use crate::{
7    Error, Ident, LiteralCharacter, LiteralInteger, Parse, Parser, RefineErr, Result, Span,
8    ToTokens, TokenIter, TokenStream, TokenTree,
9};
10
11// Parser and ToTokens for unsigned integer types
12macro_rules! impl_unsigned_integer {
13    ($($ty:ty),*) => {
14        $(
15            #[doc = stringify!(Parse $ty may have a positive sign but no suffix)]
16            impl Parser for $ty {
17                fn parser(tokens: &mut TokenIter) -> Result<Self> {
18                    let at = tokens.clone().next();
19                    let lit = crate::Cons::<Option<crate::Plus>, LiteralInteger>::parser(tokens).refine_err::<Self>()?;
20                    <$ty>::try_from(lit.second.value())
21                        .or_else(|e| Error::dynamic::<Self>(at, tokens, e))
22                }
23            }
24
25            #[doc = stringify!(Emit a literal $ty without sign and suffix)]
26            impl ToTokens for $ty {
27                fn to_tokens(&self, tokens: &mut TokenStream) {
28                    #[allow(clippy::cast_lossless)]
29                    LiteralInteger::new(*self as u128).to_tokens(tokens);
30                }
31            }
32
33            #[doc = stringify!(Emit a literal $ty without sign and suffix)]
34            impl ToTokens for &$ty {
35                fn to_tokens(&self, tokens: &mut TokenStream) {
36                    #[allow(clippy::cast_lossless)]
37                    LiteralInteger::new(**self as u128).to_tokens(tokens);
38                }
39            }
40        )*
41    };
42}
43
44impl_unsigned_integer! {u8, u16, u32, u64, u128, usize}
45
46// Parser and ToTokens for signed integer types
47macro_rules! impl_signed_integer {
48    ($($ty:ty),*) => {
49        $(
50            #[doc = stringify!(Parse $ty may have a positive or negative sign but no suffix)]
51            impl Parser for $ty {
52                fn parser(tokens: &mut TokenIter) -> Result<Self> {
53                    let at = tokens.clone().next();
54                    let lit = crate::Cons::<Option<crate::Either<crate::Plus, crate::Minus>>, LiteralInteger>::parser(tokens).refine_err::<Self>()?;
55                    let value = <$ty>::try_from(lit.second.value())
56                        .or_else(|e| Error::dynamic::<Self>(at, tokens, e))?;
57                    match lit.first {
58                        Some(crate::Either::Second(_)) => Ok(-value),
59                        _ => Ok(value),
60                    }
61                }
62            }
63
64            #[doc = stringify!(Emit a literal $ty with negative sign and without suffix)]
65            impl ToTokens for $ty {
66                fn to_tokens(&self, tokens: &mut TokenStream) {
67                    if *self < 0 {
68                        crate::Minus::new().to_tokens(tokens);
69                    }
70                    LiteralInteger::new(self.abs().try_into().unwrap()).to_tokens(tokens);
71                }
72            }
73
74            #[doc = stringify!(Emit a literal $ty with negative sign and without suffix)]
75            impl ToTokens for &$ty {
76                fn to_tokens(&self, tokens: &mut TokenStream) {
77                    if **self < 0 {
78                        crate::Minus::new().to_tokens(tokens);
79                    }
80                    LiteralInteger::new(self.abs().try_into().unwrap()).to_tokens(tokens);
81                }
82            }
83        )*
84    };
85}
86
87impl_signed_integer! {i8, i16, i32, i64, i128, isize}
88
89// Parser and ToTokens for char
90impl Parser for char {
91    fn parser(tokens: &mut TokenIter) -> Result<Self> {
92        let lit = LiteralCharacter::parser(tokens).refine_err::<Self>()?;
93        Ok(lit.value())
94    }
95}
96
97impl ToTokens for char {
98    fn to_tokens(&self, tokens: &mut TokenStream) {
99        LiteralCharacter::new(*self).to_tokens(tokens);
100    }
101}
102
103// Helper function for parsing bool identifiers without proc_macro2.
104// This is tested in the proc-macro workspace (tests-proc-macro/) where proc_macro2
105// is disabled. cargo-mutants only tests the main workspace with default features
106// (proc_macro2 enabled), where this code is not compiled. Therefore, we skip mutation testing.
107#[cfg(not(feature = "proc_macro2"))]
108#[mutants::skip]
109fn parse_bool_ident(ident: &Ident, at: Option<TokenTree>, tokens: &mut TokenIter) -> Result<bool> {
110    let ident_str = ident.to_string();
111    if ident_str == "true" {
112        Ok(true)
113    } else if ident_str == "false" {
114        Ok(false)
115    } else {
116        Error::unexpected_token(at, tokens)
117    }
118}
119
120// Parser and ToTokens for bool
121/// Parse a boolean value from the input stream.
122/// Only `true` and `false` are valid boolean values.
123impl Parser for bool {
124    fn parser(tokens: &mut TokenIter) -> Result<Self> {
125        let at = tokens.clone().next();
126        Ident::parse_with(tokens, |ident, tokens| {
127            // proc_macro2::Ident implements PartialEq<&str>, so we can compare directly without allocation
128            // proc_macro::Ident does not, so we need to_string() which allocates
129            #[cfg(feature = "proc_macro2")]
130            {
131                if ident == "true" {
132                    Ok(true)
133                } else if ident == "false" {
134                    Ok(false)
135                } else {
136                    Error::unexpected_token(at, tokens)
137                }
138            }
139            #[cfg(not(feature = "proc_macro2"))]
140            {
141                parse_bool_ident(&ident, at, tokens)
142            }
143        })
144        .refine_err::<Self>()
145    }
146}
147
148impl ToTokens for bool {
149    fn to_tokens(&self, tokens: &mut TokenStream) {
150        Ident::new(if *self { "true" } else { "false" }, Span::call_site()).to_tokens(tokens);
151    }
152}
153
154/// Parse a `String` from the input stream.  Parsing into a string is special as it parses any
155/// kind of `TokenTree` and converts it `.to_string()`. Thus it looses its relationship to the
156/// type of the underlying token/syntactic entity. This is only useful when one wants to parse
157/// string like parameters in a macro that are not emitted later. This limits the use of this
158/// parser significantly.
159impl Parser for String {
160    fn parser(tokens: &mut TokenIter) -> Result<Self> {
161        TokenTree::parse_with(tokens, |token, _| Ok(token.to_string())).refine_err::<Self>()
162    }
163}
164
165/// Tokenizes a `&str`. Panics if the input string does not tokenize.
166///
167/// # Example
168///
169/// ```
170/// # use unsynn::*;
171/// let mut tokens = "foo -> {1,2,3}".to_token_stream();
172///
173/// assert_tokens_eq!(
174///     tokens,
175///     "foo -> { 1 , 2 , 3 }"
176/// );
177/// ```
178#[cfg(feature = "proc_macro2")]
179impl ToTokens for &str {
180    fn to_tokens(&self, tokens: &mut TokenStream) {
181        use std::str::FromStr;
182        let ts = TokenStream::from_str(self).expect("Failed to tokenize input string.");
183        tokens.extend(ts);
184    }
185}
186
187#[cfg(feature = "proc_macro2")]
188impl ToTokens for str {
189    fn to_tokens(&self, tokens: &mut TokenStream) {
190        use std::str::FromStr;
191        let ts = TokenStream::from_str(self).expect("Failed to tokenize input string.");
192        tokens.extend(ts);
193    }
194}
195
196#[cfg(feature = "proc_macro2")]
197impl ToTokens for &String {
198    fn to_tokens(&self, tokens: &mut TokenStream) {
199        self.as_str().to_tokens(tokens);
200    }
201}
202
203/// `PhantomData` behaves like `Nothing` it doesn't parse anything and doesnt emit tokens.
204impl<T> Parser for std::marker::PhantomData<T> {
205    #[inline]
206    #[mutants::skip]
207    fn parser(_tokens: &mut TokenIter) -> Result<Self> {
208        Ok(Self)
209    }
210}
211
212impl<T> ToTokens for std::marker::PhantomData<T> {
213    #[inline]
214    fn to_tokens(&self, _tokens: &mut TokenStream) {
215        /*NOP*/
216    }
217}
218
219// Parser and ToTokens implementations for tuples
220
221/// Parse a 2-element tuple by parsing each element in sequence.
222///
223/// This provides a more idiomatic alternative to [`Cons`](crate::Cons) for simple cases.
224///
225/// # Example
226///
227/// ```
228/// # use unsynn::*;
229/// let mut tokens = "42 true".to_token_iter();
230/// let (num, flag): (u8, bool) = Parse::parse(&mut tokens).unwrap();
231/// assert_eq!(num, 42);
232/// assert_eq!(flag, true);
233/// ```
234impl<A: Parse, B: Parse> Parser for (A, B) {
235    fn parser(tokens: &mut TokenIter) -> Result<Self> {
236        Ok((A::parser(tokens)?, B::parser(tokens)?))
237    }
238}
239
240/// Emit tokens for a 2-element tuple by emitting each element in sequence.
241///
242/// # Example
243///
244/// ```
245/// # use unsynn::*;
246/// let mut tokens = TokenStream::new();
247/// (42u8, true).to_tokens(&mut tokens);
248/// assert_eq!(tokens.to_string(), "42 true");
249/// ```
250impl<A: ToTokens, B: ToTokens> ToTokens for (A, B) {
251    fn to_tokens(&self, tokens: &mut TokenStream) {
252        self.0.to_tokens(tokens);
253        self.1.to_tokens(tokens);
254    }
255}
256
257/// Parse a 3-element tuple by parsing each element in sequence.
258///
259/// # Example
260///
261/// ```
262/// # use unsynn::*;
263/// let mut tokens = "foo + 42".to_token_iter();
264/// let (id, op, num): (Ident, Punct, u8) = Parse::parse(&mut tokens).unwrap();
265/// assert_eq!(id.to_string(), "foo");
266/// assert_eq!(op.to_string(), "+");
267/// assert_eq!(num, 42);
268/// ```
269impl<A: Parse, B: Parse, C: Parse> Parser for (A, B, C) {
270    fn parser(tokens: &mut TokenIter) -> Result<Self> {
271        Ok((A::parser(tokens)?, B::parser(tokens)?, C::parser(tokens)?))
272    }
273}
274
275/// Emit tokens for a 3-element tuple by emitting each element in sequence.
276impl<A: ToTokens, B: ToTokens, C: ToTokens> ToTokens for (A, B, C) {
277    fn to_tokens(&self, tokens: &mut TokenStream) {
278        self.0.to_tokens(tokens);
279        self.1.to_tokens(tokens);
280        self.2.to_tokens(tokens);
281    }
282}
283
284/// Parse a 4-element tuple by parsing each element in sequence.
285///
286/// # Example
287///
288/// ```
289/// # use unsynn::*;
290/// let mut tokens = "5 true 'a' 255".to_token_iter();
291/// let tuple: (u8, bool, char, u8) = Parse::parse(&mut tokens).unwrap();
292/// assert_eq!(tuple, (5, true, 'a', 255));
293/// ```
294impl<A: Parse, B: Parse, C: Parse, D: Parse> Parser for (A, B, C, D) {
295    fn parser(tokens: &mut TokenIter) -> Result<Self> {
296        Ok((
297            A::parser(tokens)?,
298            B::parser(tokens)?,
299            C::parser(tokens)?,
300            D::parser(tokens)?,
301        ))
302    }
303}
304
305/// Emit tokens for a 4-element tuple by emitting each element in sequence.
306impl<A: ToTokens, B: ToTokens, C: ToTokens, D: ToTokens> ToTokens for (A, B, C, D) {
307    fn to_tokens(&self, tokens: &mut TokenStream) {
308        self.0.to_tokens(tokens);
309        self.1.to_tokens(tokens);
310        self.2.to_tokens(tokens);
311        self.3.to_tokens(tokens);
312    }
313}