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