Skip to main content

vibe_ready/api/
connection_status.rs

1use crate::api::engine_error::{VibeEngineError, VibeEngineErrorCode};
2use crate::log::log_def::DESC;
3use crate::{err, log_e};
4use serde::{Deserialize, Serialize};
5use std::backtrace::Backtrace;
6use std::fmt;
7
8#[repr(i32)]
9#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize, Eq, Default)]
10/// Connection lifecycle state used by status integrations.
11pub enum VibeConnectionStatus {
12    /// No connection attempt is active.
13    #[default]
14    Idle,
15
16    /// A connection attempt is in progress.
17    Connecting,
18
19    /// The connection is established.
20    Connected,
21
22    /// Disconnect is in progress.
23    Disconnecting,
24
25    /// The connection has been closed.
26    Disconnected,
27}
28
29impl fmt::Display for VibeConnectionStatus {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        let s = match self {
32            VibeConnectionStatus::Idle => "Idle",
33            VibeConnectionStatus::Connecting => "Connecting",
34            VibeConnectionStatus::Connected => "Connected",
35            VibeConnectionStatus::Disconnecting => "Disconnecting",
36            VibeConnectionStatus::Disconnected => "Disconnected",
37        };
38        write!(f, "{}", s)
39    }
40}
41
42fn trans_unreachable(
43    from: VibeConnectionStatus,
44    to: VibeConnectionStatus,
45) -> Result<VibeConnectionStatus, VibeEngineError> {
46    log_e!(
47        "trans_unreachable",
48        DESC,
49        format!(
50            "trans_unreachable_test error , from: {:?},to: {:?}, -- {:?}",
51            from,
52            to,
53            Backtrace::capture()
54        )
55    );
56    Err(err!(VibeEngineError::from_internal_error()))
57}
58
59impl VibeConnectionStatus {
60    /// Applies a validated transition to `new_status`.
61    ///
62    /// # Returns
63    ///
64    /// `Ok(new_status)` when the transition is allowed, or [`VibeEngineError`]
65    /// when the transition is invalid for the current state.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// use vibe_ready::{VibeConnectionStatus, VibeResult};
71    ///
72    /// # fn demo() -> VibeResult<()> {
73    /// let mut status = VibeConnectionStatus::Idle;
74    /// assert_eq!(status.trans(VibeConnectionStatus::Connecting)?, VibeConnectionStatus::Connecting);
75    /// # Ok(())
76    /// # }
77    /// ```
78    pub fn trans(
79        &mut self,
80        new_status: VibeConnectionStatus,
81    ) -> Result<VibeConnectionStatus, VibeEngineError> {
82        let ret = match self {
83            VibeConnectionStatus::Idle => match new_status {
84                VibeConnectionStatus::Idle => Ok(VibeConnectionStatus::Idle),
85                VibeConnectionStatus::Connecting => Ok(VibeConnectionStatus::Connecting),
86                VibeConnectionStatus::Connected => trans_unreachable(self.clone(), new_status),
87                VibeConnectionStatus::Disconnecting => Err(err!(VibeEngineError::from_error_code(
88                    VibeEngineErrorCode::ConnectionClosed
89                ))),
90                VibeConnectionStatus::Disconnected => Ok(VibeConnectionStatus::Disconnected),
91            },
92            VibeConnectionStatus::Connecting => match new_status {
93                VibeConnectionStatus::Idle => Ok(VibeConnectionStatus::Idle),
94                VibeConnectionStatus::Connecting => trans_unreachable(self.clone(), new_status),
95                VibeConnectionStatus::Connected => Ok(VibeConnectionStatus::Connected),
96                VibeConnectionStatus::Disconnecting => Ok(VibeConnectionStatus::Disconnecting),
97                VibeConnectionStatus::Disconnected => Ok(VibeConnectionStatus::Disconnected),
98            },
99            VibeConnectionStatus::Connected => match new_status {
100                VibeConnectionStatus::Idle => Ok(VibeConnectionStatus::Idle),
101                VibeConnectionStatus::Connecting => Err(VibeEngineError::from_error_code(
102                    VibeEngineErrorCode::ConnectionExists,
103                )),
104                VibeConnectionStatus::Connected => trans_unreachable(self.clone(), new_status),
105                VibeConnectionStatus::Disconnecting => Ok(VibeConnectionStatus::Disconnecting),
106                VibeConnectionStatus::Disconnected => Ok(VibeConnectionStatus::Disconnected),
107            },
108            VibeConnectionStatus::Disconnecting => match new_status {
109                VibeConnectionStatus::Idle => Ok(VibeConnectionStatus::Idle),
110                VibeConnectionStatus::Connecting => Ok(VibeConnectionStatus::Connecting),
111                VibeConnectionStatus::Connected => trans_unreachable(self.clone(), new_status),
112                VibeConnectionStatus::Disconnecting => Err(err!(VibeEngineError::from_error_code(
113                    VibeEngineErrorCode::ConnectionClosing
114                ))),
115                VibeConnectionStatus::Disconnected => Ok(VibeConnectionStatus::Disconnected),
116            },
117            VibeConnectionStatus::Disconnected => match new_status {
118                VibeConnectionStatus::Idle => Ok(VibeConnectionStatus::Idle),
119                VibeConnectionStatus::Connecting => Ok(VibeConnectionStatus::Connecting),
120                VibeConnectionStatus::Connected => trans_unreachable(self.clone(), new_status),
121                VibeConnectionStatus::Disconnecting => Err(err!(VibeEngineError::from_error_code(
122                    VibeEngineErrorCode::ConnectionClosed,
123                ))),
124                VibeConnectionStatus::Disconnected => Ok(VibeConnectionStatus::Disconnected),
125            },
126        };
127        *self = ret?;
128        Ok(*self)
129    }
130}
131
132#[cfg(test)]
133mod strict_tests {
134    use super::*;
135    include!(concat!(
136        env!("CARGO_MANIFEST_DIR"),
137        "/test/unit/api/connection_status_tests.rs"
138    ));
139}