#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("wrong password")]
WrongPassword,
#[error("cannot open document: {0}")]
Open(#[source] pdfrum_parser::LoadError),
#[error("cannot read document: {0}")]
Read(#[source] pdfrum_parser::Error),
#[error("cannot render page: {0}")]
Render(#[source] pdfrum_render::Error),
#[error("cannot read document feature: {0}")]
Doc(#[from] pdfrum_doc::Error),
#[error("cannot save document: {0}")]
#[cfg(feature = "edit")]
Save(#[from] pdfrum_edit::Error),
#[error("cannot extract text: {0}")]
Text(#[from] pdfrum_text::Error),
#[error(transparent)]
Limit(#[from] pdfrum_common::LimitExceeded),
#[error("cannot read svg: {0}")]
#[cfg(feature = "svg-import")]
Svg(#[source] crate::SvgError),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum ErrorCode {
Io = 1,
Open = 2,
WrongPassword = 3,
Read = 4,
Render = 5,
Doc = 6,
Save = 7,
Text = 8,
Limit = 9,
Svg = 10,
}
impl From<ErrorCode> for u32 {
fn from(code: ErrorCode) -> u32 {
code as u32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[error("no error code numbered {0}")]
pub struct UnknownErrorCode(pub u32);
impl ErrorCode {
#[must_use]
pub fn name(self) -> &'static str {
match self {
ErrorCode::Io => "io",
ErrorCode::Open => "open",
ErrorCode::WrongPassword => "wrong-password",
ErrorCode::Read => "read",
ErrorCode::Render => "render",
ErrorCode::Doc => "doc",
ErrorCode::Save => "save",
ErrorCode::Text => "text",
ErrorCode::Limit => "limit",
ErrorCode::Svg => "svg",
}
}
}
impl std::fmt::Display for ErrorCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name())
}
}
impl TryFrom<u32> for ErrorCode {
type Error = UnknownErrorCode;
fn try_from(n: u32) -> core::result::Result<ErrorCode, UnknownErrorCode> {
match n {
1 => Ok(ErrorCode::Io),
2 => Ok(ErrorCode::Open),
3 => Ok(ErrorCode::WrongPassword),
4 => Ok(ErrorCode::Read),
5 => Ok(ErrorCode::Render),
6 => Ok(ErrorCode::Doc),
7 => Ok(ErrorCode::Save),
8 => Ok(ErrorCode::Text),
9 => Ok(ErrorCode::Limit),
10 => Ok(ErrorCode::Svg),
other => Err(UnknownErrorCode(other)),
}
}
}
impl Error {
#[must_use]
pub fn code(&self) -> ErrorCode {
match self {
Error::WrongPassword => ErrorCode::WrongPassword,
Error::Open(_) => ErrorCode::Open,
Error::Read(_) => ErrorCode::Read,
Error::Render(_) => ErrorCode::Render,
Error::Doc(_) => ErrorCode::Doc,
#[cfg(feature = "edit")]
Error::Save(_) => ErrorCode::Save,
Error::Text(_) => ErrorCode::Text,
Error::Limit(_) => ErrorCode::Limit,
#[cfg(feature = "svg-import")]
Error::Svg(_) => ErrorCode::Svg,
Error::Io(_) => ErrorCode::Io,
}
}
}
impl From<pdfrum_parser::LoadError> for Error {
fn from(e: pdfrum_parser::LoadError) -> Self {
match e {
pdfrum_parser::LoadError::WrongPassword => Error::WrongPassword,
pdfrum_parser::LoadError::Limit(limit) => Error::Limit(limit),
other => Error::Open(other),
}
}
}
impl From<pdfrum_parser::Error> for Error {
fn from(e: pdfrum_parser::Error) -> Self {
match e {
pdfrum_parser::Error::Limit(limit) => Error::Limit(limit),
other => Error::Read(other),
}
}
}
impl From<pdfrum_render::Error> for Error {
fn from(e: pdfrum_render::Error) -> Self {
match e {
pdfrum_render::Error::Limit(limit) => Error::Limit(limit),
other => Error::Render(other),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_error_has_the_code_the_table_says() {
let table: Vec<(Error, ErrorCode, u32)> = vec![
(Error::Io(std::io::Error::other("io")), ErrorCode::Io, 1),
(
Error::Open(pdfrum_parser::LoadError::NotPdf),
ErrorCode::Open,
2,
),
(Error::WrongPassword, ErrorCode::WrongPassword, 3),
(
Error::Read(pdfrum_parser::Error::Unresolved(
pdfrum_object::ObjRef::new(1, 0),
)),
ErrorCode::Read,
4,
),
(
Error::Render(pdfrum_render::Error::TargetEmpty {
width: 0,
height: 0,
}),
ErrorCode::Render,
5,
),
(Error::Doc(pdfrum_doc::Error::NoCatalog), ErrorCode::Doc, 6),
#[cfg(feature = "edit")]
(
Error::Save(pdfrum_edit::Error::BadPageRange),
ErrorCode::Save,
7,
),
(
Error::Text(pdfrum_text::Error::CharIndexOutOfRange {
index: pdfrum_text::CharIndex::from(3),
len: 1,
}),
ErrorCode::Text,
8,
),
(
Error::Limit(pdfrum_common::LimitExceeded::Stopped {
during: pdfrum_common::Operation::PageLoad,
page: None,
}),
ErrorCode::Limit,
9,
),
];
for (error, code, number) in table {
assert_eq!(error.code(), code, "{error}");
assert_eq!(u32::from(code), number, "{error}");
}
assert_eq!(u32::from(ErrorCode::Save), 7);
assert_eq!(u32::from(ErrorCode::Svg), 10);
}
}