1use std::marker::PhantomData;
2
3use digest::ExtendableOutput;
4
5use crate::{
6 utils::{into_bytes, read_u16, HexDisplayRef16},
7 LtHash,
8};
9
10#[derive(Clone, Copy)]
12pub struct LtHash16<H> {
13 pub(crate) checksum: [u16; 1024],
14 hasher: PhantomData<H>,
15}
16
17static_assertions::assert_impl_all!(LtHash16<()>: Send, Sync, Unpin);
19
20impl<H> LtHash16<H> {
21 pub(crate) const fn name(&self) -> &'static str {
22 "LtHash16"
23 }
24}
25
26impl<H> LtHash16<H>
27where
28 H: ExtendableOutput + Default,
29{
30 #[inline(always)]
31 pub fn new() -> Self {
32 Self::default()
33 }
34
35 fn hash_object(&mut self, object: impl AsRef<[u8]>) -> [u8; 2048] {
36 let mut output = [0u8; 2048];
37 H::digest_xof(object, output.as_mut());
38 output
39 }
40
41 #[inline(always)]
42 fn display_hex_ref(&self) -> HexDisplayRef16<'_> {
43 HexDisplayRef16(&self.checksum[..])
44 }
45}
46
47impl<H> Default for LtHash16<H>
48where
49 H: ExtendableOutput + Default,
50{
51 #[inline(always)]
52 fn default() -> Self {
53 Self {
54 checksum: [0; 1024],
55 hasher: Default::default(),
56 }
57 }
58}
59
60impl<H> LtHash for LtHash16<H>
61where
62 H: ExtendableOutput + Default,
63{
64 fn insert(&mut self, element: impl AsRef<[u8]>) {
66 let hashed = self.hash_object(element);
67 let mut i = 0;
68 while i < 2048 {
69 let xi = &self.checksum[i / 2];
70 let yi = &hashed[i..i + 2];
71 let yi = read_u16(yi);
72 let sum = xi.wrapping_add(yi);
73 self.checksum[i / 2] = sum;
74 i += 2;
75 }
76 }
77
78 fn remove(&mut self, element: impl AsRef<[u8]>) {
80 let hashed = self.hash_object(element);
81 let mut i = 0;
82 while i < 2048 {
83 let xi = &self.checksum[i / 2];
84 let yi = &hashed[i..i + 2];
85 let yi = read_u16(yi);
86 let diff = xi.wrapping_sub(yi);
87 self.checksum[i / 2] = diff;
88 i += 2;
89 }
90 }
91
92 fn to_hex_string(&self) -> String {
94 self.display_hex_ref().to_string()
95 }
96
97 fn union(&self, rhs: &Self) -> Self {
118 let mut checksum = [0; 1024];
119
120 for (checksum, (&lhs, &rhs)) in checksum
121 .iter_mut()
122 .zip(self.checksum.iter().zip(rhs.checksum.iter()))
123 {
124 *checksum = lhs.wrapping_add(rhs);
125 }
126
127 Self {
128 checksum,
129 hasher: PhantomData,
130 }
131 }
132
133 fn difference(&self, rhs: &Self) -> Self {
154 let mut checksum = [0; 1024];
155
156 for (checksum, (&lhs, &rhs)) in checksum
157 .iter_mut()
158 .zip(self.checksum.iter().zip(rhs.checksum.iter()))
159 {
160 *checksum = lhs.wrapping_sub(rhs);
161 }
162
163 Self {
164 checksum,
165 hasher: PhantomData,
166 }
167 }
168
169 fn reset(&mut self) {
171 self.checksum.fill(0);
172 }
173
174 fn into_bytes(self) -> Vec<u8> {
176 into_bytes(self.checksum)
177 }
178}
179
180impl<H> TryFrom<&[u8]> for LtHash16<H> {
181 type Error = String;
182
183 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
184 if bytes.len() != 2048 {
185 return Err(String::from("Wrong number of bytes."));
186 }
187
188 let mut checksum = [0; 1024];
189
190 for (checksum, bytes) in checksum.iter_mut().zip(bytes.chunks_exact(2))
191 {
192 *checksum =
193 u16::from_le_bytes(bytes.try_into().map_err(|_| {
194 String::from("Error converting bytes to u16.")
195 })?);
196 }
197
198 Ok(Self {
199 checksum,
200 hasher: PhantomData,
201 })
202 }
203}