memberlist_types/
server.rs

1use nodecraft::{CheapClone, Node};
2
3use super::{DelegateVersion, Meta, ProtocolVersion};
4
5/// State for the memberlist
6#[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  /// Alive state
20  #[default]
21  Alive = 0,
22  /// Suspect state
23  Suspect = 1,
24  /// Dead state
25  Dead = 2,
26  /// Left state
27  Left = 3,
28}
29
30impl State {
31  /// Returns the [`State`] as a `&'static str`.
32  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  /// Returns an array of the default state metrics.
42  #[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/// Unknown server state.
71#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, thiserror::Error)]
72#[error("{0} is not a valid state")]
73pub struct UnknownState(u8);
74
75/// Represents a node in the cluster
76#[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  /// The id of the node.
86  #[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  /// The address of the node.
92  #[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  /// Metadata from the delegate for this node.
106  #[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  /// State of the node.
112  #[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  /// The protocol version of the node is speaking.
118  #[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  /// The delegate version of the node is speaking.
131  #[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  /// Construct a new node with the given name, address and state.
161  #[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  /// Sets the id of the node state
174  #[inline]
175  pub fn set_id(&mut self, id: I) -> &mut Self {
176    self.id = id;
177    self
178  }
179
180  /// Sets the address of the node state
181  #[inline]
182  pub fn set_address(&mut self, addr: A) -> &mut Self {
183    self.addr = addr;
184    self
185  }
186
187  /// Sets the metadata for the node.
188  #[inline]
189  pub fn set_meta(&mut self, meta: Meta) -> &mut Self {
190    self.meta = meta;
191    self
192  }
193
194  /// Sets the state for the node.
195  #[inline]
196  pub fn set_state(&mut self, state: State) -> &mut Self {
197    self.state = state;
198    self
199  }
200
201  /// Set the protocol version of the alive message is speaking.
202  #[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  /// Set the delegate version of the alive message is speaking.
209  #[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  /// Returns a [`Node`] with the same id and address as this [`NodeState`].
231  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}