#[derive(Debug, Clone)]
pub enum SupportsCondition
{
Not(Box<SupportsCondition>),
Parenthesized(Box<SupportsCondition>),
And(Vec<SupportsCondition>),
Or(Vec<SupportsCondition>),
Declaration(SupportsPropertyDeclaration),
FutureSyntax(String),
}
impl ToCss for SupportsCondition
{
fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result
{
match *self
{
Not(ref condition) =>
{
dest.write_str("not ")?;
condition.to_css(dest)
}
Parenthesized(ref condition) =>
{
dest.write_str("(")?;
condition.to_css(dest)?;
dest.write_str(")")
}
And(ref conditions) =>
{
let mut first = true;
for condition in conditions
{
if first
{
first = false;
}
else
{
dest.write_str(" and ")?;
}
condition.to_css(dest)?;
}
Ok(())
}
Or(ref conditions) =>
{
let mut first = true;
for condition in conditions
{
if first
{
first = false;
}
else
{
dest.write_str(" or ")?;
}
condition.to_css(dest)?;
}
Ok(())
}
Declaration(ref declaration) =>
{
dest.write_str("(")?;
declaration.to_css(dest)?;
dest.write_str(")")
}
FutureSyntax(ref value) => dest.write_str(&value),
}
}
}
impl SupportsCondition
{
pub(crate) fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, CustomParseError<'i>>>
{
if let Ok(_) = input.try(|i| i.expect_ident_matching("not"))
{
let inner = Self::parse_in_parentheses(input)?;
return Ok(Not(Box::new(inner)));
}
let in_parentheses = Self::parse_in_parentheses(input)?;
let (keyword, wrapper) = match input.next()
{
Err(_) => return Ok(in_parentheses),
Ok(&Ident(ref ident)) =>
{
match_ignore_ascii_case!
{
&ident,
"and" => ("and", And as fn(_) -> _),
"or" => ("or", Or as fn(_) -> _),
_ => return Err(ParseError::Custom(CustomParseError::InvalidSupportsCondition(ident.clone())))
}
}
Ok(unexpectedToken) => return Err(ParseError::Basic(BasicParseError::UnexpectedToken(unexpectedToken.clone()))),
};
let mut conditions = Vec::with_capacity(2);
conditions.push(in_parentheses);
loop
{
conditions.push(Self::parse_in_parentheses(input)?);
if input.try(|input| input.expect_ident_matching(keyword)).is_err()
{
return Ok(wrapper(conditions))
}
}
}
fn parse_in_parentheses<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, CustomParseError<'i>>>
{
while input.try(Parser::expect_whitespace).is_ok()
{
}
let pos = input.position();
match input.next()?.clone()
{
ParenthesisBlock =>
{
let nested = input.try(|input|
{
input.parse_nested_block(|i| Self::parse_condition_or_declaration(i))
});
if nested.is_ok()
{
return nested;
}
}
Function(_) =>
{
}
unexpectedToken => return Err(ParseError::Basic(BasicParseError::UnexpectedToken(unexpectedToken))),
}
input.parse_nested_block(|i| consume_any_value(i))?;
Ok(FutureSyntax(input.slice_from(pos).to_owned()))
}
fn parse_condition_or_declaration<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, CustomParseError<'i>>>
{
if let Ok(condition) = input.try(Self::parse)
{
Ok(Parenthesized(Box::new(condition)))
}
else
{
SupportsPropertyDeclaration::parse(input).map(Declaration)
}
}
}