atm0s_sdn_identity/
node_id.rs

1pub type NodeId = u32;
2
3#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4/// Enum representing a segment of a node ID.
5pub enum NodeSegment {
6    Public,
7    Private(u8),
8}
9
10pub trait NodeIdType: Clone {
11    /// Generates a random `NodeId`.
12    fn random() -> NodeId;
13    /// Returns the segment of the node ID.
14    fn segment(&self) -> NodeSegment;
15    /// Calculates the distance between two NodeIds.
16    fn distance(&self, other: &NodeId) -> u32;
17    /// Calculates the distance in bits between two NodeIds.
18    ///
19    /// # Arguments
20    ///
21    /// * `other` - The other NodeId to calculate the distance to.
22    ///
23    /// # Returns
24    ///
25    /// The distance in bits between the two NodeIds.
26    fn distance_bits(&self, other: &NodeId) -> u8;
27    /// Returns the index of the bucket that this node ID belongs to.
28    fn bucket_index(&self) -> u8;
29
30    /// Builds a new `NodeId` with the given geographic location, group, and index.
31    ///
32    /// # Arguments
33    ///
34    /// * `geo1` - The first geographic location byte.
35    /// * `geo2` - The second geographic location byte.
36    /// * `group` - The group byte.
37    /// * `index` - The index byte.
38    fn build(geo1: u8, geo2: u8, group: u8, index: u8) -> Self;
39    /// Builds a `NodeId` from a zone ID, group, and index.
40    fn build2(zone_id: u16, group: u8, index: u8) -> Self;
41    /// Returns the value of the layer of the node at the given index.
42    fn layer(&self, index: u8) -> u8;
43    /// Returns the first geographic location byte.
44    fn geo1(&self) -> u8;
45    /// Returns the second geographic location byte.
46    fn geo2(&self) -> u8;
47    /// Returns the group byte.
48    fn group(&self) -> u8;
49    /// Returns the index byte.
50    fn index(&self) -> u8;
51    /// Returns the number of layers that the two NodeIds are equal up to.
52    fn eq_util_layer(&self, other: &Self) -> u8;
53}
54
55impl NodeIdType for NodeId {
56    fn random() -> NodeId {
57        rand::random()
58    }
59
60    fn segment(&self) -> NodeSegment {
61        NodeSegment::Public
62    }
63
64    fn distance(&self, other: &NodeId) -> u32 {
65        self ^ *other
66    }
67
68    fn distance_bits(&self, other: &NodeId) -> u8 {
69        let distance = self.distance(other);
70        (32 - distance.leading_zeros()) as u8
71    }
72
73    fn bucket_index(&self) -> u8 {
74        (32 - self.leading_zeros()) as u8
75    }
76
77    fn layer(&self, index: u8) -> u8 {
78        assert!(index <= 3);
79
80        (*self >> (8 * index)) as u8
81    }
82
83    fn build(geo1: u8, geo2: u8, group: u8, index: u8) -> Self {
84        ((geo1 as u32) << (8 * 3)) | ((geo2 as u32) << (8 * 2)) | ((group as u32) << 8) | (index as u32)
85    }
86
87    fn build2(zone_id: u16, group: u8, index: u8) -> Self {
88        ((zone_id as u32) << 16) | ((group as u32) << 8) | (index as u32)
89    }
90
91    fn geo1(&self) -> u8 {
92        (*self >> (8 * 3)) as u8
93    }
94
95    fn geo2(&self) -> u8 {
96        (*self >> (8 * 2)) as u8
97    }
98
99    fn group(&self) -> u8 {
100        (*self >> 8) as u8
101    }
102
103    fn index(&self) -> u8 {
104        *self as u8
105    }
106
107    // TODO: typo in name, should be eq_until_layer
108    fn eq_util_layer(&self, other: &Self) -> u8 {
109        if self.layer(3) != other.layer(3) {
110            return 4;
111        }
112
113        if self.layer(2) != other.layer(2) {
114            return 3;
115        }
116
117        if self.layer(1) != other.layer(1) {
118            return 2;
119        }
120
121        if self.layer(0) != other.layer(0) {
122            return 1;
123        }
124
125        0
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use crate::NodeSegment;
132
133    use super::{NodeId, NodeIdType};
134
135    #[test]
136    fn my_distance() {
137        let id1: NodeId = 30;
138        assert_eq!(id1.distance(&id1), 0);
139        assert_eq!(id1.distance_bits(&id1), 0);
140    }
141
142    #[test]
143    fn test_random() {
144        let id1 = NodeId::random();
145        let id2 = NodeId::random();
146        assert_ne!(id1, id2);
147    }
148
149    #[test]
150    fn test_segment() {
151        let id1: NodeId = 30;
152        assert_eq!(id1.segment(), NodeSegment::Public);
153    }
154
155    #[test]
156    fn test_distance() {
157        let id1: NodeId = 0;
158        let id2: NodeId = 1;
159        let id3: NodeId = 2;
160        let id4: NodeId = 3;
161        let id5: NodeId = u32::MAX;
162
163        assert_eq!(id1.distance(&id1), 0);
164        assert_eq!(id1.distance_bits(&id1), 0);
165
166        assert_eq!(id1.distance_bits(&id2), 1);
167        assert_eq!(id1.distance_bits(&id3), 2);
168        assert_eq!(id1.distance_bits(&id4), 2);
169        assert_eq!(id1.distance_bits(&id5), 32);
170    }
171
172    #[test]
173    fn test_bucket_index() {
174        let id1: NodeId = 0;
175        let id2: NodeId = 1;
176        let id3: NodeId = 2;
177        let id4: NodeId = 3;
178        let id5: NodeId = u32::MAX;
179
180        assert_eq!(id1.bucket_index(), 0);
181        assert_eq!(id2.bucket_index(), 1);
182        assert_eq!(id3.bucket_index(), 2);
183        assert_eq!(id4.bucket_index(), 2);
184        assert_eq!(id5.bucket_index(), 32);
185    }
186
187    #[test]
188    fn test_layer() {
189        let id1: NodeId = 0x12345678;
190        assert_eq!(id1.layer(0), 0x78);
191        assert_eq!(id1.layer(1), 0x56);
192        assert_eq!(id1.layer(2), 0x34);
193        assert_eq!(id1.layer(3), 0x12);
194    }
195
196    #[test]
197    fn test_eq_util_layer() {
198        let id1: NodeId = 0x12345678;
199        let id2: NodeId = 0x12345679;
200        let id3: NodeId = 0x12345778;
201        let id4: NodeId = 0x12355678;
202        let id5: NodeId = 0x12345678;
203
204        assert_eq!(id1.eq_util_layer(&id2), 1);
205        assert_eq!(id1.eq_util_layer(&id3), 2);
206        assert_eq!(id1.eq_util_layer(&id4), 3);
207        assert_eq!(id1.eq_util_layer(&id5), 0);
208    }
209}