Skip to main content

_synta/
error.rs

1//! Error handling for Python bindings
2//!
3//! Converts Synta errors to Python exceptions.
4//!
5//! Because both `synta::Error` and `pyo3::PyErr` are defined in foreign crates,
6//! the orphan rule prevents `impl From<synta::Error> for PyErr` directly.
7//! The local newtype `SyntaErr` bridges the gap: callers use `.map_err(SyntaErr)?`
8//! and pyo3's `?` machinery picks up `From<SyntaErr> for PyErr`.
9
10use pyo3::exceptions::{PyEOFError, PyOverflowError, PyRuntimeError, PyValueError};
11use pyo3::{create_exception, PyErr};
12
13// Create a custom exception type visible from Python.
14create_exception!(synta, SyntaError, pyo3::exceptions::PyException);
15
16/// Local newtype wrapper around `synta::Error` that satisfies the orphan rule.
17pub(crate) struct SyntaErr(pub synta::Error);
18
19impl From<synta::Error> for SyntaErr {
20    fn from(e: synta::Error) -> Self {
21        SyntaErr(e)
22    }
23}
24
25impl From<SyntaErr> for PyErr {
26    fn from(SyntaErr(err): SyntaErr) -> PyErr {
27        match err {
28            synta::Error::UnexpectedEof { position } => {
29                PyEOFError::new_err(format!("Unexpected end of input at position {}", position))
30            }
31            synta::Error::InvalidTag { position, byte } => PyValueError::new_err(format!(
32                "Invalid ASN.1 tag at position {}: 0x{:02x}",
33                position, byte
34            )),
35            synta::Error::InvalidLength { position } => {
36                PyValueError::new_err(format!("Invalid length encoding at position {}", position))
37            }
38            synta::Error::LengthOverflow => PyOverflowError::new_err("Length value overflow"),
39            synta::Error::LengthExceedsMaximum {
40                position,
41                length,
42                max_length,
43            } => PyValueError::new_err(format!(
44                "Length {} exceeds maximum {} at position {}",
45                length, max_length, position
46            )),
47            synta::Error::MaxDepthExceeded {
48                position,
49                max_depth,
50            } => PyValueError::new_err(format!(
51                "Maximum nesting depth {} exceeded at position {}",
52                max_depth, position
53            )),
54            synta::Error::UnexpectedTag {
55                position,
56                expected,
57                actual,
58            } => PyValueError::new_err(format!(
59                "Unexpected tag at position {}: expected {:?}, got {:?}",
60                position, expected, actual
61            )),
62            synta::Error::InvalidEncoding {
63                position,
64                tag,
65                reason,
66            } => PyValueError::new_err(format!(
67                "Invalid encoding for {:?} at position {}: {}",
68                tag, position, reason
69            )),
70            synta::Error::IntegerOverflow { position } => {
71                PyOverflowError::new_err(format!("Integer overflow at position {}", position))
72            }
73            synta::Error::InvalidOid { position } => {
74                PyValueError::new_err(format!("Invalid OID encoding at position {}", position))
75            }
76            synta::Error::InvalidString {
77                position,
78                string_type,
79                reason,
80            } => PyValueError::new_err(format!(
81                "Invalid {} at position {}: {}",
82                string_type, position, reason
83            )),
84            synta::Error::InvalidTime { position } => {
85                PyValueError::new_err(format!("Invalid time format at position {}", position))
86            }
87            synta::Error::DerViolation { position, reason } => PyValueError::new_err(format!(
88                "DER violation at position {}: {}",
89                position, reason
90            )),
91            synta::Error::IndefiniteLengthInDer { position } => PyValueError::new_err(format!(
92                "Indefinite length not allowed in DER at position {}",
93                position
94            )),
95            synta::Error::CerViolation { position, reason } => PyValueError::new_err(format!(
96                "CER violation at position {}: {}",
97                position, reason
98            )),
99            synta::Error::UnfinishedConstructed => {
100                PyRuntimeError::new_err("Constructed encoder not properly finished")
101            }
102            synta::Error::NoConstructedToFinish => {
103                PyRuntimeError::new_err("No constructed element to finish")
104            }
105            synta::Error::LengthTooLarge => PyValueError::new_err("Length too large to encode"),
106            synta::Error::Custom(msg) => PyRuntimeError::new_err(msg),
107        }
108    }
109}