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}