Skip to main content

edgefirst_tensor/
error.rs

1// SPDX-FileCopyrightText: Copyright 2025 Au-Zone Technologies
2// SPDX-License-Identifier: Apache-2.0
3
4pub type Result<T, E = Error> = std::result::Result<T, E>;
5
6#[derive(Debug)]
7pub enum Error {
8    IoError(std::io::Error),
9    #[cfg(unix)]
10    NixError(nix::Error),
11    NotImplemented(String),
12    InvalidSize(usize),
13    ShapeMismatch(String),
14    #[cfg(target_os = "linux")]
15    UnknownDeviceType(u64, u64),
16    InvalidMemoryType(String),
17    /// The GL context backing a PBO tensor has been destroyed.
18    PboDisconnected,
19    /// The PBO buffer is currently mapped and cannot be used for GL operations.
20    PboMapped,
21    #[cfg(feature = "ndarray")]
22    NdArrayError(ndarray::ShapeError),
23    InvalidShape(String),
24    InvalidArgument(String),
25    InvalidOperation(String),
26    /// Structured quantization-invariant failure. Round-trippable through
27    /// the C and Python boundaries so callers can diagnose which field
28    /// failed without parsing strings.
29    QuantizationInvalid {
30        /// Which invariant failed: `"scale.len"`, `"zero_point.len"`,
31        /// `"axis"`, `"per_channel_requires_axis"`,
32        /// `"per_tensor_redundant_axis"`, `"dtype_is_integer"`.
33        field: &'static str,
34        /// What the validator expected, e.g. `"length matches scale (48)"`.
35        expected: String,
36        /// What was observed, e.g. `"length 32"`.
37        got: String,
38    },
39}
40
41impl From<std::io::Error> for Error {
42    fn from(err: std::io::Error) -> Self {
43        Error::IoError(err)
44    }
45}
46#[cfg(unix)]
47impl From<nix::Error> for Error {
48    fn from(err: nix::Error) -> Self {
49        Error::NixError(err)
50    }
51}
52
53#[cfg(feature = "ndarray")]
54impl From<ndarray::ShapeError> for Error {
55    fn from(err: ndarray::ShapeError) -> Self {
56        Error::NdArrayError(err)
57    }
58}
59
60impl std::fmt::Display for Error {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(f, "{self:?}")
63    }
64}
65
66impl std::error::Error for Error {}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn test_error_display() {
74        let e = Error::InvalidSize(0);
75        let msg = e.to_string();
76        assert!(!msg.is_empty());
77        assert!(
78            msg.contains("InvalidSize"),
79            "unexpected InvalidSize message: {msg}"
80        );
81
82        let e = Error::NotImplemented("foo".to_string());
83        let msg = e.to_string();
84        assert!(!msg.is_empty());
85        assert!(
86            msg.contains("NotImplemented") && msg.contains("foo"),
87            "unexpected NotImplemented message: {msg}"
88        );
89
90        let e = Error::ShapeMismatch("expected 3, got 4".to_string());
91        let msg = e.to_string();
92        assert!(!msg.is_empty());
93        assert!(
94            msg.contains("ShapeMismatch") && msg.contains("expected 3"),
95            "unexpected ShapeMismatch message: {msg}"
96        );
97
98        let e = Error::InvalidMemoryType("dma".to_string());
99        let msg = e.to_string();
100        assert!(!msg.is_empty());
101        assert!(
102            msg.contains("InvalidMemoryType") && msg.contains("dma"),
103            "unexpected InvalidMemoryType message: {msg}"
104        );
105
106        let e = Error::PboDisconnected;
107        let msg = e.to_string();
108        assert!(!msg.is_empty());
109        assert!(
110            msg.contains("PboDisconnected"),
111            "unexpected PboDisconnected message: {msg}"
112        );
113
114        let e = Error::PboMapped;
115        let msg = e.to_string();
116        assert!(!msg.is_empty());
117        assert!(
118            msg.contains("PboMapped"),
119            "unexpected PboMapped message: {msg}"
120        );
121
122        let e = Error::InvalidShape("bad shape".to_string());
123        let msg = e.to_string();
124        assert!(!msg.is_empty());
125        assert!(
126            msg.contains("InvalidShape") && msg.contains("bad shape"),
127            "unexpected InvalidShape message: {msg}"
128        );
129
130        let e = Error::InvalidArgument("negative".to_string());
131        let msg = e.to_string();
132        assert!(!msg.is_empty());
133        assert!(
134            msg.contains("InvalidArgument") && msg.contains("negative"),
135            "unexpected InvalidArgument message: {msg}"
136        );
137
138        let e = Error::InvalidOperation("read-only".to_string());
139        let msg = e.to_string();
140        assert!(!msg.is_empty());
141        assert!(
142            msg.contains("InvalidOperation") && msg.contains("read-only"),
143            "unexpected InvalidOperation message: {msg}"
144        );
145
146        let e = Error::IoError(std::io::Error::new(
147            std::io::ErrorKind::NotFound,
148            "file missing",
149        ));
150        let msg = e.to_string();
151        assert!(!msg.is_empty());
152        assert!(
153            msg.contains("IoError") && msg.contains("file missing"),
154            "unexpected IoError message: {msg}"
155        );
156    }
157}