1use std::fmt;
4
5use crate::limits::LimitKind;
6use crate::object::ObjId;
7use crate::source::SourceError;
8
9#[derive(Debug, Clone, PartialEq)]
11pub enum Error {
12 Source(SourceError),
14 Syntax {
17 offset: u64,
19 message: &'static str,
21 },
22 UnexpectedEof,
24 Limit(LimitKind),
26 NoXref,
28 NoRoot,
30 MissingObject(ObjId),
32 WrongType {
34 expected: &'static str,
36 found: &'static str,
38 },
39 Filter(&'static str),
41 UnsupportedEncryption(String),
43 InvalidPassword,
45}
46
47impl Error {
48 pub fn syntax(offset: u64, message: &'static str) -> Self {
50 Self::Syntax { offset, message }
51 }
52}
53
54impl fmt::Display for Error {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 match self {
57 Self::Source(e) => e.fmt(f),
58 Self::Syntax { offset, message } => {
59 write!(f, "syntax error at byte {offset}: {message}")
60 }
61 Self::UnexpectedEof => f.write_str("unexpected end of input"),
62 Self::Limit(kind) => write!(f, "{kind} limit exceeded"),
63 Self::NoXref => f.write_str("no cross-reference data or objects found"),
64 Self::NoRoot => f.write_str("trailer has no document catalog (/Root)"),
65 Self::MissingObject(id) => write!(f, "object {} {} not found", id.num, id.generation),
66 Self::WrongType { expected, found } => {
67 write!(f, "expected {expected}, found {found}")
68 }
69 Self::Filter(msg) => write!(f, "stream decoding failed: {msg}"),
70 Self::UnsupportedEncryption(msg) => write!(f, "unsupported encryption: {msg}"),
71 Self::InvalidPassword => f.write_str("incorrect password"),
72 }
73 }
74}
75
76impl std::error::Error for Error {
77 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
78 match self {
79 Self::Source(e) => Some(e),
80 _ => None,
81 }
82 }
83}
84
85impl From<SourceError> for Error {
86 fn from(e: SourceError) -> Self {
87 Self::Source(e)
88 }
89}
90
91pub type Result<T> = std::result::Result<T, Error>;
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn display() {
100 assert_eq!(
101 Error::syntax(5, "expected dictionary").to_string(),
102 "syntax error at byte 5: expected dictionary"
103 );
104 assert_eq!(
105 Error::Limit(LimitKind::Depth).to_string(),
106 "nesting depth limit exceeded"
107 );
108 assert_eq!(
109 Error::MissingObject(ObjId::new(3, 0)).to_string(),
110 "object 3 0 not found"
111 );
112 assert!(std::error::Error::source(&Error::Source(SourceError::new("x"))).is_some());
113 assert!(std::error::Error::source(&Error::NoRoot).is_none());
114 }
115}