Skip to main content

cr1140_sdk/
error.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Unified SDK error type. Mirrors `cr1140_hal::HalError`'s thiserror pattern so
3//! callers — including ROS 2 / Apex nodes — can match on the cause. Metrics
4//! parsers/readers stay `Option`; fallible hardware and config operations return
5//! [`SdkResult`].
6
7/// Errors from fallible SDK operations (hardware restore, config IO).
8#[derive(Debug, thiserror::Error)]
9pub enum SdkError {
10    /// An underlying HAL operation failed (sysfs read/write, parse).
11    #[error("hal: {0}")]
12    Hal(#[from] cr1140_hal::HalError),
13    /// Filesystem IO failed.
14    #[error("io: {0}")]
15    Io(#[from] std::io::Error),
16    /// A config file could not be decoded from TOML.
17    #[cfg(feature = "config")]
18    #[error("config decode: {0}")]
19    Decode(#[from] toml::de::Error),
20    /// A config value could not be encoded to TOML.
21    #[cfg(feature = "config")]
22    #[error("config encode: {0}")]
23    Encode(#[from] toml::ser::Error),
24    /// A retain-store framing/integrity error (bad magic, CRC mismatch, payload
25    /// too large, or `postcard` (de)serialization failure).
26    #[cfg(feature = "retain")]
27    #[error("retain: {0}")]
28    Retain(String),
29    /// A network-apply error: `nmcli` missing, a non-zero exit (with captured
30    /// stderr), or an invalid [`crate::net::NetworkConfig`].
31    #[cfg(feature = "net")]
32    #[error("net: {0}")]
33    Net(String),
34}
35
36/// Result alias for SDK operations.
37pub type SdkResult<T> = Result<T, SdkError>;
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn from_io_error_displays_with_prefix() {
45        let io = std::io::Error::new(std::io::ErrorKind::NotFound, "nope");
46        let e: SdkError = io.into();
47        assert!(e.to_string().starts_with("io: "), "got {e}");
48    }
49
50    #[test]
51    fn from_hal_error_is_wrapped() {
52        let hal = cr1140_hal::HalError::DeviceNotFound("kbd".into());
53        let e: SdkError = hal.into();
54        assert!(matches!(e, SdkError::Hal(_)));
55        assert!(e.to_string().starts_with("hal: "), "got {e}");
56    }
57
58    #[cfg(feature = "config")]
59    #[test]
60    fn from_toml_decode_error_is_wrapped() {
61        // `= 1` with no key is invalid TOML.
62        let err = toml::from_str::<toml::Table>("= 1").unwrap_err();
63        let e: SdkError = err.into();
64        assert!(matches!(e, SdkError::Decode(_)));
65    }
66}