macroex_extras/
lib.rs

1//! Additional "fun" extractors for macroex.
2
3use macroex::{proc_macro2::{TokenStream, TokenTree, Delimiter}, FromMacro, StreamExtract, All};
4use quote::ToTokens;
5
6mod angle;
7mod color;
8
9pub use angle::Angle;
10pub use color::Rgba;
11
12/// This replaces the idiom `Option<Either<CurlyBraced<TokenStream>, T>>` commonly
13/// used in parsing contents that may be expressions.
14#[derive(Debug, Clone, Default)]
15pub enum MaybeExpr<T, TExpr=TokenStream>{
16    #[default]
17    None,
18    Value(T),
19    Expr(TExpr),
20}
21
22impl<T, TExpr> MaybeExpr<T, TExpr> {
23    pub fn is_some(&self) -> bool {
24        !matches!(self, MaybeExpr::None)
25    }
26    
27    pub fn is_none(&self) -> bool {
28        matches!(self, MaybeExpr::None)
29    }
30
31    pub fn get(&self) -> Option<ValueOrExpr<T, TExpr>> {
32        match self {
33            MaybeExpr::None => None,
34            MaybeExpr::Expr(e) => Some(ValueOrExpr::Expr(e)),
35            MaybeExpr::Value(v) => Some(ValueOrExpr::Value(v)),
36        }
37    }
38}
39
40
41impl<T: FromMacro, TExpr: FromMacro> FromMacro for MaybeExpr<T, TExpr> {
42    fn from_one(tt: macroex::proc_macro2::TokenTree) -> Result<Self, macroex::Error> {
43        match tt {
44            TokenTree::Group(ref g) if g.delimiter() == Delimiter::Brace => {
45                let All(expr) = g.stream().into_iter().extract()?;
46                Ok(Self::Expr(expr))
47            },
48            tt => Ok(Self::Value(T::from_one(tt)?))
49        }
50    }
51}
52
53#[derive(Debug, Clone)]
54pub enum ValueOrExpr<'t, T, TExpr=TokenStream>{
55    Value(&'t T),
56    Expr(&'t TExpr),
57}
58
59
60impl<T: ToTokens, TExpr: ToTokens> quote::ToTokens for ValueOrExpr<'_, T, TExpr> {
61    fn to_tokens(&self, tokens: &mut TokenStream) {
62        match self {
63            ValueOrExpr::Value(v) => v.to_tokens(tokens),
64            ValueOrExpr::Expr(t) => t.to_tokens(tokens),
65        }
66    }
67}