Skip to main content

laser_dac/
error.rs

1//! Error types for the laser-dac crate.
2
3use std::error::Error as StdError;
4use std::fmt;
5
6// =============================================================================
7// Streaming Error
8// =============================================================================
9
10/// Streaming-specific error type.
11///
12/// This error type is designed for the streaming API and includes variants
13/// that enforce the uniform backpressure contract across all backends.
14#[derive(Debug)]
15pub enum Error {
16    /// The device/library cannot accept more data right now.
17    WouldBlock,
18
19    /// The stream was explicitly stopped via `StreamControl::stop()`.
20    Stopped,
21
22    /// The device disconnected or became unreachable.
23    Disconnected(String),
24
25    /// Invalid configuration or API misuse.
26    InvalidConfig(String),
27
28    /// Backend/protocol error (wrapped).
29    Backend(Box<dyn StdError + Send + Sync>),
30}
31
32impl fmt::Display for Error {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        match self {
35            Error::WouldBlock => write!(f, "would block: device cannot accept more data"),
36            Error::Stopped => write!(f, "stopped: stream was explicitly stopped"),
37            Error::Disconnected(msg) => write!(f, "disconnected: {}", msg),
38            Error::InvalidConfig(msg) => write!(f, "invalid configuration: {}", msg),
39            Error::Backend(e) => write!(f, "backend error: {}", e),
40        }
41    }
42}
43
44impl StdError for Error {
45    fn source(&self) -> Option<&(dyn StdError + 'static)> {
46        match self {
47            Error::Backend(e) => Some(e.as_ref()),
48            _ => None,
49        }
50    }
51}
52
53impl Error {
54    /// Create a disconnected error with a message.
55    pub fn disconnected(msg: impl Into<String>) -> Self {
56        Error::Disconnected(msg.into())
57    }
58
59    /// Create an invalid config error with a message.
60    pub fn invalid_config(msg: impl Into<String>) -> Self {
61        Error::InvalidConfig(msg.into())
62    }
63
64    /// Create a backend error from any error type.
65    pub fn backend(err: impl StdError + Send + Sync + 'static) -> Self {
66        Error::Backend(Box::new(err))
67    }
68
69    /// Returns true if this is a WouldBlock error.
70    pub fn is_would_block(&self) -> bool {
71        matches!(self, Error::WouldBlock)
72    }
73
74    /// Returns true if this is a Disconnected error.
75    pub fn is_disconnected(&self) -> bool {
76        matches!(self, Error::Disconnected(_))
77    }
78
79    /// Returns true if this is a Stopped error.
80    pub fn is_stopped(&self) -> bool {
81        matches!(self, Error::Stopped)
82    }
83}
84
85impl From<std::io::Error> for Error {
86    fn from(err: std::io::Error) -> Self {
87        if err.kind() == std::io::ErrorKind::WouldBlock {
88            Error::WouldBlock
89        } else {
90            Error::Backend(Box::new(err))
91        }
92    }
93}
94
95/// Result type for streaming operations.
96pub type Result<T> = std::result::Result<T, Error>;