use std::error;
use std::fmt;
use cssparser::{BasicParseError, BasicParseErrorKind, ParseErrorKind, ToCss};
use markup5ever::QualName;
#[cfg(doc)]
use crate::RenderingError;
use crate::document::NodeId;
use crate::io::IoError;
use crate::limits;
use crate::node::Node;
pub type ParseError<'i> = cssparser::ParseError<'i, ValueErrorKind>;
#[derive(Debug, Clone)]
pub enum ValueErrorKind {
UnknownProperty,
Parse(String),
Value(String),
}
impl ValueErrorKind {
pub fn parse_error(s: &str) -> ValueErrorKind {
ValueErrorKind::Parse(s.to_string())
}
pub fn value_error(s: &str) -> ValueErrorKind {
ValueErrorKind::Value(s.to_string())
}
}
impl fmt::Display for ValueErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ValueErrorKind::UnknownProperty => write!(f, "unknown property name"),
ValueErrorKind::Parse(ref s) => write!(f, "parse error: {s}"),
ValueErrorKind::Value(ref s) => write!(f, "invalid value: {s}"),
}
}
}
impl<'a> From<BasicParseError<'a>> for ValueErrorKind {
fn from(e: BasicParseError<'_>) -> ValueErrorKind {
let BasicParseError { kind, .. } = e;
let msg = match kind {
BasicParseErrorKind::UnexpectedToken(_) => "unexpected token",
BasicParseErrorKind::EndOfInput => "unexpected end of input",
BasicParseErrorKind::AtRuleInvalid(_) => "invalid @-rule",
BasicParseErrorKind::AtRuleBodyInvalid => "invalid @-rule body",
BasicParseErrorKind::QualifiedRuleInvalid => "invalid qualified rule",
};
ValueErrorKind::parse_error(msg)
}
}
#[derive(Debug, Clone)]
pub struct ElementError {
pub attr: QualName,
pub err: ValueErrorKind,
}
impl fmt::Display for ElementError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}: {}", self.attr.expanded(), self.err)
}
}
#[derive(Debug, Clone)]
pub enum DefsLookupErrorKind {
InvalidId,
NotFound,
}
impl fmt::Display for DefsLookupErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
DefsLookupErrorKind::InvalidId => write!(f, "invalid id"),
DefsLookupErrorKind::NotFound => write!(f, "not found"),
}
}
}
#[derive(Clone)]
pub enum InternalRenderingError {
Rendering(String),
LimitExceeded(ImplementationLimit),
InvalidTransform,
CircularReference(Node),
IdNotFound,
InvalidId(String),
OutOfMemory(String),
Cancelled,
}
impl From<DefsLookupErrorKind> for InternalRenderingError {
fn from(e: DefsLookupErrorKind) -> InternalRenderingError {
match e {
DefsLookupErrorKind::NotFound => InternalRenderingError::IdNotFound,
_ => InternalRenderingError::InvalidId(format!("{e}")),
}
}
}
impl From<InvalidTransform> for InternalRenderingError {
fn from(_: InvalidTransform) -> InternalRenderingError {
InternalRenderingError::InvalidTransform
}
}
impl fmt::Display for InternalRenderingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
InternalRenderingError::Rendering(ref s) => write!(f, "rendering error: {s}"),
InternalRenderingError::LimitExceeded(ref l) => write!(f, "{l}"),
InternalRenderingError::InvalidTransform => write!(f, "invalid transform"),
InternalRenderingError::CircularReference(ref c) => {
write!(f, "circular reference in element {c}")
}
InternalRenderingError::IdNotFound => write!(f, "element id not found"),
InternalRenderingError::InvalidId(ref s) => write!(f, "invalid id: {s:?}"),
InternalRenderingError::OutOfMemory(ref s) => write!(f, "out of memory: {s}"),
InternalRenderingError::Cancelled => write!(f, "rendering cancelled"),
}
}
}
impl From<cairo::Error> for InternalRenderingError {
fn from(e: cairo::Error) -> InternalRenderingError {
InternalRenderingError::Rendering(format!("{e:?}"))
}
}
macro_rules! box_error {
($from_ty:ty) => {
impl From<$from_ty> for Box<InternalRenderingError> {
fn from(e: $from_ty) -> Box<InternalRenderingError> {
Box::new(e.into())
}
}
};
}
box_error!(DefsLookupErrorKind);
box_error!(InvalidTransform);
box_error!(cairo::Error);
#[derive(Debug, PartialEq)]
pub struct InvalidTransform;
pub enum AcquireError {
LinkNotFound(NodeId),
InvalidLinkType(NodeId),
CircularReference(Node),
MaxReferencesExceeded,
}
impl fmt::Display for AcquireError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
AcquireError::LinkNotFound(ref frag) => write!(f, "link not found: {frag}"),
AcquireError::InvalidLinkType(ref frag) => {
write!(f, "link \"{frag}\" is to object of invalid type")
}
AcquireError::CircularReference(ref node) => {
write!(f, "circular reference in node {node}")
}
AcquireError::MaxReferencesExceeded => {
write!(f, "maximum number of references exceeded")
}
}
}
}
pub trait AttributeResultExt<O> {
fn attribute(self, attr: QualName) -> Result<O, ElementError>;
}
impl<O, E: Into<ValueErrorKind>> AttributeResultExt<O> for Result<O, E> {
fn attribute(self, attr: QualName) -> Result<O, ElementError> {
self.map_err(|e| e.into())
.map_err(|err| ElementError { attr, err })
}
}
fn parse_error_to_element_error<'i>(e: ParseError<'i>, attr: QualName) -> ElementError {
let ParseError {
kind,
location: _location,
} = e;
match kind {
ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(tok)) => {
let mut s = String::from("unexpected token '");
tok.to_css(&mut s).unwrap(); s.push('\'');
ElementError {
attr,
err: ValueErrorKind::Parse(s),
}
}
ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => ElementError {
attr,
err: ValueErrorKind::parse_error("unexpected end of input"),
},
ParseErrorKind::Basic(_) => {
unreachable!("attribute parsers should not return errors for CSS rules")
}
ParseErrorKind::Custom(err) => ElementError { attr, err },
}
}
impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>> {
fn attribute(self, attr: QualName) -> Result<O, ElementError> {
self.map_err(|e| parse_error_to_element_error(e, attr))
}
}
#[derive(Debug, Clone)]
pub enum AllowedUrlError {
UrlParseError(url::ParseError),
BaseRequired,
DifferentUriSchemes,
DisallowedScheme,
NotSiblingOrChildOfBaseFile,
NoQueriesAllowed,
NoFragmentIdentifierAllowed,
NoHostAllowed,
InvalidPathInUrl,
InvalidPathInBaseUrl,
BaseIsRoot,
CanonicalizationError,
}
impl fmt::Display for AllowedUrlError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use AllowedUrlError::*;
match *self {
UrlParseError(e) => write!(f, "URL parse error: {e}"),
BaseRequired => write!(f, "base required"),
DifferentUriSchemes => write!(f, "different URI schemes"),
DisallowedScheme => write!(f, "disallowed scheme"),
NotSiblingOrChildOfBaseFile => write!(f, "not sibling or child of base file"),
NoQueriesAllowed => write!(f, "no queries allowed"),
NoFragmentIdentifierAllowed => write!(f, "no fragment identifier allowed"),
NoHostAllowed => write!(f, "no hostnames allowed"),
InvalidPathInUrl => write!(f, "invalid path in file URL"),
InvalidPathInBaseUrl => write!(f, "invalid path in base URL"),
BaseIsRoot => write!(f, "base is root"),
CanonicalizationError => write!(f, "canonicalization error"),
}
}
}
#[derive(Debug, Clone)]
pub enum NodeIdError {
NodeIdRequired,
}
impl From<NodeIdError> for ValueErrorKind {
fn from(e: NodeIdError) -> ValueErrorKind {
match e {
NodeIdError::NodeIdRequired => {
ValueErrorKind::value_error("fragment identifier required")
}
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum LoadingError {
XmlParseError(String),
OutOfMemory(String),
BadUrl,
BadCss,
NoSvgRoot,
Io(String),
LimitExceeded(ImplementationLimit),
Other(String),
}
#[non_exhaustive]
#[derive(Debug, Copy, Clone)]
pub enum ImplementationLimit {
TooManyReferencedElements,
TooManyLoadedElements,
TooManyAttributes,
MaximumLayerNestingDepthExceeded,
}
impl error::Error for LoadingError {}
impl fmt::Display for LoadingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
LoadingError::XmlParseError(ref s) => write!(f, "XML parse error: {s}"),
LoadingError::OutOfMemory(ref s) => write!(f, "out of memory: {s}"),
LoadingError::BadUrl => write!(f, "invalid URL"),
LoadingError::BadCss => write!(f, "invalid CSS"),
LoadingError::NoSvgRoot => write!(f, "XML does not have <svg> root"),
LoadingError::Io(ref s) => write!(f, "I/O error: {s}"),
LoadingError::LimitExceeded(ref l) => write!(f, "{l}"),
LoadingError::Other(ref s) => write!(f, "{s}"),
}
}
}
impl From<glib::Error> for LoadingError {
fn from(e: glib::Error) -> LoadingError {
LoadingError::Io(format!("{e}"))
}
}
impl From<IoError> for LoadingError {
fn from(e: IoError) -> LoadingError {
match e {
IoError::BadDataUrl => LoadingError::BadUrl,
IoError::Glib(e) => LoadingError::Io(format!("{e}")),
}
}
}
impl fmt::Display for ImplementationLimit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ImplementationLimit::TooManyReferencedElements => write!(
f,
"exceeded more than {} referenced elements",
limits::MAX_REFERENCED_ELEMENTS
),
ImplementationLimit::TooManyLoadedElements => write!(
f,
"cannot load more than {} XML elements",
limits::MAX_LOADED_ELEMENTS
),
ImplementationLimit::TooManyAttributes => write!(
f,
"cannot load more than {} XML attributes",
limits::MAX_LOADED_ATTRIBUTES
),
ImplementationLimit::MaximumLayerNestingDepthExceeded => write!(
f,
"maximum depth of {} nested layers has been exceeded",
limits::MAX_LAYER_NESTING_DEPTH,
),
}
}
}