1#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct NodeId(u64);
10
11impl NodeId {
12 pub fn random() -> Self {
13 use rand::Rng;
14 Self(rand::thread_rng().gen())
15 }
16
17 #[inline]
18 pub fn from_u64(v: u64) -> Self {
19 Self(v)
20 }
21
22 #[inline]
23 pub fn as_u64(&self) -> u64 {
24 self.0
25 }
26
27 #[inline]
28 pub fn to_bytes(&self) -> [u8; 8] {
29 self.0.to_be_bytes()
30 }
31
32 #[inline]
33 pub fn from_bytes(b: [u8; 8]) -> Self {
34 Self(u64::from_be_bytes(b))
35 }
36}
37
38impl std::fmt::Debug for NodeId {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(f, "NodeId({:016x})", self.0)
41 }
42}
43
44impl std::fmt::Display for NodeId {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 write!(f, "{:016x}", self.0)
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn random_generates_unique_ids() {
56 let ids: Vec<NodeId> = (0..100).map(|_| NodeId::random()).collect();
57 for i in 0..ids.len() {
58 for j in (i + 1)..ids.len() {
59 assert_ne!(ids[i], ids[j], "collision at indices {i} and {j}");
60 }
61 }
62 }
63
64 #[test]
65 fn u64_roundtrip() {
66 let id = NodeId::from_u64(0xDEADBEEF_CAFEBABE);
67 assert_eq!(id.as_u64(), 0xDEADBEEF_CAFEBABE);
68 }
69
70 #[test]
71 fn bytes_roundtrip() {
72 let id = NodeId::from_u64(0x0123_4567_89AB_CDEF);
73 let bytes = id.to_bytes();
74 let id2 = NodeId::from_bytes(bytes);
75 assert_eq!(id, id2);
76 }
77
78 #[test]
79 fn bytes_big_endian() {
80 let id = NodeId::from_u64(0x0102_0304_0506_0708);
81 let bytes = id.to_bytes();
82 assert_eq!(bytes, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
83 }
84
85 #[test]
86 fn ordering_consistent() {
87 let a = NodeId::from_u64(100);
88 let b = NodeId::from_u64(200);
89 assert!(a < b);
90
91 let c = NodeId::from_u64(100);
92 assert_eq!(a, c);
93 }
94
95 #[test]
96 fn display_hex() {
97 let id = NodeId::from_u64(0xFF);
98 assert_eq!(format!("{id}"), "00000000000000ff");
99 }
100
101 #[test]
102 fn debug_hex() {
103 let id = NodeId::from_u64(0xFF);
104 assert_eq!(format!("{id:?}"), "NodeId(00000000000000ff)");
105 }
106
107 #[test]
108 fn hash_consistency() {
109 use std::collections::HashSet;
110 let a = NodeId::from_u64(42);
111 let b = NodeId::from_u64(42);
112 let c = NodeId::from_u64(43);
113
114 let mut set = HashSet::new();
115 set.insert(a);
116 assert!(set.contains(&b));
117 assert!(!set.contains(&c));
118 }
119}