journal_core/file/
object_hash.rs1use super::object::*;
2use crate::error::Result;
3use std::num::NonZeroU64;
4use zerocopy::{ByteSlice, ByteSliceMut, Ref, SplitByteSlice, SplitByteSliceMut};
5
6pub trait HashableObject {
7 fn hash(&self) -> u64;
9
10 fn raw_payload(&self) -> &[u8];
12
13 fn is_compressed(&self) -> bool;
15
16 fn decompress(&self, buf: &mut Vec<u8>) -> Result<usize>;
19
20 fn next_hash_offset(&self) -> Option<NonZeroU64>;
22
23 fn object_type() -> ObjectType;
25}
26
27pub trait HashableObjectMut: HashableObject {
28 fn set_next_hash_offset(&mut self, offset: NonZeroU64);
30
31 fn set_payload(&mut self, data: &[u8]);
33}
34
35pub trait HashTable {
37 type Object: HashableObject;
39
40 fn hash_item_ref(&self, hash: u64) -> &HashItem;
42
43 fn len(&self) -> usize;
45
46 fn is_empty(&self) -> bool {
48 self.len() == 0
49 }
50}
51
52pub trait HashTableMut: HashTable {
54 fn hash_item_mut(&mut self, hash: u64) -> &mut HashItem;
56}
57
58pub struct DataHashTable<B: ByteSlice> {
59 pub header: Ref<B, ObjectHeader>,
60 pub items: Ref<B, [HashItem]>,
61}
62
63pub struct FieldHashTable<B: ByteSlice> {
64 pub header: Ref<B, ObjectHeader>,
65 pub items: Ref<B, [HashItem]>,
66}
67
68impl<B: ByteSlice> HashTable for DataHashTable<B> {
70 type Object = DataObject<B>;
71
72 fn hash_item_ref(&self, hash: u64) -> &HashItem {
73 let bucket_index = hash as usize % self.items.len();
74 &self.items[bucket_index]
75 }
76
77 fn len(&self) -> usize {
78 self.items.len()
79 }
80}
81
82impl<B: ByteSlice> HashTable for FieldHashTable<B> {
84 type Object = FieldObject<B>;
85
86 fn hash_item_ref(&self, hash: u64) -> &HashItem {
87 let bucket_index = hash as usize % self.items.len();
88 &self.items[bucket_index]
89 }
90
91 fn len(&self) -> usize {
92 self.items.len()
93 }
94}
95
96impl<B: ByteSliceMut> HashTableMut for DataHashTable<B> {
98 fn hash_item_mut(&mut self, hash: u64) -> &mut HashItem {
99 let bucket_index = hash as usize % self.items.len();
100 &mut self.items[bucket_index]
101 }
102}
103
104impl<B: ByteSliceMut> HashTableMut for FieldHashTable<B> {
106 fn hash_item_mut(&mut self, hash: u64) -> &mut HashItem {
107 let bucket_index = hash as usize % self.items.len();
108 &mut self.items[bucket_index]
109 }
110}
111
112impl<B: SplitByteSlice> JournalObject<B> for DataHashTable<B> {
114 fn from_data(data: B, _is_compact: bool) -> Option<Self> {
115 let (header_data, items_data) = data.split_at(std::mem::size_of::<ObjectHeader>()).ok()?;
116
117 let header = zerocopy::Ref::from_bytes(header_data).ok()?;
118 let items = zerocopy::Ref::from_bytes(items_data).ok()?;
119
120 Some(DataHashTable { header, items })
121 }
122}
123
124impl<B: SplitByteSliceMut> JournalObjectMut<B> for DataHashTable<B> {
126 fn from_data_mut(data: B, _is_compact: bool) -> Option<Self> {
127 let (header_data, items_data) = data.split_at(std::mem::size_of::<ObjectHeader>()).ok()?;
128
129 let header = zerocopy::Ref::from_bytes(header_data).ok()?;
130 let items = zerocopy::Ref::from_bytes(items_data).ok()?;
131
132 Some(DataHashTable { header, items })
133 }
134}
135
136impl<B: SplitByteSlice> JournalObject<B> for FieldHashTable<B> {
138 fn from_data(data: B, _is_compact: bool) -> Option<Self> {
139 let (header_data, items_data) = data.split_at(std::mem::size_of::<ObjectHeader>()).ok()?;
140
141 let header = zerocopy::Ref::from_bytes(header_data).ok()?;
142 let items = zerocopy::Ref::from_bytes(items_data).ok()?;
143
144 Some(FieldHashTable { header, items })
145 }
146}
147
148impl<B: SplitByteSliceMut> JournalObjectMut<B> for FieldHashTable<B> {
150 fn from_data_mut(data: B, _is_compact: bool) -> Option<Self> {
151 let (header_data, items_data) = data.split_at(std::mem::size_of::<ObjectHeader>()).ok()?;
152
153 let header = zerocopy::Ref::from_bytes(header_data).ok()?;
154 let items = zerocopy::Ref::from_bytes(items_data).ok()?;
155
156 Some(FieldHashTable { header, items })
157 }
158}
159
160impl<B: ByteSlice> HashableObject for FieldObject<B> {
161 fn hash(&self) -> u64 {
162 self.header.hash
163 }
164
165 fn raw_payload(&self) -> &[u8] {
166 &self.payload
167 }
168
169 fn is_compressed(&self) -> bool {
170 false
171 }
172
173 fn decompress(&self, buf: &mut Vec<u8>) -> Result<usize> {
174 buf.clear();
175 buf.extend_from_slice(&self.payload);
176 Ok(buf.len())
177 }
178
179 fn next_hash_offset(&self) -> Option<NonZeroU64> {
180 self.header.next_hash_offset
181 }
182
183 fn object_type() -> ObjectType {
184 ObjectType::Field
185 }
186}
187
188impl HashableObjectMut for FieldObject<&mut [u8]> {
189 fn set_next_hash_offset(&mut self, next_hash_offset: NonZeroU64) {
190 self.header.next_hash_offset = Some(next_hash_offset);
191 }
192
193 fn set_payload(&mut self, data: &[u8]) {
194 self.payload.copy_from_slice(data);
195 }
196}
197
198impl<B: ByteSlice> HashableObject for DataObject<B> {
199 fn hash(&self) -> u64 {
200 self.header.hash
201 }
202
203 fn raw_payload(&self) -> &[u8] {
204 self.raw_payload()
205 }
206
207 fn is_compressed(&self) -> bool {
208 DataObject::is_compressed(self)
209 }
210
211 fn decompress(&self, buf: &mut Vec<u8>) -> Result<usize> {
212 DataObject::decompress(self, buf)
213 }
214
215 fn next_hash_offset(&self) -> Option<NonZeroU64> {
216 self.header.next_hash_offset
217 }
218
219 fn object_type() -> ObjectType {
220 ObjectType::Data
221 }
222}
223
224impl HashableObjectMut for DataObject<&mut [u8]> {
225 fn set_next_hash_offset(&mut self, next_hash_offset: NonZeroU64) {
226 self.header.next_hash_offset = Some(next_hash_offset);
227 }
228
229 fn set_payload(&mut self, data: &[u8]) {
230 match &mut self.payload {
231 DataPayloadType::Regular(payload) => {
232 payload.copy_from_slice(data);
233 }
234 DataPayloadType::Compact { payload, .. } => {
235 payload.copy_from_slice(data);
236 }
237 };
238 }
239}