mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-15 23:12:15 +00:00
174 lines
6.1 KiB
Rust
174 lines
6.1 KiB
Rust
//! Error handling.
|
|
//!
|
|
//! There are a lot of things that can go wrong when writing a PDF, like for example when
|
|
//! invalid fonts are provided. This module provides the basic error types krilla uses.
|
|
|
|
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;
|
|
|
|
/// A wrapper type for krilla errors.
|
|
pub type KrillaResult<T> = Result<T, KrillaError>;
|
|
|
|
/// An error in krilla.
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
pub enum KrillaError {
|
|
/// A page or surface failed during cleanup; discard the complete document.
|
|
Poisoned,
|
|
/// An error while attempting to embed a font.
|
|
Font(Font, String),
|
|
/// A list of validation errors. Can only occur if you set the `validator` in
|
|
/// the [`SerializeSettings`] to something else than the dummy validator.
|
|
///
|
|
/// [`SerializeSettings`]: crate::SerializeSettings
|
|
Validation(Vec<(ValidationError, Validators)>),
|
|
/// A hard limit of the selected PDF version was exceeded.
|
|
Limit(LimitError),
|
|
/// The same destination name has been associated with two different destinations,
|
|
/// which is prohibited.
|
|
DuplicateNamedDestination(Arc<String>),
|
|
/// A duplicate [`Tag::id`] was provided.
|
|
///
|
|
/// [`Tag::id`]: crate::interchange::tagging::Tag::id
|
|
DuplicateTagId(TagId, Option<Location>),
|
|
/// A [`TagId`] was not found in the [`TagTree`].
|
|
///
|
|
/// [`TagTree`]: crate::interchange::tagging::TagTree
|
|
UnknownTagId(TagId, Option<Location>),
|
|
/// An image couldn't be processed properly.
|
|
///
|
|
/// The third argument contains the error message.
|
|
#[cfg(feature = "raster-images")]
|
|
Image(Image, Option<Location>, String),
|
|
/// An embedded PDF document couldn't be processed properly.
|
|
#[cfg(feature = "pdf")]
|
|
Pdf(PdfDocument, PdfError, Option<Location>),
|
|
/// A sixteen bit image was used, even though it isn't
|
|
/// supported by the used PDF version (only available in PDF 1.5+).
|
|
#[cfg(feature = "raster-images")]
|
|
SixteenBitImage(Image, Option<Location>),
|
|
}
|
|
|
|
impl Display for KrillaError {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
KrillaError::Poisoned => f.write_str("document contains a failed page or surface"),
|
|
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,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A limit imposed by the selected PDF version.
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
pub enum LimitError {
|
|
/// A float exceeded the maximum allowed size for the PDF version.
|
|
TooLargeFloat,
|
|
/// An array exceeded the maximum allowed length for the PDF version.
|
|
TooLongArray,
|
|
/// A dictionary exceeded the maximum allowed number of entries for the PDF version.
|
|
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());
|
|
}
|
|
}
|