oxihuman_core/
digest_hash.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub struct DigestHash {
9 value: u64,
10}
11
12#[allow(dead_code)]
13impl DigestHash {
14 pub const SEED: u64 = 0xcbf2_9ce4_8422_2325;
15
16 pub fn new() -> Self {
17 Self { value: Self::SEED }
18 }
19
20 pub fn from_bytes(data: &[u8]) -> Self {
21 let mut h = Self::new();
22 h.update(data);
23 h
24 }
25
26 pub fn from_text(s: &str) -> Self {
27 Self::from_bytes(s.as_bytes())
28 }
29
30 pub fn update(&mut self, data: &[u8]) {
31 for &b in data {
32 self.value ^= b as u64;
33 self.value = self.value.wrapping_mul(0x0100_0000_01b3);
34 }
35 }
36
37 pub fn update_u32(&mut self, val: u32) {
38 self.update(&val.to_le_bytes());
39 }
40
41 pub fn update_f32(&mut self, val: f32) {
42 self.update(&val.to_le_bytes());
43 }
44
45 pub fn finish(&self) -> u64 {
46 self.value
47 }
48
49 pub fn finish_u32(&self) -> u32 {
50 (self.value ^ (self.value >> 32)) as u32
51 }
52
53 pub fn combine(&self, other: &DigestHash) -> DigestHash {
54 DigestHash {
55 value: self.value ^ other.value.wrapping_mul(0x9e37_79b9_7f4a_7c15),
56 }
57 }
58
59 pub fn is_zero(&self) -> bool {
60 self.value == 0
61 }
62
63 pub fn to_hex(&self) -> String {
64 format!("{:016x}", self.value)
65 }
66}
67
68impl Default for DigestHash {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_new() {
80 let h = DigestHash::new();
81 assert_eq!(h.finish(), DigestHash::SEED);
82 }
83
84 #[test]
85 fn test_from_bytes() {
86 let h = DigestHash::from_bytes(b"hello");
87 assert_ne!(h.finish(), DigestHash::SEED);
88 }
89
90 #[test]
91 fn test_deterministic() {
92 let a = DigestHash::from_text("test");
93 let b = DigestHash::from_text("test");
94 assert_eq!(a, b);
95 }
96
97 #[test]
98 fn test_different_inputs() {
99 let a = DigestHash::from_text("alpha");
100 let b = DigestHash::from_text("beta");
101 assert_ne!(a, b);
102 }
103
104 #[test]
105 fn test_update_u32() {
106 let mut h = DigestHash::new();
107 h.update_u32(42);
108 assert_ne!(h.finish(), DigestHash::SEED);
109 }
110
111 #[test]
112 fn test_update_f32() {
113 let mut h = DigestHash::new();
114 h.update_f32(1.5);
115 assert_ne!(h.finish(), DigestHash::SEED);
116 }
117
118 #[test]
119 fn test_finish_u32() {
120 let h = DigestHash::from_text("data");
121 let _v = h.finish_u32();
122 }
124
125 #[test]
126 fn test_combine() {
127 let a = DigestHash::from_text("a");
128 let b = DigestHash::from_text("b");
129 let c = a.combine(&b);
130 assert_ne!(c, a);
131 assert_ne!(c, b);
132 }
133
134 #[test]
135 fn test_to_hex() {
136 let h = DigestHash::new();
137 let hex = h.to_hex();
138 assert_eq!(hex.len(), 16);
139 }
140
141 #[test]
142 fn test_default() {
143 let h = DigestHash::default();
144 assert_eq!(h.finish(), DigestHash::SEED);
145 }
146}