macroex/
either.rs

1use proc_macro2::{TokenTree, TokenStream};
2
3use crate::{FromMacro, abort, Error};
4
5/// Matches one of two [`FromMacro`] implementors by count.
6///
7/// * Uses [`One`](OneOrMany::One) if input is a [`TokenTree`]
8/// * Uses [`Many`](OneOrMany::Many) if input is a [`TokenStream`]
9#[derive(Debug)]
10pub enum OneOrMany<TOne, TMany>{
11    One(TOne),
12    Many(TMany),
13}
14
15impl<TOne, TMany> FromMacro for OneOrMany<TOne, TMany> where TOne: FromMacro, TMany: FromMacro{
16    fn from_one(tt: TokenTree) -> Result<Self, Error> {
17        Ok(Self::One(TOne::from_one(tt)?))
18    }
19
20    fn from_many(tokens: TokenStream) -> Result<Self, Error> {
21        Ok(Self::Many(TMany::from_many(tokens)?))
22    }
23}
24
25/// Either a [`TokenTree`] or a [`TokenStream`]
26pub type EitherStream = OneOrMany<TokenTree, TokenStream>;
27
28
29
30macro_rules! impl_choice {
31    ($name: ident {$($fields: ident),*}) => {
32
33/// Matches one of many [`FromMacro`] implementors sequentially.
34/// 
35/// Note the input will be cloned for each branch, which might not be optimal.
36#[derive(Debug)]
37pub enum $name<$($fields: FromMacro),*>{
38    $($fields($fields)),*
39}
40        
41impl<$($fields),*> FromMacro for $name<$($fields),*> where $($fields: FromMacro),* {
42    fn from_one(tt: proc_macro2::TokenTree) -> Result<Self, crate::Error> {
43        let span = tt.span();
44        $(
45            if $fields::peek(&tt) {
46                if let Ok(x) = $fields::from_one(tt.clone()) {
47                    return Ok(Self::$fields(x));
48                }
49            }
50        )*
51        abort!(span, FailedToMatch(tt.to_string()))
52    }
53
54    fn from_many(tokens: proc_macro2::TokenStream) -> Result<Self, crate::Error> {
55        $(if let Ok(x) = $fields::from_many(tokens.clone()) {
56            return Ok(Self::$fields(x));
57        })*
58        abort!(call_site, FailedToMatch(tokens.to_string()))
59    }
60}
61
62impl<$($fields),*> Default for $name<$($fields),*> where A: Default, $($fields: FromMacro),*{
63    fn default() -> Self {
64        Self::A(A::default())
65    }
66}
67
68
69#[cfg(feature="quote")]
70impl<$($fields),*> quote::ToTokens for $name<$($fields),*>where $($fields: FromMacro + quote::ToTokens),*{
71    #[allow(nonstandard_style)]
72    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
73        match self {
74            $($name::$fields($fields) => $fields.to_tokens(tokens)),*
75        }
76    }
77}
78    };
79}
80
81impl_choice!(Either {A, B});
82impl_choice!(Either3 {A, B, C});
83impl_choice!(Either4 {A, B, C, D});
84impl_choice!(Either5 {A, B, C, D, E});
85impl_choice!(Either6 {A, B, C, D, E, F});
86impl_choice!(Either7 {A, B, C, D, E, F, G});
87impl_choice!(Either8 {A, B, C, D, E, F, G, H});
88impl_choice!(Either9 {A, B, C, D, E, F, G, H, I});
89