Skip to main content

fraiseql_wire/connection/state/
mod.rs

1//! Connection state machine
2
3use crate::{Result, WireError};
4
5/// Connection state
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[non_exhaustive]
8pub enum ConnectionState {
9    /// Initial state (not connected)
10    Initial,
11
12    /// Startup sent, awaiting authentication request
13    AwaitingAuth,
14
15    /// Authentication in progress
16    Authenticating,
17
18    /// Idle (ready for query)
19    Idle,
20
21    /// Query in progress
22    QueryInProgress,
23
24    /// Reading query results
25    ReadingResults,
26
27    /// Closed
28    Closed,
29}
30
31impl ConnectionState {
32    /// Check if transition is valid
33    #[must_use]
34    pub const fn can_transition_to(&self, next: ConnectionState) -> bool {
35        use ConnectionState::{
36            Authenticating, AwaitingAuth, Closed, Idle, Initial, QueryInProgress, ReadingResults,
37        };
38
39        matches!(
40            (self, next),
41            (Initial, AwaitingAuth)
42                | (AwaitingAuth, Authenticating)
43                | (Authenticating | ReadingResults, Idle)
44                | (Idle, QueryInProgress)
45                | (QueryInProgress, ReadingResults)
46                | (_, Closed)
47        )
48    }
49
50    /// Transition to new state
51    ///
52    /// # Errors
53    ///
54    /// Returns [`WireError::InvalidState`] if the transition from the current state to `next`
55    /// is not permitted by the state machine.
56    pub fn transition(&mut self, next: ConnectionState) -> Result<()> {
57        if !self.can_transition_to(next) {
58            return Err(WireError::InvalidState {
59                expected: format!("valid transition from {:?}", self),
60                actual: format!("{:?}", next),
61            });
62        }
63        *self = next;
64        Ok(())
65    }
66}
67
68impl std::fmt::Display for ConnectionState {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        match self {
71            Self::Initial => write!(f, "initial"),
72            Self::AwaitingAuth => write!(f, "awaiting_auth"),
73            Self::Authenticating => write!(f, "authenticating"),
74            Self::Idle => write!(f, "idle"),
75            Self::QueryInProgress => write!(f, "query_in_progress"),
76            Self::ReadingResults => write!(f, "reading_results"),
77            Self::Closed => write!(f, "closed"),
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests;