Skip to main content

pdf_engine/
error.rs

1//! Error types for the rendering engine.
2
3use crate::api_error::PdfError;
4
5/// Errors that can occur in the rendering engine.
6#[derive(Debug, thiserror::Error)]
7pub enum EngineError {
8    /// The PDF data is invalid or could not be parsed.
9    #[error("invalid PDF: {0}")]
10    InvalidPdf(String),
11
12    /// A page index is out of range.
13    #[error("page {index} out of range (document has {count} pages)")]
14    PageOutOfRange {
15        /// The requested page index.
16        index: usize,
17        /// Total number of pages.
18        count: usize,
19    },
20
21    /// A rendering error occurred.
22    #[error("render error: {0}")]
23    RenderError(String),
24
25    /// An I/O error occurred.
26    #[error(transparent)]
27    Io(#[from] std::io::Error),
28
29    /// The PDF is encrypted and requires a password to open.
30    #[error("PDF is encrypted: {0}")]
31    Encrypted(String),
32
33    /// The page has invalid or degenerate dimensions.
34    #[error("invalid page geometry (w={width:.2}pt, h={height:.2}pt): {reason}")]
35    InvalidPageGeometry {
36        /// Page width in points.
37        width: f32,
38        /// Page height in points.
39        height: f32,
40        /// Human-readable reason for the failure.
41        reason: String,
42    },
43
44    /// XFA flattening failed.
45    #[error("XFA flatten failed: {0}")]
46    XfaFlattenFailed(String),
47}
48
49impl PdfError for EngineError {
50    fn code(&self) -> &str {
51        match self {
52            EngineError::InvalidPdf(_) => "INVALID_PDF",
53            EngineError::PageOutOfRange { .. } => "PAGE_OUT_OF_RANGE",
54            EngineError::RenderError(_) => "RENDER_ERROR",
55            EngineError::Io(_) => "IO_ERROR",
56            EngineError::Encrypted(_) => "ENCRYPTED",
57            EngineError::InvalidPageGeometry { .. } => "INVALID_PAGE_GEOMETRY",
58            EngineError::XfaFlattenFailed(_) => "XFA_FLATTEN_FAILED",
59        }
60    }
61
62    fn help(&self) -> Option<String> {
63        match self {
64            EngineError::InvalidPdf(_) => {
65                Some("The PDF file is corrupt or invalid. Try using a PDF repair tool or re-save the document.".to_string())
66            }
67            EngineError::PageOutOfRange { index, count } => {
68                Some(format!("Page {} does not exist. This document has {} pages (0-{}).", index, count, count - 1))
69            }
70            EngineError::RenderError(_) => {
71                Some("Rendering failed. Check that the page exists and the document is not corrupted.".to_string())
72            }
73            EngineError::Io(_) => {
74                Some("An I/O error occurred. Check file permissions and disk space.".to_string())
75            }
76            EngineError::Encrypted(_) => {
77                Some("The PDF is encrypted. Provide the correct password to open it.".to_string())
78            }
79            EngineError::InvalidPageGeometry { .. } => {
80                Some("The page has invalid or degenerate dimensions and cannot be rendered.".to_string())
81            }
82            EngineError::XfaFlattenFailed(_) => {
83                Some("XFA flattening produced an invalid PDF. The document may use unsupported XFA features.".to_string())
84            }
85        }
86    }
87}
88
89/// Convenience type alias.
90pub type Result<T> = std::result::Result<T, EngineError>;
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn encrypted_error_code() {
98        let e = EngineError::Encrypted("bad password".into());
99        assert_eq!(e.code(), "ENCRYPTED");
100    }
101
102    #[test]
103    fn invalid_page_geometry_error_code() {
104        let e = EngineError::InvalidPageGeometry {
105            width: 0.5,
106            height: 0.5,
107            reason: "test".into(),
108        };
109        assert_eq!(e.code(), "INVALID_PAGE_GEOMETRY");
110    }
111
112    #[test]
113    fn xfa_flatten_failed_error_code() {
114        let e = EngineError::XfaFlattenFailed("corrupt output".into());
115        assert_eq!(e.code(), "XFA_FLATTEN_FAILED");
116    }
117}