use cssparser::BasicParseError;
pub(crate) use cssparser::{Parser, ParserInput, Token};
use std::borrow::Cow;
pub(crate) type CssParseError<'i> = cssparser::ParseError<'i, Cow<'i, str>>;
pub(crate) type CssParseResult<'i, T> = Result<T, CssParseError<'i>>;
#[derive(Clone, Debug)]
pub struct ParseError(String);
impl core::fmt::Display for ParseError {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(fmt, "{}", &self.0)
}
}
impl<'i> From<CssParseError<'i>> for ParseError {
fn from(value: CssParseError<'i>) -> Self {
Self(value.to_string())
}
}
impl<'i> From<BasicParseError<'i>> for ParseError {
fn from(value: BasicParseError<'i>) -> Self {
Self(CssParseError::from(value).to_string())
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseError {}
pub type ParseResult<T> = Result<T, ParseError>;
pub(crate) trait FromCss: Sized {
fn from_css<'i>(parser: &mut Parser<'i, '_>) -> CssParseResult<'i, Self>;
}
pub(crate) fn parse_css_str_entirely<T: FromCss>(input: &str) -> Result<T, ParseError> {
let mut parser_input = ParserInput::new(input);
let mut parser = Parser::new(&mut parser_input);
parser.parse_entirely(|parser| T::from_css(parser)).map_err(|err| ParseError(err.to_string()))
}
macro_rules! from_str_from_css {
($ty:ident) => {
#[cfg(feature = "parse")]
impl core::str::FromStr for $ty {
type Err = $crate::ParseError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
parse_css_str_entirely(input)
}
}
};
}
pub(crate) use from_str_from_css;
macro_rules! impl_parse_for_keyword_enum {
(
// The type name (followed by a comma)
$ty:ident,
$(
// 0-or-more metadata attributes (e.g. #[cfg] attributes for conditional compilation)
$( #[$meta: meta] )*
$keyword:literal => $enum_variant:ident,
)+
) => {
impl $crate::util::parse::FromCss for $ty {
fn from_css<'i>(input: &mut cssparser::Parser<'i, '_>) -> $crate::util::parse::CssParseResult<'i, Self> {
let ident = input.expect_ident()?;
cssparser::match_ignore_ascii_case! { &*ident,
$(
// Add the metadata attributes to the match case
$( #[$meta] )*
// If the keyword matches, return the corresponding variant of the enum
$keyword => return Ok(Self::$enum_variant),
)+
_ => {
let ident = ident.clone();
Err(input.new_unexpected_token_error(cssparser::Token::Ident(ident)))
}
}
}
}
impl core::str::FromStr for $ty {
type Err = $crate::ParseError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
$crate::util::parse::parse_css_str_entirely(input)
}
}
};
}
pub(crate) use impl_parse_for_keyword_enum;