Skip to main content

printwell_pdf/
error.rs

1//! Error types for printwell.
2
3use thiserror::Error;
4
5/// PDF manipulation error type.
6#[derive(Debug, Error)]
7pub enum Error {
8    /// Form manipulation error.
9    #[error("Form error: {0}")]
10    Form(#[from] FormError),
11    /// Digital signing error.
12    #[error("Signing error: {0}")]
13    Signing(#[from] SigningError),
14    /// Encryption error.
15    #[error("Encryption error: {0}")]
16    Encryption(#[from] EncryptionError),
17    /// Watermark error.
18    #[error("Watermark error: {0}")]
19    Watermark(#[from] WatermarkError),
20    /// Bookmark error.
21    #[error("Bookmark error: {0}")]
22    Bookmark(#[from] BookmarkError),
23    /// Annotation error.
24    #[error("Annotation error: {0}")]
25    Annotation(#[from] AnnotationError),
26    /// PDF/A compliance error.
27    #[error("PDF/A error: {0}")]
28    PdfA(#[from] PdfAError),
29    /// PDF/UA accessibility error.
30    #[error("PDF/UA error: {0}")]
31    PdfUA(#[from] PdfUAError),
32    /// Invalid PDF structure.
33    #[error("Invalid PDF: {0}")]
34    InvalidPdf(String),
35    /// Invalid parameter.
36    #[error("Invalid parameter: {0}")]
37    InvalidParameter(String),
38    /// PDF operation error.
39    #[error("PDF operation error: {0}")]
40    PdfOperation(String),
41    /// I/O error.
42    #[error("IO error: {0}")]
43    Io(#[from] std::io::Error),
44    /// FFI error.
45    #[error("FFI error: {0}")]
46    Ffi(#[from] cxx::Exception),
47}
48
49/// Form-related errors.
50#[derive(Debug, Error)]
51pub enum FormError {
52    /// Feature requires a commercial license.
53    #[error(
54        "PDF form manipulation requires a commercial license. Purchase at: https://printwell.dev/pricing"
55    )]
56    RequiresLicense,
57    /// Failed to initialize form builder.
58    #[error("failed to initialize form builder: {0}")]
59    InitFailed(String),
60    /// Failed to add a form field.
61    #[error("failed to add {field_type} field '{name}': {reason}")]
62    AddFieldFailed {
63        /// The type of form field (e.g., "text", "checkbox", "dropdown").
64        field_type: &'static str,
65        /// The name of the field that failed to be added.
66        name: String,
67        /// The reason the field could not be added.
68        reason: String,
69    },
70    /// Failed to build form.
71    #[error("failed to build form: {0}")]
72    BuildFailed(String),
73    /// Field validation failed.
74    #[error("validation failed for field '{field}': {reason}")]
75    ValidationFailed {
76        /// The name of the field that failed validation.
77        field: String,
78        /// The reason validation failed.
79        reason: String,
80    },
81    /// Invalid field specification.
82    #[error("invalid field specification: {0}")]
83    InvalidSpec(String),
84    /// PDF operation failed.
85    #[error("{0}")]
86    Operation(String),
87}
88
89/// Signing-related errors.
90#[derive(Debug, Error)]
91pub enum SigningError {
92    /// Feature requires a commercial license.
93    #[error(
94        "Digital signing requires a commercial license. Purchase at: https://printwell.dev/pricing"
95    )]
96    RequiresLicense,
97    /// Failed to load certificate.
98    #[error("failed to load certificate: {0}")]
99    CertificateLoadFailed(String),
100    /// Invalid certificate format.
101    #[error("invalid certificate format: {0}")]
102    InvalidCertificate(String),
103    /// Failed to prepare PDF for signing.
104    #[error("failed to prepare PDF for signing: {0}")]
105    PrepareFailed(String),
106    /// Failed to create signature.
107    #[error("failed to create signature: {0}")]
108    SignatureFailed(String),
109    /// Failed to embed signature.
110    #[error("failed to embed signature in PDF: {0}")]
111    EmbedFailed(String),
112    /// No signer information found.
113    #[error("no signer information found in signature")]
114    NoSignerInfo,
115    /// Signature verification failed.
116    #[error("signature verification failed: {0}")]
117    VerificationFailed(String),
118    /// Timestamp operation failed.
119    #[error("timestamp operation failed: {0}")]
120    TimestampFailed(String),
121    /// CMS/PKCS#7 parsing or encoding failed.
122    #[error("CMS operation failed: {0}")]
123    CmsFailed(String),
124    /// Failed to extract signatures.
125    #[error("failed to extract signatures: {0}")]
126    ExtractionFailed(String),
127    /// Generic signing operation error.
128    #[error("{0}")]
129    Operation(String),
130}
131
132/// Encryption-related errors.
133#[derive(Debug, Error)]
134pub enum EncryptionError {
135    /// Feature requires a commercial license.
136    #[error(
137        "PDF encryption requires a commercial license. Purchase at: https://printwell.dev/pricing"
138    )]
139    RequiresLicense,
140    /// Invalid password.
141    #[error("invalid password")]
142    InvalidPassword,
143    /// Password too short.
144    #[error("password too short (minimum {min} characters)")]
145    PasswordTooShort {
146        /// The minimum required password length.
147        min: usize,
148    },
149    /// Unsupported encryption algorithm.
150    #[error("unsupported encryption algorithm: {0}")]
151    UnsupportedAlgorithm(String),
152    /// Failed to encrypt PDF.
153    #[error("failed to encrypt PDF: {0}")]
154    EncryptFailed(String),
155    /// Failed to decrypt PDF.
156    #[error("failed to decrypt PDF: {0}")]
157    DecryptFailed(String),
158    /// PDF is already encrypted.
159    #[error("PDF is already encrypted")]
160    AlreadyEncrypted,
161    /// PDF is not encrypted.
162    #[error("PDF is not encrypted")]
163    NotEncrypted,
164    /// Generic encryption operation error.
165    #[error("{0}")]
166    Operation(String),
167}
168
169/// Watermark-related errors.
170#[derive(Debug, Error)]
171pub enum WatermarkError {
172    /// No content specified.
173    #[error("either text or image must be specified for watermark")]
174    NoContent,
175    /// Both text and image specified.
176    #[error("cannot specify both text and image for watermark")]
177    BothContentTypes,
178    /// Invalid image data.
179    #[error("invalid image data: {0}")]
180    InvalidImage(String),
181    /// Invalid opacity value.
182    #[error("invalid opacity value {value}: must be between 0.0 and 1.0")]
183    InvalidOpacity {
184        /// The invalid opacity value that was provided.
185        value: f32,
186    },
187    /// Invalid position.
188    #[error("invalid position: {0}")]
189    InvalidPosition(String),
190    /// Failed to add watermark.
191    #[error("failed to add watermark: {0}")]
192    AddFailed(String),
193    /// Generic watermark operation error.
194    #[error("{0}")]
195    Operation(String),
196}
197
198/// Bookmark-related errors.
199#[derive(Debug, Error)]
200pub enum BookmarkError {
201    /// Invalid bookmark specification.
202    #[error("invalid bookmark specification: {0}")]
203    InvalidSpec(String),
204    /// Invalid page number.
205    #[error("invalid page number {page}: document has {total} pages")]
206    InvalidPage {
207        /// The invalid page number that was requested.
208        page: u32,
209        /// The total number of pages in the document.
210        total: u32,
211    },
212    /// Failed to add bookmarks.
213    #[error("failed to add bookmarks: {0}")]
214    AddFailed(String),
215    /// Failed to extract bookmarks.
216    #[error("failed to extract bookmarks: {0}")]
217    ExtractFailed(String),
218    /// Generic bookmark operation error.
219    #[error("{0}")]
220    Operation(String),
221}
222
223/// Annotation-related errors.
224#[derive(Debug, Error)]
225pub enum AnnotationError {
226    /// Invalid annotation type.
227    #[error("invalid annotation type: {0}")]
228    InvalidType(String),
229    /// Invalid rectangle bounds.
230    #[error("invalid rectangle bounds: {reason}")]
231    InvalidRect {
232        /// The reason the rectangle bounds are invalid.
233        reason: String,
234    },
235    /// Invalid color specification.
236    #[error("invalid color: {0}")]
237    InvalidColor(String),
238    /// Failed to add annotations.
239    #[error("failed to add annotations: {0}")]
240    AddFailed(String),
241    /// Failed to list annotations.
242    #[error("failed to list annotations: {0}")]
243    ListFailed(String),
244    /// Failed to remove annotations.
245    #[error("failed to remove annotations: {0}")]
246    RemoveFailed(String),
247    /// Generic annotation operation error.
248    #[error("{0}")]
249    Operation(String),
250}
251
252/// PDF/A compliance errors.
253#[derive(Debug, Error)]
254pub enum PdfAError {
255    /// Feature requires a commercial license.
256    #[error(
257        "PDF/A compliance features require a commercial license. Purchase at: https://printwell.dev/pricing"
258    )]
259    RequiresLicense,
260    /// Invalid PDF/A level.
261    #[error("invalid PDF/A level: {0}")]
262    InvalidLevel(String),
263    /// Validation failed.
264    #[error("PDF/A validation failed: {error_count} errors, {warning_count} warnings")]
265    ValidationFailed {
266        /// The number of validation errors found.
267        error_count: usize,
268        /// The number of validation warnings found.
269        warning_count: usize,
270    },
271    /// Failed to add metadata.
272    #[error("failed to add PDF/A metadata: {0}")]
273    MetadataFailed(String),
274    /// Document has compliance issues.
275    #[error("document has {count} compliance issues")]
276    ComplianceIssues {
277        /// The number of compliance issues found.
278        count: usize,
279    },
280    /// Generic PDF/A operation error.
281    #[error("{0}")]
282    Operation(String),
283}
284
285/// PDF/UA accessibility errors.
286#[derive(Debug, Error)]
287pub enum PdfUAError {
288    /// Feature requires a commercial license.
289    #[error(
290        "PDF/UA accessibility features require a commercial license. Purchase at: https://printwell.dev/pricing"
291    )]
292    RequiresLicense,
293    /// Invalid PDF/UA level.
294    #[error("invalid PDF/UA level: {0}")]
295    InvalidLevel(String),
296    /// Document missing required structure.
297    #[error("document missing required structure: {0}")]
298    MissingStructure(String),
299    /// Accessibility issue detected.
300    #[error("accessibility issue: {category} - {description}")]
301    AccessibilityIssue {
302        /// The category of the accessibility issue (e.g., "structure", "alt-text").
303        category: String,
304        /// A description of the accessibility issue.
305        description: String,
306    },
307    /// Failed to add metadata.
308    #[error("failed to add PDF/UA metadata: {0}")]
309    MetadataFailed(String),
310    /// Generic PDF/UA operation error.
311    #[error("{0}")]
312    Operation(String),
313}
314
315// Backward compatibility: Allow creating errors from strings for migration
316impl From<String> for FormError {
317    fn from(s: String) -> Self {
318        Self::Operation(s)
319    }
320}
321
322impl From<String> for SigningError {
323    fn from(s: String) -> Self {
324        Self::Operation(s)
325    }
326}
327
328impl From<String> for EncryptionError {
329    fn from(s: String) -> Self {
330        Self::Operation(s)
331    }
332}
333
334impl From<String> for WatermarkError {
335    fn from(s: String) -> Self {
336        Self::Operation(s)
337    }
338}
339
340impl From<String> for BookmarkError {
341    fn from(s: String) -> Self {
342        Self::Operation(s)
343    }
344}
345
346impl From<String> for AnnotationError {
347    fn from(s: String) -> Self {
348        Self::Operation(s)
349    }
350}
351
352impl From<String> for PdfAError {
353    fn from(s: String) -> Self {
354        Self::Operation(s)
355    }
356}
357
358impl From<String> for PdfUAError {
359    fn from(s: String) -> Self {
360        Self::Operation(s)
361    }
362}
363
364/// Result type alias.
365pub type Result<T> = std::result::Result<T, Error>;