structured_pades/error.rs
1//! Located syntax, ambiguity, unsupported capability and processing refusals.
2
3use crate::source::Location;
4use core::fmt;
5use structured_asn1::memory::MemoryError;
6
7/// A concrete PDF grammar or document-structure violation.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Syntax {
10 /// Missing or malformed file header.
11 Header,
12 /// Unexpected token for the selected grammar.
13 Token,
14 /// Value or delimiter extends beyond its original source.
15 End,
16 /// Invalid integer or real spelling.
17 Number,
18 /// Invalid name escape or forbidden zero byte.
19 Name,
20 /// Invalid literal or hexadecimal string.
21 String,
22 /// Invalid dictionary entry or conflicting duplicate key.
23 Dictionary,
24 /// Invalid stream extent, encoding or decoding parameters.
25 Stream,
26 /// Invalid indirect object definition or reference identity.
27 Object,
28 /// Invalid cross-reference section or object location.
29 CrossReference,
30 /// Invalid terminal startxref record.
31 StartXref,
32 /// Invalid document trailer.
33 Trailer,
34 /// The carried signature container has the wrong format or extent.
35 Container,
36 /// Reference or cross-reference chain returns to itself.
37 Cycle,
38}
39
40/// Caller-selected mechanism limit, separate from malformed syntax.
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum Limit {
43 /// Container or resolution nesting limit.
44 Depth,
45 /// Cumulative original and decoded object count.
46 Objects,
47 /// Cumulative revision count.
48 Revisions,
49 /// Cumulative decoded output allowance.
50 Decoded,
51}
52
53/// An explicitly unavailable processing capability.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum Unsupported {
56 /// Requested stream filter has no selected structural decoder.
57 Filter,
58 /// External stream bytes were not supplied by a caller.
59 ExternalStream,
60 /// Required encrypted source bytes are unavailable.
61 Encryption,
62 /// A number cannot be represented for this particular query.
63 NumericRange,
64}
65
66/// Independent failure classes; processing causes cannot become syntax faults.
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum ErrorKind {
69 /// Unreadable syntax with its actual domain and range.
70 Syntax(Syntax),
71 /// Two incompatible readings; selecting the first would lose meaning.
72 Ambiguous(Syntax),
73 /// Caller-selected resource count exhausted before the operation.
74 Limit(Limit),
75 /// Actual shared allocator, capacity, or current/source work refusal.
76 Resource(MemoryError),
77 /// Required capability is explicitly unavailable.
78 Unsupported(Unsupported),
79 /// A caller mixed source/session/document identities.
80 Foreign,
81}
82
83/// Failure preserving both logical coordinates and honest physical enclosure.
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub struct Error {
86 /// Original failure classification and cause.
87 pub kind: ErrorKind,
88 /// Original range, with its source discriminator.
89 pub location: Location,
90}
91impl Error {
92 /// Processing and source misuse cannot become a recoverable syntax slot.
93 #[must_use]
94 pub fn is_terminal(&self) -> bool {
95 matches!(
96 self.kind,
97 ErrorKind::Limit(_) | ErrorKind::Resource(_) | ErrorKind::Foreign
98 )
99 }
100}
101
102impl fmt::Display for Error {
103 fn fmt(&self, output: &mut fmt::Formatter<'_>) -> fmt::Result {
104 write!(output, "{:?} at {:?}", self.kind, self.location)
105 }
106}
107
108#[cfg(feature = "std")]
109impl std::error::Error for Error {}
110
111/// Recoverable original format fault, never an allocator/work/processing cause.
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113pub struct Fault {
114 /// Specific readable format violation.
115 pub code: Syntax,
116 /// Original source location.
117 pub location: Location,
118}
119
120/// Result of a PDF mechanism operation.
121pub type Result<T> = core::result::Result<T, Error>;
122
123/// A format operation may fail independently in PDF processing or in the
124/// caller's asynchronous source. Opaque causes are never syntax diagnostics.
125#[derive(Debug)]
126pub enum ReadFailure<E> {
127 /// Original located PDF syntax, ambiguity, resource or capability cause.
128 Format(Error),
129 /// Original source snapshot/acquisition/resource cause and range.
130 Input(crate::range::InputError<E>),
131}
132impl<E> ReadFailure<E> {
133 /// Opaque acquisition, resource and source-identity refusals are terminal.
134 #[must_use]
135 pub fn is_terminal(&self) -> bool {
136 match self {
137 Self::Format(cause) => cause.is_terminal(),
138 Self::Input(_) => true,
139 }
140 }
141}
142
143impl<E> From<Error> for ReadFailure<E> {
144 fn from(error: Error) -> Self {
145 Self::Format(error)
146 }
147}
148
149impl<E> From<crate::range::InputError<E>> for ReadFailure<E> {
150 fn from(error: crate::range::InputError<E>) -> Self {
151 Self::Input(error)
152 }
153}