Skip to main content

canlink_hal/
state.rs

1//! Backend state management.
2//!
3//! This module defines the lifecycle states of a backend.
4
5/// Backend lifecycle state.
6///
7/// Represents the current state of a backend in its lifecycle.
8/// Backends transition through these states during initialization,
9/// operation, and shutdown.
10///
11/// # State Transitions
12///
13/// ```text
14/// Uninitialized -> Initializing -> Ready -> Closing -> Closed
15///                       ↓            ↓
16///                     Error ←--------┘
17/// ```
18///
19/// # Examples
20///
21/// ```
22/// use canlink_hal::BackendState;
23///
24/// let state = BackendState::Uninitialized;
25/// assert!(!state.is_ready());
26///
27/// let state = BackendState::Ready;
28/// assert!(state.is_ready());
29/// ```
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
31pub enum BackendState {
32    /// Backend has not been initialized
33    #[default]
34    Uninitialized,
35
36    /// Backend is currently initializing
37    Initializing,
38
39    /// Backend is ready for operations
40    Ready,
41
42    /// Backend is closing
43    Closing,
44
45    /// Backend has been closed
46    Closed,
47
48    /// Backend encountered an error
49    Error,
50}
51
52impl BackendState {
53    /// Check if the backend is ready for operations.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use canlink_hal::BackendState;
59    ///
60    /// assert!(BackendState::Ready.is_ready());
61    /// assert!(!BackendState::Uninitialized.is_ready());
62    /// ```
63    #[must_use]
64    pub const fn is_ready(&self) -> bool {
65        matches!(self, Self::Ready)
66    }
67
68    /// Check if the backend is in an error state.
69    ///
70    /// # Examples
71    ///
72    /// ```
73    /// use canlink_hal::BackendState;
74    ///
75    /// assert!(BackendState::Error.is_error());
76    /// assert!(!BackendState::Ready.is_error());
77    /// ```
78    #[must_use]
79    pub const fn is_error(&self) -> bool {
80        matches!(self, Self::Error)
81    }
82
83    /// Check if the backend is closed.
84    ///
85    /// # Examples
86    ///
87    /// ```
88    /// use canlink_hal::BackendState;
89    ///
90    /// assert!(BackendState::Closed.is_closed());
91    /// assert!(!BackendState::Ready.is_closed());
92    /// ```
93    #[must_use]
94    pub const fn is_closed(&self) -> bool {
95        matches!(self, Self::Closed)
96    }
97
98    /// Check if the backend can accept operations.
99    ///
100    /// Returns true only if the backend is in the Ready state.
101    ///
102    /// # Examples
103    ///
104    /// ```
105    /// use canlink_hal::BackendState;
106    ///
107    /// assert!(BackendState::Ready.can_operate());
108    /// assert!(!BackendState::Initializing.can_operate());
109    /// assert!(!BackendState::Error.can_operate());
110    /// ```
111    #[must_use]
112    pub const fn can_operate(&self) -> bool {
113        matches!(self, Self::Ready)
114    }
115
116    /// Get a human-readable description of the state.
117    ///
118    /// # Examples
119    ///
120    /// ```
121    /// use canlink_hal::BackendState;
122    ///
123    /// assert_eq!(BackendState::Ready.description(), "Ready");
124    /// assert_eq!(BackendState::Error.description(), "Error");
125    /// ```
126    #[must_use]
127    pub const fn description(&self) -> &'static str {
128        match self {
129            Self::Uninitialized => "Uninitialized",
130            Self::Initializing => "Initializing",
131            Self::Ready => "Ready",
132            Self::Closing => "Closing",
133            Self::Closed => "Closed",
134            Self::Error => "Error",
135        }
136    }
137}
138
139impl std::fmt::Display for BackendState {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        write!(f, "{}", self.description())
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn test_state_checks() {
151        assert!(BackendState::Ready.is_ready());
152        assert!(!BackendState::Uninitialized.is_ready());
153
154        assert!(BackendState::Error.is_error());
155        assert!(!BackendState::Ready.is_error());
156
157        assert!(BackendState::Closed.is_closed());
158        assert!(!BackendState::Ready.is_closed());
159    }
160
161    #[test]
162    fn test_can_operate() {
163        assert!(BackendState::Ready.can_operate());
164        assert!(!BackendState::Uninitialized.can_operate());
165        assert!(!BackendState::Initializing.can_operate());
166        assert!(!BackendState::Closing.can_operate());
167        assert!(!BackendState::Closed.can_operate());
168        assert!(!BackendState::Error.can_operate());
169    }
170
171    #[test]
172    fn test_description() {
173        assert_eq!(BackendState::Uninitialized.description(), "Uninitialized");
174        assert_eq!(BackendState::Initializing.description(), "Initializing");
175        assert_eq!(BackendState::Ready.description(), "Ready");
176        assert_eq!(BackendState::Closing.description(), "Closing");
177        assert_eq!(BackendState::Closed.description(), "Closed");
178        assert_eq!(BackendState::Error.description(), "Error");
179    }
180
181    #[test]
182    fn test_display() {
183        assert_eq!(format!("{}", BackendState::Ready), "Ready");
184        assert_eq!(format!("{}", BackendState::Error), "Error");
185    }
186
187    #[test]
188    fn test_default() {
189        assert_eq!(BackendState::default(), BackendState::Uninitialized);
190    }
191}