1use nodecraft::{CheapClone, Node};
2
3use super::{DelegateVersion, Meta, ProtocolVersion};
4
5#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
7#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
8#[cfg_attr(
9 feature = "rkyv",
10 derive(::rkyv::Serialize, ::rkyv::Deserialize, ::rkyv::Archive)
11)]
12#[cfg_attr(
13 feature = "rkyv",
14 rkyv(compare(PartialEq), derive(Debug, Clone, PartialEq, Eq, Hash))
15)]
16#[repr(u8)]
17#[non_exhaustive]
18pub enum State {
19 #[default]
21 Alive = 0,
22 Suspect = 1,
24 Dead = 2,
26 Left = 3,
28}
29
30impl State {
31 pub const fn as_str(&self) -> &'static str {
33 match self {
34 Self::Alive => "alive",
35 Self::Suspect => "suspect",
36 Self::Dead => "dead",
37 Self::Left => "left",
38 }
39 }
40
41 #[cfg(feature = "metrics")]
43 #[cfg_attr(feature = "docs", doc(cfg(feature = "metrics")))]
44 #[inline]
45 pub const fn metrics_array() -> [(&'static str, usize); 4] {
46 [("alive", 0), ("suspect", 0), ("dead", 0), ("left", 0)]
47 }
48}
49
50impl core::fmt::Display for State {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 write!(f, "{}", self.as_str())
53 }
54}
55
56impl TryFrom<u8> for State {
57 type Error = UnknownState;
58
59 fn try_from(value: u8) -> Result<Self, Self::Error> {
60 Ok(match value {
61 0 => Self::Alive,
62 1 => Self::Suspect,
63 2 => Self::Dead,
64 3 => Self::Left,
65 _ => return Err(UnknownState(value)),
66 })
67 }
68}
69
70#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, thiserror::Error)]
72#[error("{0} is not a valid state")]
73pub struct UnknownState(u8);
74
75#[viewit::viewit(getters(vis_all = "pub"), setters(vis_all = "pub", prefix = "with"))]
77#[derive(Debug, Clone, PartialEq, Eq, Hash)]
78#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
79#[cfg_attr(
80 feature = "rkyv",
81 derive(::rkyv::Serialize, ::rkyv::Deserialize, ::rkyv::Archive)
82)]
83#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq)))]
84pub struct NodeState<I, A> {
85 #[viewit(
87 getter(const, style = "ref", attrs(doc = "Returns the id of the node")),
88 setter(attrs(doc = "Sets the id of the node (Builder pattern)"))
89 )]
90 id: I,
91 #[viewit(
93 getter(
94 const,
95 rename = "address",
96 style = "ref",
97 attrs(doc = "Returns the address of the node")
98 ),
99 setter(
100 rename = "with_address",
101 attrs(doc = "Sets the address of the node (Builder pattern)")
102 )
103 )]
104 addr: A,
105 #[viewit(
107 getter(const, style = "ref", attrs(doc = "Returns the meta of the node")),
108 setter(attrs(doc = "Sets the meta of the node (Builder pattern)"))
109 )]
110 meta: Meta,
111 #[viewit(
113 getter(const, attrs(doc = "Returns the state of the node")),
114 setter(const, attrs(doc = "Sets the state of the node (Builder pattern)"))
115 )]
116 state: State,
117 #[viewit(
119 getter(
120 const,
121 style = "move",
122 attrs(doc = "Returns the protocol version of the node is speaking")
123 ),
124 setter(
125 const,
126 attrs(doc = "Sets the protocol version of the node is speaking (Builder pattern)")
127 )
128 )]
129 protocol_version: ProtocolVersion,
130 #[viewit(
132 getter(
133 const,
134 style = "move",
135 attrs(doc = "Returns the delegate version of the node is speaking")
136 ),
137 setter(
138 const,
139 attrs(doc = "Sets the delegate version of the node is speaking (Builder pattern)")
140 )
141 )]
142 delegate_version: DelegateVersion,
143}
144
145impl<I: CheapClone, A: CheapClone> From<super::Alive<I, A>> for NodeState<I, A> {
146 fn from(value: super::Alive<I, A>) -> Self {
147 let (id, addr) = value.node.into_components();
148 Self {
149 id,
150 addr,
151 meta: value.meta,
152 state: State::Alive,
153 protocol_version: value.protocol_version,
154 delegate_version: value.delegate_version,
155 }
156 }
157}
158
159impl<I, A> NodeState<I, A> {
160 #[inline]
162 pub const fn new(id: I, addr: A, state: State) -> Self {
163 Self {
164 id,
165 addr,
166 meta: Meta::empty(),
167 state,
168 protocol_version: ProtocolVersion::V1,
169 delegate_version: DelegateVersion::V1,
170 }
171 }
172
173 #[inline]
175 pub fn set_id(&mut self, id: I) -> &mut Self {
176 self.id = id;
177 self
178 }
179
180 #[inline]
182 pub fn set_address(&mut self, addr: A) -> &mut Self {
183 self.addr = addr;
184 self
185 }
186
187 #[inline]
189 pub fn set_meta(&mut self, meta: Meta) -> &mut Self {
190 self.meta = meta;
191 self
192 }
193
194 #[inline]
196 pub fn set_state(&mut self, state: State) -> &mut Self {
197 self.state = state;
198 self
199 }
200
201 #[inline]
203 pub fn set_protocol_version(&mut self, protocol_version: ProtocolVersion) -> &mut Self {
204 self.protocol_version = protocol_version;
205 self
206 }
207
208 #[inline]
210 pub fn set_delegate_version(&mut self, delegate_version: DelegateVersion) -> &mut Self {
211 self.delegate_version = delegate_version;
212 self
213 }
214}
215
216impl<I: CheapClone, A: CheapClone> CheapClone for NodeState<I, A> {
217 fn cheap_clone(&self) -> Self {
218 Self {
219 id: self.id.cheap_clone(),
220 addr: self.addr.cheap_clone(),
221 meta: self.meta.cheap_clone(),
222 state: self.state,
223 protocol_version: self.protocol_version,
224 delegate_version: self.delegate_version,
225 }
226 }
227}
228
229impl<I: CheapClone, A: CheapClone> NodeState<I, A> {
230 pub fn node(&self) -> Node<I, A> {
232 Node::new(self.id.cheap_clone(), self.addr.cheap_clone())
233 }
234}
235
236impl<I: core::fmt::Display, A: core::fmt::Display> core::fmt::Display for NodeState<I, A> {
237 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
238 write!(f, "{}({})", self.id, self.addr)
239 }
240}
241
242#[cfg(feature = "rkyv")]
243const _: () = {
244 use core::fmt::Debug;
245 use rkyv::Archive;
246
247 impl<I: Debug + Archive, A: Debug + Archive> core::fmt::Debug for ArchivedNodeState<I, A>
248 where
249 I::Archived: Debug,
250 A::Archived: Debug,
251 {
252 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
253 f.debug_struct("NodeState")
254 .field("id", &self.id)
255 .field("addr", &self.addr)
256 .field("meta", &self.meta)
257 .field("state", &self.state)
258 .field("protocol_version", &self.protocol_version)
259 .field("delegate_version", &self.delegate_version)
260 .finish()
261 }
262 }
263
264 impl<I: Archive, A: Archive> PartialEq for ArchivedNodeState<I, A>
265 where
266 I::Archived: PartialEq,
267 A::Archived: PartialEq,
268 {
269 fn eq(&self, other: &Self) -> bool {
270 self.id == other.id
271 && self.addr == other.addr
272 && self.meta == other.meta
273 && self.state == other.state
274 && self.protocol_version == other.protocol_version
275 && self.delegate_version == other.delegate_version
276 }
277 }
278
279 impl<I: Archive, A: Archive> Eq for ArchivedNodeState<I, A>
280 where
281 I::Archived: Eq,
282 A::Archived: Eq,
283 {
284 }
285
286 impl<I: Archive, A: Archive> core::hash::Hash for ArchivedNodeState<I, A>
287 where
288 I::Archived: core::hash::Hash,
289 A::Archived: core::hash::Hash,
290 {
291 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
292 self.id.hash(state);
293 self.addr.hash(state);
294 self.meta.hash(state);
295 self.state.hash(state);
296 self.protocol_version.hash(state);
297 self.delegate_version.hash(state);
298 }
299 }
300};
301
302#[cfg(test)]
303mod tests {
304 use std::net::SocketAddr;
305
306 use smol_str::SmolStr;
307
308 use super::*;
309
310 #[test]
311 fn test_state_try_from() {
312 assert_eq!(State::try_from(0), Ok(State::Alive));
313 assert_eq!(State::try_from(1), Ok(State::Suspect));
314 assert_eq!(State::try_from(2), Ok(State::Dead));
315 assert_eq!(State::try_from(3), Ok(State::Left));
316 assert_eq!(State::try_from(4), Err(UnknownState(4)));
317 }
318
319 #[test]
320 fn test_state_as_str() {
321 assert_eq!(State::Alive.as_str(), "alive");
322 assert_eq!(State::Suspect.as_str(), "suspect");
323 assert_eq!(State::Dead.as_str(), "dead");
324 assert_eq!(State::Left.as_str(), "left");
325 }
326
327 #[test]
328 fn test_node_state_cheap_clone() {
329 let node = NodeState::<_, SocketAddr>::new(
330 SmolStr::from("a"),
331 "127.0.0.1:8080".parse().unwrap(),
332 State::Alive,
333 );
334 let node2 = node.cheap_clone();
335 assert_eq!(node, node2);
336 }
337
338 #[test]
339 fn test_access() {
340 let mut node = NodeState::<_, SocketAddr>::new(
341 SmolStr::from("a"),
342 "127.0.0.1:8080".parse().unwrap(),
343 State::Alive,
344 );
345
346 node.set_address("127.0.0.1:8081".parse().unwrap());
347 assert_eq!(node.address(), &SocketAddr::from(([127, 0, 0, 1], 8081)));
348 node.set_id(SmolStr::from("b"));
349 assert_eq!(node.id(), &SmolStr::from("b"));
350 node.set_meta(Meta::empty());
351 assert_eq!(node.meta(), &Meta::empty());
352 node.set_state(State::Dead);
353 assert_eq!(node.state(), State::Dead);
354 node.set_protocol_version(ProtocolVersion::V1);
355 assert_eq!(node.protocol_version(), ProtocolVersion::V1);
356 node.set_delegate_version(DelegateVersion::V1);
357 assert_eq!(node.delegate_version(), DelegateVersion::V1);
358 println!("{}", node);
359 }
360}