cuprate_types/
connection_state.rs

1//! [`ConnectionState`].
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "epee")]
7use cuprate_epee_encoding::{
8    error,
9    macros::bytes::{Buf, BufMut},
10    EpeeValue, Marker,
11};
12
13use strum::{
14    AsRefStr, Display, EnumCount, EnumIs, EnumString, FromRepr, IntoStaticStr, VariantArray,
15};
16
17/// An enumeration of P2P connection states.
18///
19/// Used in `cuprate_p2p` and `cuprate_rpc_types`.
20///
21/// Original definition:
22/// - <https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/src/cryptonote_basic/connection_context.h#L49>
23///
24/// # Serde
25/// This type's `serde` implementation depends on `snake_case`.
26///
27/// ```rust
28/// use cuprate_types::ConnectionState as C;
29/// use serde_json::to_string;
30///
31/// assert_eq!(to_string(&C::BeforeHandshake).unwrap(), r#""before_handshake""#);
32/// assert_eq!(to_string(&C::Synchronizing).unwrap(), r#""synchronizing""#);
33/// assert_eq!(to_string(&C::Standby).unwrap(), r#""standby""#);
34/// assert_eq!(to_string(&C::Idle).unwrap(), r#""idle""#);
35/// assert_eq!(to_string(&C::Normal).unwrap(), r#""normal""#);
36///
37/// assert_eq!(C::BeforeHandshake.to_string(), "before_handshake");
38/// assert_eq!(C::Synchronizing.to_string(), "synchronizing");
39/// assert_eq!(C::Standby.to_string(), "standby");
40/// assert_eq!(C::Idle.to_string(), "idle");
41/// assert_eq!(C::Normal.to_string(), "normal");
42/// ```
43#[derive(
44    Copy,
45    Clone,
46    Default,
47    Debug,
48    PartialEq,
49    Eq,
50    PartialOrd,
51    Ord,
52    Hash,
53    AsRefStr,
54    Display,
55    EnumCount,
56    EnumIs,
57    EnumString,
58    FromRepr,
59    IntoStaticStr,
60    VariantArray,
61)]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] // cuprate-rpc-types depends on snake_case
64#[strum(serialize_all = "snake_case")]
65#[repr(u8)]
66pub enum ConnectionState {
67    BeforeHandshake,
68    Synchronizing,
69    Standby,
70    Idle,
71    #[default]
72    Normal,
73}
74
75impl ConnectionState {
76    /// Convert [`Self`] to a [`u8`].
77    ///
78    /// ```rust
79    /// use cuprate_types::ConnectionState as C;
80    ///
81    /// assert_eq!(C::BeforeHandshake.to_u8(), 0);
82    /// assert_eq!(C::Synchronizing.to_u8(), 1);
83    /// assert_eq!(C::Standby.to_u8(), 2);
84    /// assert_eq!(C::Idle.to_u8(), 3);
85    /// assert_eq!(C::Normal.to_u8(), 4);
86    /// ```
87    pub const fn to_u8(self) -> u8 {
88        self as u8
89    }
90
91    /// Convert a [`u8`] to a [`Self`].
92    ///
93    /// # Errors
94    /// This returns [`None`] if `u > 4`.
95    ///
96    /// ```rust
97    /// use cuprate_types::ConnectionState as C;
98    ///
99    /// assert_eq!(C::from_u8(0), Some(C::BeforeHandshake));
100    /// assert_eq!(C::from_u8(1), Some(C::Synchronizing));
101    /// assert_eq!(C::from_u8(2), Some(C::Standby));
102    /// assert_eq!(C::from_u8(3), Some(C::Idle));
103    /// assert_eq!(C::from_u8(4), Some(C::Normal));
104    /// assert_eq!(C::from_u8(5), None);
105    /// ```
106    pub const fn from_u8(u: u8) -> Option<Self> {
107        Some(match u {
108            0 => Self::BeforeHandshake,
109            1 => Self::Synchronizing,
110            2 => Self::Standby,
111            3 => Self::Idle,
112            4 => Self::Normal,
113            _ => return None,
114        })
115    }
116}
117
118impl From<ConnectionState> for u8 {
119    fn from(value: ConnectionState) -> Self {
120        value.to_u8()
121    }
122}
123
124impl TryFrom<u8> for ConnectionState {
125    type Error = u8;
126    fn try_from(value: u8) -> Result<Self, Self::Error> {
127        match Self::from_u8(value) {
128            Some(s) => Ok(s),
129            None => Err(value),
130        }
131    }
132}
133
134#[cfg(feature = "epee")]
135impl EpeeValue for ConnectionState {
136    const MARKER: Marker = u8::MARKER;
137
138    fn read<B: Buf>(r: &mut B, marker: &Marker) -> error::Result<Self> {
139        let u = u8::read(r, marker)?;
140        Self::from_u8(u).ok_or(error::Error::Format("u8 was greater than 4"))
141    }
142
143    fn write<B: BufMut>(self, w: &mut B) -> error::Result<()> {
144        let u = self.to_u8();
145        u8::write(u, w)?;
146        Ok(())
147    }
148}