parse_more/
lib.rs

1//! # parse-more
2//! Parse-more is an extension of the [syn::parse::Parse] trait from the [syn](https://docs.rs/syn/) crate, allowing to parse input from procedural macros directly, without having to create a custom structure and implementing the [syn::parse::Parse] trait on it.
3//!
4//! It provides classic [syn](https://docs.rs/syn/) macros and functions variant, using the [ParseMore] trait instead.
5//!
6//! # Example
7//!
8//! ```
9//! # extern crate proc_macro;
10//! use quote::quote;
11//! use parse_more::{parse_more_macro_input, Concat, Braced};
12//! use proc_macro::TokenStream;
13//! use syn::{Expr, Ident, Token, punctuated::Punctuated};
14//!
15//! # const IGNORE_TOKENS: &str = stringify! {
16//! #[proc_macro]
17//! # };
18//! pub fn complex_args(input: TokenStream) -> TokenStream {
19//!    let content = parse_more_macro_input!(
20//!        input as Punctuated<Concat<Ident, Token![=>], Braced<(Ident, Expr)>>, Token![,]>
21//!    );
22//!    content
23//!        .into_iter()
24//!        .map(|concat| {
25//!            // Second item is discarded (it's the => arrow)
26//!            let (ident, _, Braced((other_ident, literal))) = concat.into();
27//!            quote! {
28//!                println!("{}: {} versus other type {}", #literal, (-1i8) as #ident, (-1i8) as #other_ident);
29//!            }
30//!        })
31//!        .collect::<proc_macro2::TokenStream>()
32//!        .into()
33//! }
34//! ```
35//! And then :
36//! ```
37//! # macro_rules! complex_args { ($($tt:tt)*) => {} }
38//! complex_args! {
39//!     u8 => {
40//!         (i8, "u8 integer")
41//!     },
42//!     u16 => {
43//!         (i16, "u16 integer")
44//!     },
45//!     Foo => {
46//!         (Bar, 8 + 42)
47//!     }
48//! }
49//! ```
50
51extern crate proc_macro;
52
53pub mod syn_types;
54
55/// Re-export `crate` as `parse_more` to use the `parse_more` macro easily.
56pub use crate as parse_more;
57
58/// Re-export proc macro.
59pub use parse_more_macros::{filler, parse_more};
60
61use syn::{
62    braced, bracketed, parenthesized,
63    parse::{Nothing, Parse},
64    punctuated::Punctuated,
65    LitInt, LitStr,
66};
67
68/// Parsing interface implemented by all types from the [syn] crate which already implement [syn::parse::Parse], and some others usefull ones.
69/// Use the [parse_more_auto_impl] macros to easily implement [ParseMore] on a type which already implement [syn::parse::Parse].
70pub trait ParseMore: Sized {
71    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self>;
72}
73
74/// This wrapper implements [syn::parse::Parse] when T implements [ParseMore]. It permits to use this wrapper and a type implementing [ParseMore] in a parsing function from [syn].
75///
76/// You should probably use [parse_more()], [parse_more_macro_input], or any other function from this crate instead of using this type directly.
77///
78/// # Example
79///
80/// ```
81/// # extern crate proc_macro;
82/// use quote::quote;
83/// use parse_more::ParseMoreWrapper;
84/// use proc_macro::TokenStream;
85/// use syn::{Ident, Token};
86///
87/// # const IGNORE_TOKENS: &str = stringify! {
88/// #[proc_macro]
89/// # };
90/// pub fn flip_identifiers(input: TokenStream) -> TokenStream {
91///     let (ident_a, arrow, ident_b) = syn::parse::<ParseMoreWrapper<(Ident, Token![=>], Ident)>>(input).unwrap().0;
92///     quote! {
93///         #ident_b <= #ident_a
94///     }.into()
95/// }
96/// ```
97pub struct ParseMoreWrapper<T>(pub T);
98
99/// Call the [ParseMore::parse] method.
100impl<T: ParseMore> Parse for ParseMoreWrapper<T> {
101    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
102        Ok(ParseMoreWrapper(ParseMore::parse(input)?))
103    }
104}
105
106/// This macro auto-implements the [ParseMore] traits on its arguments, which *MUST* implement the [syn::parse::Parse] trait.
107/// It allows using custom types inside of any parse-more macros/functions.
108///
109/// See the [macro@parse_more] macro.
110///
111/// # Example
112///
113/// ```
114/// use parse_more::parse_more_auto_impl;
115/// use syn::{Ident, Token};
116///
117/// struct MyParsedStruct(Ident, Ident);
118///
119/// impl syn::parse::Parse for MyParsedStruct {
120///     fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
121///         let a = input.parse()?;
122///         input.parse::<Token![=>]>()?;
123///         let b = input.parse()?;
124///         Ok(Self(a, b))
125///     }
126/// }
127///
128/// parse_more_auto_impl! {
129///     MyParsedStruct
130/// }
131/// ```
132#[macro_export]
133macro_rules! parse_more_auto_impl {
134    ($($ty:ty),*) => {
135        $(impl $crate::ParseMore for $ty {
136            fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
137                <Self as syn::parse::Parse>::parse(input)
138            }
139        })*
140    }
141}
142
143/// Implement [ParseMore] for a given tuple.
144macro_rules! tuple_impls {
145    ($first:ident) => {
146        impl<$first:ParseMore> ParseMore for ($first, ) {
147            fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
148                let content;
149                parenthesized!(content in input);
150                let first = content.parse::<ParseMoreWrapper<$first>>()?.0;
151                content.parse::<syn::Token![,]>()?;
152                Ok((first,))
153            }
154        }
155    };
156    ($first:ident $($generics:ident)*) => {
157        impl<$first:ParseMore, $($generics: ParseMore),*> ParseMore for ($first, $($generics,)*) {
158            fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
159                let content;
160                parenthesized!(content in input);
161                let first = content.parse::<ParseMoreWrapper<$first>>()?.0;
162                let res = Ok((first,
163                    $({
164                        content.parse::<syn::Token![,]>()?;
165                        content.parse::<ParseMoreWrapper<$generics>>()?.0
166                    },)*
167                ));
168
169                // If there is a remaining comma, parse it
170                if content.peek(syn::Token![,]) {
171                    content.parse::<syn::Token![,]>().unwrap();
172                }
173                res
174            }
175        }
176    };
177}
178
179/// Inner code of the [for_each_tuple] macro.
180macro_rules! for_each_tuple_ {
181    ($mac:ident =>) => {};
182    ($mac:ident => $first:ident, $($generics:ident,)*) => {
183        $mac! {
184            $first $($generics)*
185        }
186        for_each_tuple_ ! {
187            $mac => $($generics,)*
188        }
189    };
190}
191
192/// Call a macro over every tuple size between 1 and 20.
193macro_rules! for_each_tuple {
194    ($mac:ident) => {
195        for_each_tuple_! {
196            $mac => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T,
197        }
198    };
199}
200
201// Generate [ParseMore] impls for tuples.
202for_each_tuple! {
203    tuple_impls
204}
205
206/// Implement [ParseMore] for the array type.
207/// ```
208/// # extern crate proc_macro;
209/// use quote::quote;
210/// use parse_more::parse_more_macro_input;
211/// use proc_macro::TokenStream;
212/// use syn::{Ident, Token};
213///
214/// # const IGNORE_TOKENS: &str = stringify! {
215/// #[proc_macro]
216/// # };
217/// pub fn identifiers_sum(input: TokenStream) -> TokenStream {
218///     let idents = parse_more_macro_input!(input as [Ident; 3]);
219///     let [a, b, c] = idents;
220///     quote! {
221///         #a + #b + #c
222///     }.into()
223/// }
224/// ```
225impl<T: ParseMore, const N: usize> ParseMore for [T; N] {
226    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
227        let content;
228        bracketed!(content in input);
229
230        let mut res = vec![];
231        for i in 0..N {
232            if i != 0 {
233                content.parse::<syn::Token![,]>()?;
234            }
235            res.push(content.parse::<ParseMoreWrapper<T>>()?.0)
236        }
237
238        // If there is a remaining comma, parse it
239        if content.peek(syn::Token![,]) {
240            content.parse::<syn::Token![,]>().unwrap();
241        }
242        Ok(unsafe { res.try_into().unwrap_unchecked() })
243    }
244}
245
246/// Implement [ParseMore] for the [Vec] type, with a behaviour similar to [syn::punctuated::Punctuated<T, syn::parse::Nothing>]
247/// ```
248/// # extern crate proc_macro;
249/// use quote::quote;
250/// use parse_more::parse_more_macro_input;
251/// use proc_macro::TokenStream;
252/// use syn::Ident;
253///
254/// # const IGNORE_TOKENS: &str = stringify! {
255/// #[proc_macro]
256/// # };
257/// pub fn identifiers_sum(input: TokenStream) -> TokenStream {
258///     let idents = parse_more_macro_input!(input as Vec<Ident>);
259///     idents.into_iter().map(|ident| quote! {
260///         #ident
261///     }).collect::<proc_macro2::TokenStream>().into()
262/// }
263/// ```
264impl<T: ParseMore> ParseMore for Vec<T> {
265    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
266        let mut res = vec![];
267        while let Ok(parsed) = input.parse::<ParseMoreWrapper<T>>() {
268            res.push(parsed.0);
269        }
270        Ok(res)
271    }
272}
273
274/// Implement [ParseMore] for the [syn::punctuated::Punctuated] type.
275/// ```
276/// # extern crate proc_macro;
277/// use quote::quote;
278/// use parse_more::parse_more_macro_input;
279/// use proc_macro::TokenStream;
280/// use syn::{Ident, Token, punctuated::Punctuated};
281///
282/// # const IGNORE_TOKENS: &str = stringify! {
283/// #[proc_macro]
284/// # };
285/// pub fn identifiers_sum(input: TokenStream) -> TokenStream {
286///     let idents = parse_more_macro_input!(input as Punctuated<Ident, Token![,]>);
287///     idents.into_iter().map(|ident| quote! {
288///         #ident
289///     }).collect::<proc_macro2::TokenStream>().into()
290/// }
291/// ```
292impl<T: ParseMore, P: ParseMore> ParseMore for Punctuated<T, P> {
293    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
294        let mut res = Punctuated::new();
295        let wrapped =
296            Punctuated::<ParseMoreWrapper<T>, ParseMoreWrapper<P>>::parse_terminated(input)?;
297
298        // Unwrap parsed values
299        wrapped.into_pairs().for_each(|pair| {
300            let pair = pair.into_tuple();
301            res.push_value(pair.0 .0);
302            if let Some(punct) = pair.1 {
303                res.push_punct(punct.0);
304            }
305        });
306
307        Ok(res)
308    }
309}
310
311/// Parse successive items.
312#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
313#[parse_more]
314pub struct Concat<A, B, C = Nothing, D = Nothing, E = Nothing, F = Nothing, G = Nothing> {
315    first: A,
316    second: B,
317    third: C,
318    fourth: D,
319    fifth: E,
320    sixth: F,
321    seventh: G,
322}
323
324impl<A, B, C, D, E, F, G> From<Concat<A, B, C, D, E, F, G>> for (A, B, C, D, E, F, G) {
325    fn from(value: Concat<A, B, C, D, E, F, G>) -> Self {
326        (
327            value.first,
328            value.second,
329            value.third,
330            value.fourth,
331            value.fifth,
332            value.sixth,
333            value.seventh,
334        )
335    }
336}
337impl<A, B, C, D, E, F> From<Concat<A, B, C, D, E, F>> for (A, B, C, D, E, F) {
338    fn from(value: Concat<A, B, C, D, E, F>) -> Self {
339        (
340            value.first,
341            value.second,
342            value.third,
343            value.fourth,
344            value.fifth,
345            value.sixth,
346        )
347    }
348}
349impl<A, B, C, D, E> From<Concat<A, B, C, D, E>> for (A, B, C, D, E) {
350    fn from(value: Concat<A, B, C, D, E>) -> Self {
351        (
352            value.first,
353            value.second,
354            value.third,
355            value.fourth,
356            value.fifth,
357        )
358    }
359}
360impl<A, B, C, D> From<Concat<A, B, C, D>> for (A, B, C, D) {
361    fn from(value: Concat<A, B, C, D>) -> Self {
362        (value.first, value.second, value.third, value.fourth)
363    }
364}
365impl<A, B, C> From<Concat<A, B, C>> for (A, B, C) {
366    fn from(value: Concat<A, B, C>) -> Self {
367        (value.first, value.second, value.third)
368    }
369}
370impl<A, B> From<Concat<A, B>> for (A, B) {
371    fn from(value: Concat<A, B>) -> Self {
372        (value.first, value.second)
373    }
374}
375impl<A, B> Concat<A, B> {
376    /// Convert itself to a tuple containing the parsed values.
377    pub fn into_tuple2(self) -> (A, B) {
378        self.into()
379    }
380}
381impl<A, B, C> Concat<A, B, C> {
382    /// Convert itself to a tuple containing the parsed values.
383    pub fn into_tuple3(self) -> (A, B, C) {
384        self.into()
385    }
386}
387impl<A, B, C, D> Concat<A, B, C, D> {
388    /// Convert itself to a tuple containing the parsed values.
389    pub fn into_tuple4(self) -> (A, B, C, D) {
390        self.into()
391    }
392}
393impl<A, B, C, D, E> Concat<A, B, C, D, E> {
394    /// Convert itself to a tuple containing the parsed values.
395    pub fn into_tuple5(self) -> (A, B, C, D, E) {
396        self.into()
397    }
398}
399impl<A, B, C, D, E, F> Concat<A, B, C, D, E, F> {
400    /// Convert itself to a tuple containing the parsed values.
401    pub fn into_tuple6(self) -> (A, B, C, D, E, F) {
402        self.into()
403    }
404}
405impl<A, B, C, D, E, F, G> Concat<A, B, C, D, E, F, G> {
406    /// Convert itself to a tuple containing the parsed values.
407    pub fn into_tuple7(self) -> (A, B, C, D, E, F, G) {
408        self.into()
409    }
410}
411
412/// Parse an item surrounded by braces.
413#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
414pub struct Braced<T>(pub T);
415
416/// Imlement [ParseMore] for the [Braced] type.
417impl<T: ParseMore> ParseMore for Braced<T> {
418    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
419        let content;
420        braced!(content in input);
421        Ok(Self(content.parse::<ParseMoreWrapper<T>>()?.0))
422    }
423}
424
425impl<T> Braced<T> {
426    /// Get the parsed value.
427    pub fn value(self) -> T {
428        self.0
429    }
430}
431
432/// Parse an item surrounded by parenthesis.
433#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
434pub struct Parenthesized<T>(pub T);
435
436/// Imlement [ParseMore] for the [Parenthesized] type.
437impl<T: ParseMore> ParseMore for Parenthesized<T> {
438    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
439        let content;
440        parenthesized!(content in input);
441        Ok(Self(content.parse::<ParseMoreWrapper<T>>()?.0))
442    }
443}
444
445impl<T> Parenthesized<T> {
446    /// Get the parsed value.
447    pub fn value(self) -> T {
448        self.0
449    }
450}
451
452/// Parse an item surrounded by brackets.
453#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
454pub struct Bracketed<T>(pub T);
455
456/// Imlement [ParseMore] for the [Bracketed] type.
457impl<T: ParseMore> ParseMore for Bracketed<T> {
458    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
459        let content;
460        bracketed!(content in input);
461        Ok(Self(content.parse::<ParseMoreWrapper<T>>()?.0))
462    }
463}
464
465impl<T> Bracketed<T> {
466    /// Get the parsed value.
467    pub fn value(self) -> T {
468        self.0
469    }
470}
471
472/// Imlement [ParseMore] for the [Option] type.
473impl<T: ParseMore> ParseMore for Option<T> {
474    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
475        // Fork the input to be sure to don't advance the cursor if the parsing fails.
476        let input_forked = input.fork();
477        if let Ok(parsed) = input_forked.parse::<ParseMoreWrapper<T>>() {
478            // Parse it on the primary stream too to advance the cursor
479            // It should not fails.
480            assert!(input.parse::<ParseMoreWrapper<T>>().is_ok());
481            Ok(Some(parsed.0))
482        } else {
483            Ok(None)
484        }
485    }
486}
487
488/// Parse an item surrounded by brackets.
489#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
490pub struct Invalid;
491
492/// Imlement [ParseMore] for the [Invalid] type.
493impl ParseMore for Invalid {
494    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
495        Err(syn::Error::new(input.span(), "Invalid can never be parsed"))
496    }
497}
498
499/// Parse an item in a given list. If multiple types can be parsed, the first one is chosen.
500#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
501#[parse_more]
502pub enum Either<A, B, C = Invalid, D = Invalid, E = Invalid, F = Invalid, G = Invalid> {
503    First(A),
504    Second(B),
505    Third(C),
506    Fourth(D),
507    Fifth(E),
508    Sixth(F),
509    Seventh(G),
510}
511
512impl<A, B, C, D, E, F, G> Either<A, B, C, D, E, F, G> {
513    /// Check if the type of the parsed value is the first one.
514    pub fn is_first(&self) -> bool {
515        matches!(self, Either::First(_))
516    }
517    /// Check if the type of the parsed value is the second one.
518    pub fn is_second(&self) -> bool {
519        matches!(self, Either::Second(_))
520    }
521    /// Check if the type of the parsed value is the third one.
522    pub fn is_third(&self) -> bool {
523        matches!(self, Either::Third(_))
524    }
525    /// Check if the type of the parsed value is the fourth one.
526    pub fn is_fourth(&self) -> bool {
527        matches!(self, Either::Fourth(_))
528    }
529    /// Check if the type of the parsed value is the fifth one.
530    pub fn is_fifth(&self) -> bool {
531        matches!(self, Either::Fifth(_))
532    }
533    /// Check if the type of the parsed value is the sixth one.
534    pub fn is_sixth(&self) -> bool {
535        matches!(self, Either::Sixth(_))
536    }
537    /// Check if the type of the parsed value is the seveth one.
538    pub fn is_seventh(&self) -> bool {
539        matches!(self, Either::Seventh(_))
540    }
541}
542
543macro_rules! integer_impls {
544    ($($ty:ty),*) => {
545        $(
546            /// Imlement [ParseMore] for the [u8] type.
547            impl ParseMore for $ty {
548                fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
549                    input.parse::<LitInt>()?.base10_parse::<Self>()
550                }
551            }
552        )*
553    };
554}
555
556integer_impls! {
557    u8, u16, u32, u64, u128, usize,
558    i8, i16, i32, i64, i128, isize
559}
560
561/// Imlement [ParseMore] for the [String] type.
562impl ParseMore for String {
563    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
564        Ok(input.parse::<LitStr>()?.value())
565    }
566}
567
568/// Same as the [syn::parse_quote] macro, but using the [ParseMore] trait.
569#[macro_export]
570macro_rules! parse_more_quote {
571    ($($tt:tt)*) => {{
572        // Add an type hint for the compiler
573        let __tmp: $crate::ParseMoreWrapper<_> = syn::parse_quote!($($tt:tt)*);
574        __tmp.0
575    }};
576}
577
578/// Same as the [syn::parse_macro_input] macro, but using the [ParseMore] trait.
579#[macro_export]
580macro_rules! parse_more_macro_input {
581    ($tokenstream:ident as $ty:ty) => {
582        match $crate::parse_more::<$ty>($tokenstream) {
583            Ok(data) => data,
584            Err(err) => {
585                return proc_macro::TokenStream::from(err.to_compile_error());
586            }
587        }
588    };
589    ($tokenstream:ident) => {
590        $crate::parse_more_macro_input!($tokenstream as _)
591    };
592}
593
594/// Same as the [syn::parse()] function, but using the [ParseMore] trait.
595pub fn parse_more<T: ParseMore>(tokens: proc_macro::TokenStream) -> syn::Result<T> {
596    Ok(syn::parse::<ParseMoreWrapper<T>>(tokens)?.0)
597}
598
599/// Same as the [syn::parse2] function, but using the [ParseMore] trait.
600pub fn parse2_more<T: ParseMore>(tokens: proc_macro2::TokenStream) -> syn::Result<T> {
601    Ok(syn::parse2::<ParseMoreWrapper<T>>(tokens)?.0)
602}
603
604/// Same as the [syn::parse_str] function, but using the [ParseMore] trait.
605pub fn parse_more_str<T: ParseMore>(s: &str) -> syn::Result<T> {
606    Ok(syn::parse_str::<ParseMoreWrapper<T>>(s)?.0)
607}