use css_lexer::DynAtomSet;
use crate::{Cursor, Diagnostic, Parse, Parser, Peek, Result, T};
pub trait DiscreteFeature<'a>: Sized {
type Value: Parse<'a>;
#[allow(clippy::type_complexity)]
fn parse_discrete_feature<I>(
p: &mut Parser<'a, I>,
atom: &'static dyn DynAtomSet,
) -> Result<(T!['('], T![Ident], Option<(T![:], Self::Value)>, T![')'])>
where
I: Iterator<Item = Cursor> + Clone,
{
let open = p.parse::<T!['(']>()?;
let ident = p.parse::<T![Ident]>()?;
let c: Cursor = ident.into();
if !p.equals_atom(c, atom) {
Err(Diagnostic::new(c, Diagnostic::unexpected_ident))?
}
if <T![:]>::peek(p, p.peek_n(1)) {
let colon = p.parse::<T![:]>()?;
let value = p.parse::<Self::Value>()?;
let close = p.parse::<T![')']>()?;
Ok((open, ident, Some((colon, value)), close))
} else {
let close = p.parse::<T![')']>()?;
Ok((open, ident, None, close))
}
}
}
#[macro_export]
macro_rules! discrete_feature {
($(#[$meta:meta])* $vis:vis enum $feature: ident{$feature_name: path, $value: ty}) => {
$(#[$meta])*
$vis enum $feature {
WithValue($crate::T!['('], $crate::T![Ident], $crate::T![:], $value, $crate::T![')']),
Bare($crate::T!['('], $crate::T![Ident], $crate::T![')']),
}
impl<'a> $crate::Parse<'a> for $feature {
fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
where
I: Iterator<Item = $crate::Cursor> + Clone,
{
use $crate::DiscreteFeature;
let (open, ident, opt, close) = Self::parse_discrete_feature(p, &$feature_name)?;
if let Some((colon, value)) = opt {
Ok(Self::WithValue(open, ident, colon, value, close))
} else {
Ok(Self::Bare(open, ident, close))
}
}
}
impl<'a> $crate::DiscreteFeature<'a> for $feature {
type Value = $value;
}
};
}