scatter_net/legacy/utils/
distance.rs

1use ps_range::Range;
2
3fn u64_from(raw: &[u8]) -> u64 {
4    let range = (..8).clamp_right(raw.len());
5    let mut array = [0u8; 8];
6
7    array[range.clone()].copy_from_slice(&raw[range]);
8
9    u64::from_be_bytes(array)
10}
11
12pub fn distance<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: A, b: B) -> u64 {
13    let a = u64_from(a.as_ref());
14    let b = u64_from(b.as_ref());
15
16    a ^ b
17}
18
19#[cfg(test)]
20mod tests {
21    use super::*;
22
23    /// Test identical inputs of exactly 8 bytes
24    #[test]
25    fn test_distance_identical_8_bytes() {
26        let a = [1, 2, 3, 4, 5, 6, 7, 8];
27        let b = [1, 2, 3, 4, 5, 6, 7, 8];
28        assert_eq!(
29            distance(a, b),
30            0,
31            "Identical 8-byte inputs should have distance 0"
32        );
33    }
34
35    /// Test different inputs of exactly 8 bytes, differing in the first byte
36    #[test]
37    fn test_distance_different_8_bytes_first_byte() {
38        let a = [0, 0, 0, 0, 0, 0, 0, 0];
39        let b = [1, 0, 0, 0, 0, 0, 0, 0];
40        let expected = 1u64 << 56; // First byte is most significant in big-endian
41        assert_eq!(
42            distance(a, b),
43            expected,
44            "Distance should reflect difference in the first byte"
45        );
46    }
47
48    /// Test different inputs of exactly 8 bytes, differing in the last byte
49    #[test]
50    fn test_distance_different_8_bytes_last_byte() {
51        let a = [0, 0, 0, 0, 0, 0, 0, 0];
52        let b = [0, 0, 0, 0, 0, 0, 0, 1];
53        assert_eq!(
54            distance(a, b),
55            1,
56            "Distance should reflect difference in the last byte"
57        );
58    }
59
60    /// Test identical inputs shorter than 8 bytes
61    #[test]
62    fn test_distance_identical_short() {
63        let a = [1, 2, 3];
64        let b = [1, 2, 3];
65        assert_eq!(
66            distance(a, b),
67            0,
68            "Identical short inputs should have distance 0"
69        );
70    }
71
72    /// Test different inputs shorter than 8 bytes
73    #[test]
74    fn test_distance_different_short() {
75        let a = [1, 2, 3];
76        let b = [1, 2, 4];
77        let expected = 7u64 << 40; // 3 ^ 4 = 7, third byte (bits 40-47 in big-endian)
78        assert_eq!(
79            distance(a, b),
80            expected,
81            "Distance should reflect difference in short inputs"
82        );
83    }
84
85    /// Test one input shorter than 8 bytes, the other exactly 8 bytes
86    #[test]
87    fn test_distance_mixed_length() {
88        let a = [1, 2, 3];
89        let b = [1, 2, 3, 4, 5, 6, 7, 8];
90        let expected = u64::from_be_bytes([0, 0, 0, 4, 5, 6, 7, 8]);
91        assert_eq!(
92            distance(a, b),
93            expected,
94            "Distance should handle mixed length inputs correctly"
95        );
96    }
97
98    /// Test inputs longer than 8 bytes with identical first 8 bytes
99    #[test]
100    fn test_distance_long_identical() {
101        let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
102        let b = [1, 2, 3, 4, 5, 6, 7, 8, 11, 12];
103        assert_eq!(
104            distance(a, b),
105            0,
106            "Inputs with identical first 8 bytes should have distance 0"
107        );
108    }
109
110    /// Test inputs longer than 8 bytes, differing in the 8th byte
111    #[test]
112    fn test_distance_long_different() {
113        let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
114        let b = [1, 2, 3, 4, 5, 6, 7, 9, 10];
115        let expected = 1u64; // 8 ^ 9 = 1 in the 8th byte
116        assert_eq!(
117            distance(a, b),
118            expected,
119            "Distance should reflect difference in the 8th byte"
120        );
121    }
122
123    /// Test both inputs empty
124    #[test]
125    fn test_distance_empty() {
126        let a: &[u8] = &[];
127        let b: &[u8] = &[];
128        assert_eq!(distance(a, b), 0, "Empty inputs should have distance 0");
129    }
130
131    /// Test one empty input, one non-empty
132    #[test]
133    fn test_distance_one_empty() {
134        let a: &[u8] = &[];
135        let b = [1, 2, 3];
136        let expected = u64::from_be_bytes([1, 2, 3, 0, 0, 0, 0, 0]);
137        assert_eq!(
138            distance(a, b),
139            expected,
140            "Distance should handle one empty input correctly"
141        );
142    }
143
144    /// Test maximum possible distance with 8-byte inputs
145    #[test]
146    fn test_distance_max_xor() {
147        let a = [255u8; 8];
148        let b = [0u8; 8];
149        let expected = u64::MAX;
150        assert_eq!(
151            distance(a, b),
152            expected,
153            "Distance should be u64::MAX when all bytes differ maximally"
154        );
155    }
156
157    /// Test inputs as vectors
158    #[test]
159    fn test_distance_with_vectors() {
160        let a = vec![1, 2, 3];
161        let b = vec![1, 2, 4];
162        let expected = 7u64 << 40;
163        assert_eq!(
164            distance(&a, &b),
165            expected,
166            "Distance should work with Vec<u8> inputs"
167        );
168    }
169
170    /// Test inputs as strings
171    #[test]
172    fn test_distance_with_strings() {
173        let a = "hello"; // [104, 101, 108, 108, 111]
174        let b = "world"; // [119, 111, 114, 108, 100]
175        let a_bytes = a.as_bytes();
176        let b_bytes = b.as_bytes();
177        let mut a_array = [0u8; 8];
178        let mut b_array = [0u8; 8];
179        let len_a = a_bytes.len().min(8);
180        let len_b = b_bytes.len().min(8);
181        a_array[..len_a].copy_from_slice(&a_bytes[..len_a]);
182        b_array[..len_b].copy_from_slice(&b_bytes[..len_b]);
183        let a_u64 = u64::from_be_bytes(a_array);
184        let b_u64 = u64::from_be_bytes(b_array);
185        let expected = a_u64 ^ b_u64; // XOR of [104,101,108,108,111,0,0,0] and [119,111,114,108,100,0,0,0]
186        assert_eq!(
187            distance(a, b),
188            expected,
189            "Distance should work with string inputs"
190        );
191    }
192}