Skip to main content

rvcsi_core/
error.rs

1//! Error type for the rvCSI runtime.
2
3use thiserror::Error;
4
5use crate::validation::ValidationError;
6
7/// Errors surfaced by the rvCSI core, adapters, DSP and event pipeline.
8///
9/// Parser failures are structured (never panics, never raw pointers across
10/// boundaries — ADR-095 D6). A `Validation` error means a frame was *rejected*;
11/// a *degraded* frame is not an error and is returned normally with reduced
12/// `quality_score`.
13#[derive(Debug, Error)]
14#[non_exhaustive]
15pub enum RvcsiError {
16    /// A source/adapter could not be opened or talked to.
17    #[error("adapter '{kind}' failed: {message}")]
18    Adapter {
19        /// The adapter kind (`"file"`, `"nexmon"`, `"esp32"`, ...).
20        kind: String,
21        /// Human-readable detail.
22        message: String,
23    },
24
25    /// A raw byte buffer could not be parsed into a frame.
26    #[error("parse error at offset {offset}: {message}")]
27    Parse {
28        /// Byte offset where parsing failed (best effort).
29        offset: usize,
30        /// Human-readable detail.
31        message: String,
32    },
33
34    /// A frame failed validation and was rejected.
35    #[error("frame rejected: {0}")]
36    Validation(#[from] ValidationError),
37
38    /// A configuration value was out of range or inconsistent.
39    #[error("invalid configuration: {0}")]
40    Config(String),
41
42    /// An I/O error (file capture, replay, WebSocket, ...).
43    #[error("io error: {0}")]
44    Io(#[from] std::io::Error),
45
46    /// Serialization / deserialization error (JSON capture sidecars, RuVector export).
47    #[error("serde error: {0}")]
48    Serde(#[from] serde_json::Error),
49
50    /// The requested operation is not supported by this source/adapter.
51    #[error("unsupported: {0}")]
52    Unsupported(String),
53}
54
55impl RvcsiError {
56    /// Convenience constructor for adapter errors.
57    pub fn adapter(kind: impl Into<String>, message: impl Into<String>) -> Self {
58        RvcsiError::Adapter {
59            kind: kind.into(),
60            message: message.into(),
61        }
62    }
63
64    /// Convenience constructor for parse errors.
65    pub fn parse(offset: usize, message: impl Into<String>) -> Self {
66        RvcsiError::Parse {
67            offset,
68            message: message.into(),
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn display_messages_are_useful() {
79        let e = RvcsiError::adapter("nexmon", "device /dev/wlan0 not in monitor mode");
80        assert!(e.to_string().contains("nexmon"));
81        assert!(e.to_string().contains("monitor mode"));
82
83        let e = RvcsiError::parse(12, "frame length 0");
84        assert!(e.to_string().contains("offset 12"));
85    }
86}