macroex/
multi.rs

1use proc_macro2::TokenTree;
2
3use crate::{Extractor, FromMacro, Iter, Parenthesized, StreamExtract, CommaExtractor, EndOfStream};
4
5/// Extracts multiple items sequentiallly.
6/// # Example:
7/// ```
8/// # use macroex::*;
9/// # use quote::quote;
10/// # fn main() -> Result<(), Error> {
11/// let MultiExtractor((a, b, c)) = quote!(1 2.0 '3').into_iter().extract()?;
12/// # let _ = 1u8.max(a); let _ = 2.0f32.max(b); let _ = '3'.max(c);
13/// assert_eq!(a, 1);
14/// assert_eq!(b, 2.0);
15/// assert_eq!(c, '3');
16/// # Ok(())}
17/// ```
18#[derive(Debug)]
19pub struct MultiExtractor<T>(pub T);
20
21macro_rules! multi_extract_tuple {
22    () => {};
23    ($this: ident $(,$thing: ident)* $(,)?) => {
24        impl<$this, $($thing),*> Extractor for MultiExtractor<($this, $($thing),*)> where $this: Extractor, $($thing: Extractor),*{
25            fn extract(iter: &mut impl Iterator<Item=proc_macro2::TokenTree>) -> Result<Self, crate::Error> {
26                Ok(Self((
27                    $this::extract(iter)?,
28                    $($thing::extract(iter)?,)*
29                )))
30            }
31        }
32        multi_extract_tuple!($($thing),*);
33    };
34}
35
36multi_extract_tuple!(A, B, C, D, E, F, G, H, I, J, K, L,);
37
38macro_rules! tuple_impl {
39    () => {};
40    ($first: ident $(,$thing: ident)* $(,)?) => {
41        impl<$first, $($thing),*> FromMacro for ($first, $($thing),*) where $first: FromMacro, $($thing: FromMacro),* {
42            fn from_one(tt: TokenTree) -> Result<Self, crate::Error> {
43                let Parenthesized(Iter(mut iter)) = Parenthesized::from_one(tt)?;
44                let result = (
45                    {
46                        let CommaExtractor(x) = iter.extract::<CommaExtractor<$first>>()?;
47                        x
48                    },
49                    $({
50                        let CommaExtractor(x) = iter.extract::<CommaExtractor<$thing>>()?;
51                        x
52                    },)*
53                );
54                let EndOfStream = iter.extract()?;
55                Ok(result)
56            }
57        }
58        tuple_impl!($($thing),*);
59    };
60}
61
62tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L,);