use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::sync::Arc;
use crate::configure::{ValidationError, Validators};
#[cfg(feature = "raster-images")]
use crate::graphics::image::Image;
#[cfg(feature = "pdf")]
use crate::pdf::{PdfDocument, PdfError};
use crate::surface::Location;
use crate::tagging::TagId;
use crate::text::Font;
pub type KrillaResult<T> = Result<T, KrillaError>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum KrillaError {
Font(Font, String),
Validation(Vec<(ValidationError, Validators)>),
Limit(LimitError),
DuplicateNamedDestination(Arc<String>),
DuplicateTagId(TagId, Option<Location>),
UnknownTagId(TagId, Option<Location>),
#[cfg(feature = "raster-images")]
Image(Image, Option<Location>, String),
#[cfg(feature = "pdf")]
Pdf(PdfDocument, PdfError, Option<Location>),
#[cfg(feature = "raster-images")]
SixteenBitImage(Image, Option<Location>),
}
impl Display for KrillaError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
KrillaError::Font(_, message) => write!(f, "failed to embed font: {message}"),
KrillaError::Validation(errors) => {
let count = errors.len();
write!(
f,
"validation failed with {count} {}",
if count == 1 { "error" } else { "errors" }
)
}
KrillaError::Limit(error) => write!(f, "PDF version limit exceeded: {error}"),
KrillaError::DuplicateNamedDestination(name) => {
write!(f, "duplicate named destination: {name}")
}
KrillaError::DuplicateTagId(id, location) => {
write!(f, "duplicate tag id {id:?}")?;
write_location(f, *location)
}
KrillaError::UnknownTagId(id, location) => {
write!(f, "unknown tag id {id:?}")?;
write_location(f, *location)
}
#[cfg(feature = "raster-images")]
KrillaError::Image(_, location, message) => {
write!(f, "failed to process image")?;
write_location(f, *location)?;
write!(f, ": {message}")
}
#[cfg(feature = "pdf")]
KrillaError::Pdf(_, error, location) => {
write!(f, "failed to process embedded PDF")?;
write_location(f, *location)?;
write!(f, ": {error}")
}
#[cfg(feature = "raster-images")]
KrillaError::SixteenBitImage(_, location) => {
write!(
f,
"sixteen bit images require PDF 1.5 or newer, but the selected PDF version does not support them"
)?;
write_location(f, *location)
}
}
}
}
impl Error for KrillaError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
KrillaError::Limit(error) => Some(error),
#[cfg(feature = "pdf")]
KrillaError::Pdf(_, error, _) => Some(error),
_ => None,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum LimitError {
TooLargeFloat,
TooLongArray,
TooLongDictionary,
}
impl Display for LimitError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
LimitError::TooLargeFloat => write!(f, "a float exceeded the maximum allowed size"),
LimitError::TooLongArray => write!(f, "an array exceeded the maximum allowed length"),
LimitError::TooLongDictionary => {
write!(
f,
"a dictionary exceeded the maximum allowed number of entries"
)
}
}
}
}
impl Error for LimitError {}
fn write_location(f: &mut Formatter<'_>, location: Option<Location>) -> fmt::Result {
if let Some(location) = location {
write!(f, " at location {location}")
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::error::Error as _;
use super::{KrillaError, LimitError};
#[test]
fn krilla_error_implements_error() {
let error = KrillaError::Limit(LimitError::TooLongArray);
assert_eq!(
error.to_string(),
"PDF version limit exceeded: an array exceeded the maximum allowed length"
);
assert!(error.source().is_some());
}
}