1use crate::{blake3, BaoTree, BlockSize, TreeNode};
7use std::io;
8
9#[derive(Debug)]
13pub struct EmptyOutboard {
14 pub tree: BaoTree,
16 pub root: blake3::Hash,
18}
19
20impl crate::io::sync::Outboard for EmptyOutboard {
21 fn root(&self) -> blake3::Hash {
22 self.root
23 }
24 fn tree(&self) -> BaoTree {
25 self.tree
26 }
27 fn load(&self, node: TreeNode) -> io::Result<Option<(blake3::Hash, blake3::Hash)>> {
28 Ok(if self.tree.is_relevant_for_outboard(node) {
29 Some((blake3::Hash::from([0; 32]), blake3::Hash::from([0; 32])))
31 } else {
32 None
33 })
34 }
35}
36
37#[cfg(feature = "tokio_fsm")]
38impl crate::io::fsm::Outboard for EmptyOutboard {
39 fn root(&self) -> blake3::Hash {
40 self.root
41 }
42 fn tree(&self) -> BaoTree {
43 self.tree
44 }
45 async fn load(&mut self, node: TreeNode) -> io::Result<Option<(blake3::Hash, blake3::Hash)>> {
46 Ok(if self.tree.is_relevant_for_outboard(node) {
47 Some((blake3::Hash::from([0; 32]), blake3::Hash::from([0; 32])))
49 } else {
50 None
51 })
52 }
53}
54
55impl crate::io::sync::OutboardMut for EmptyOutboard {
56 fn save(&mut self, node: TreeNode, _pair: &(blake3::Hash, blake3::Hash)) -> io::Result<()> {
57 if self.tree.is_relevant_for_outboard(node) {
58 Ok(())
59 } else {
60 Err(io::Error::new(
61 io::ErrorKind::InvalidInput,
62 "invalid node for this outboard",
63 ))
64 }
65 }
66
67 fn sync(&mut self) -> io::Result<()> {
68 Ok(())
69 }
70}
71
72#[cfg(feature = "tokio_fsm")]
73impl crate::io::fsm::OutboardMut for EmptyOutboard {
74 async fn save(
75 &mut self,
76 node: TreeNode,
77 _pair: &(blake3::Hash, blake3::Hash),
78 ) -> io::Result<()> {
79 if self.tree.is_relevant_for_outboard(node) {
80 Ok(())
81 } else {
82 Err(io::Error::new(
83 io::ErrorKind::InvalidInput,
84 "invalid node for this outboard",
85 ))
86 }
87 }
88
89 async fn sync(&mut self) -> io::Result<()> {
90 Ok(())
91 }
92}
93
94#[derive(Debug, Clone)]
103pub struct PreOrderOutboard<D = Vec<u8>> {
104 pub root: blake3::Hash,
106 pub tree: BaoTree,
108 pub data: D,
110}
111
112impl<R: Default> Default for PreOrderOutboard<R> {
113 fn default() -> Self {
114 Self {
115 root: blake3::hash(&[]),
116 tree: BaoTree::new(0, BlockSize::ZERO),
117 data: Default::default(),
118 }
119 }
120}
121
122#[derive(Debug, Clone)]
128pub struct PostOrderOutboard<D = Vec<u8>> {
129 pub root: blake3::Hash,
131 pub tree: BaoTree,
133 pub data: D,
135}
136
137impl<D: Default> Default for PostOrderOutboard<D> {
138 fn default() -> Self {
139 Self {
140 root: blake3::hash(&[]),
141 tree: BaoTree::new(0, BlockSize::ZERO),
142 data: Default::default(),
143 }
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Eq)]
157pub struct PostOrderMemOutboard<T = Vec<u8>> {
158 pub root: blake3::Hash,
160 pub tree: BaoTree,
162 pub data: T,
164}
165
166impl<T: Default> Default for PostOrderMemOutboard<T> {
167 fn default() -> Self {
168 Self {
169 root: blake3::hash(&[]),
170 tree: BaoTree::new(0, BlockSize::ZERO),
171 data: Default::default(),
172 }
173 }
174}
175
176impl PostOrderMemOutboard {
177 pub fn create(data: impl AsRef<[u8]>, block_size: BlockSize) -> Self {
183 let data = data.as_ref();
184 let size = data.len() as u64;
185 let tree = BaoTree::new(size, block_size);
186 let mut outboard = Vec::with_capacity(tree.outboard_size().try_into().unwrap());
187 let root = crate::io::sync::outboard_post_order(data, tree, &mut outboard).unwrap();
188 Self {
189 root,
190 tree,
191 data: outboard,
192 }
193 }
194
195 pub fn into_inner_with_suffix(self) -> Vec<u8> {
197 let mut res = self.data;
198 res.extend_from_slice(self.tree.size.to_le_bytes().as_slice());
199 res
200 }
201}
202
203impl<T> PostOrderMemOutboard<T> {
204 pub fn map_data<F, U>(self, f: F) -> PostOrderMemOutboard<U>
206 where
207 F: FnOnce(T) -> U,
208 U: AsRef<[u8]>,
209 {
210 PostOrderMemOutboard {
211 root: self.root,
212 tree: self.tree,
213 data: f(self.data),
214 }
215 }
216
217 pub fn flip(&self) -> PreOrderMemOutboard
219 where
220 T: AsRef<[u8]>,
221 {
222 let mut target = PreOrderMemOutboard {
223 root: self.root,
224 tree: self.tree,
225 data: vec![0; self.tree.outboard_size().try_into().unwrap()],
226 };
227 crate::io::sync::copy(self, &mut target).unwrap();
228 target
229 }
230}
231
232impl<T: AsRef<[u8]>> crate::io::sync::Outboard for PostOrderMemOutboard<T> {
233 fn root(&self) -> blake3::Hash {
234 self.root
235 }
236 fn tree(&self) -> BaoTree {
237 self.tree
238 }
239 fn load(&self, node: TreeNode) -> io::Result<Option<(blake3::Hash, blake3::Hash)>> {
240 Ok(load_post(&self.tree, self.data.as_ref(), node))
241 }
242}
243
244#[cfg(feature = "tokio_fsm")]
245impl<T: AsRef<[u8]>> crate::io::fsm::Outboard for PostOrderMemOutboard<T> {
246 fn root(&self) -> blake3::Hash {
247 self.root
248 }
249 fn tree(&self) -> BaoTree {
250 self.tree
251 }
252 async fn load(&mut self, node: TreeNode) -> io::Result<Option<(blake3::Hash, blake3::Hash)>> {
253 Ok(load_post(&self.tree, self.data.as_ref(), node))
254 }
255}
256
257impl<T: AsMut<[u8]>> crate::io::sync::OutboardMut for PostOrderMemOutboard<T> {
258 fn save(&mut self, node: TreeNode, pair: &(blake3::Hash, blake3::Hash)) -> io::Result<()> {
259 match self.tree.post_order_offset(node) {
260 Some(offset) => {
261 let offset = usize::try_from(offset.value() * 64).unwrap();
262 let data = self.data.as_mut();
263 data[offset..offset + 32].copy_from_slice(pair.0.as_bytes());
264 data[offset + 32..offset + 64].copy_from_slice(pair.1.as_bytes());
265 Ok(())
266 }
267 None => Err(io::Error::new(
268 io::ErrorKind::InvalidInput,
269 "invalid node for this outboard",
270 )),
271 }
272 }
273
274 fn sync(&mut self) -> io::Result<()> {
275 Ok(())
276 }
277}
278
279#[cfg(feature = "tokio_fsm")]
280impl<T: AsMut<[u8]>> crate::io::fsm::OutboardMut for PostOrderMemOutboard<T> {
281 async fn save(
282 &mut self,
283 node: TreeNode,
284 pair: &(blake3::Hash, blake3::Hash),
285 ) -> io::Result<()> {
286 match self.tree.post_order_offset(node) {
287 Some(offset) => {
288 let offset = usize::try_from(offset.value() * 64).unwrap();
289 let data = self.data.as_mut();
290 data[offset..offset + 32].copy_from_slice(pair.0.as_bytes());
291 data[offset + 32..offset + 64].copy_from_slice(pair.1.as_bytes());
292 Ok(())
293 }
294 None => Err(io::Error::new(
295 io::ErrorKind::InvalidInput,
296 "invalid node for this outboard",
297 )),
298 }
299 }
300
301 async fn sync(&mut self) -> io::Result<()> {
302 Ok(())
303 }
304}
305
306fn load_raw_post_mem(tree: &BaoTree, data: &[u8], node: TreeNode) -> Option<[u8; 64]> {
307 let offset = tree.post_order_offset(node)?.value();
308 let offset = usize::try_from(offset * 64).unwrap();
309 let slice = &data[offset..offset + 64];
310 Some(slice.try_into().unwrap())
311}
312
313fn load_post(tree: &BaoTree, data: &[u8], node: TreeNode) -> Option<(blake3::Hash, blake3::Hash)> {
314 load_raw_post_mem(tree, data, node).map(parse_hash_pair)
315}
316
317#[derive(Debug, Clone, PartialEq, Eq)]
322pub struct PreOrderMemOutboard<T = Vec<u8>> {
323 pub root: blake3::Hash,
325 pub tree: BaoTree,
327 pub data: T,
329}
330
331impl<T: Default> Default for PreOrderMemOutboard<T> {
332 fn default() -> Self {
333 Self {
334 root: blake3::hash(&[]),
335 tree: BaoTree::new(0, BlockSize::ZERO),
336 data: Default::default(),
337 }
338 }
339}
340
341impl PreOrderMemOutboard {
342 pub fn into_inner_with_prefix(self) -> Vec<u8> {
344 let mut res = self.data;
345 res.splice(0..0, self.tree.size.to_le_bytes());
346 res
347 }
348
349 pub fn create(data: impl AsRef<[u8]>, block_size: BlockSize) -> Self {
353 let data = data.as_ref();
354 let size = data.len() as u64;
355 let tree = BaoTree::new(size, block_size);
356 let outboard = vec![0u8; tree.outboard_size().try_into().unwrap()];
359 let mut res = Self {
360 root: blake3::Hash::from([0; 32]),
361 tree,
362 data: outboard,
363 };
364 let root = crate::io::sync::outboard(data, tree, &mut res).unwrap();
365 res.root = root;
366 res
367 }
368}
369
370impl<T> PreOrderMemOutboard<T> {
371 pub fn map_data<F, U>(self, f: F) -> PreOrderMemOutboard<U>
373 where
374 F: FnOnce(T) -> U,
375 U: AsRef<[u8]>,
376 {
377 PreOrderMemOutboard {
378 root: self.root,
379 tree: self.tree,
380 data: f(self.data),
381 }
382 }
383
384 pub fn flip(&self) -> PostOrderMemOutboard
386 where
387 T: AsRef<[u8]>,
388 {
389 let mut target = PostOrderMemOutboard {
390 root: self.root,
391 tree: self.tree,
392 data: vec![0; self.tree.outboard_size().try_into().unwrap()],
393 };
394 crate::io::sync::copy(self, &mut target).unwrap();
395 target
396 }
397}
398
399impl<T: AsRef<[u8]>> crate::io::sync::Outboard for PreOrderMemOutboard<T> {
400 fn root(&self) -> blake3::Hash {
401 self.root
402 }
403 fn tree(&self) -> BaoTree {
404 self.tree
405 }
406 fn load(&self, node: TreeNode) -> io::Result<Option<(blake3::Hash, blake3::Hash)>> {
407 Ok(load_pre(&self.tree, self.data.as_ref(), node))
408 }
409}
410
411impl<T: AsMut<[u8]>> crate::io::sync::OutboardMut for PreOrderMemOutboard<T> {
412 fn save(&mut self, node: TreeNode, pair: &(blake3::Hash, blake3::Hash)) -> io::Result<()> {
413 match self.tree.pre_order_offset(node) {
414 Some(offset) => {
415 let offset_u64 = offset * 64;
416 let offset = usize::try_from(offset_u64).unwrap();
417 let data = self.data.as_mut();
418 data[offset..offset + 32].copy_from_slice(pair.0.as_bytes());
419 data[offset + 32..offset + 64].copy_from_slice(pair.1.as_bytes());
420 Ok(())
421 }
422 None => Err(io::Error::new(
423 io::ErrorKind::InvalidInput,
424 "invalid node for this outboard",
425 )),
426 }
427 }
428
429 fn sync(&mut self) -> io::Result<()> {
430 Ok(())
431 }
432}
433
434#[cfg(feature = "tokio_fsm")]
435impl<T: AsRef<[u8]>> crate::io::fsm::Outboard for PreOrderMemOutboard<T> {
436 fn root(&self) -> blake3::Hash {
437 self.root
438 }
439 fn tree(&self) -> BaoTree {
440 self.tree
441 }
442 async fn load(&mut self, node: TreeNode) -> io::Result<Option<(blake3::Hash, blake3::Hash)>> {
443 Ok(load_raw_pre_mem(&self.tree, self.data.as_ref(), node).map(parse_hash_pair))
444 }
445}
446
447#[cfg(feature = "tokio_fsm")]
448impl<T: AsMut<[u8]>> crate::io::fsm::OutboardMut for PreOrderMemOutboard<T> {
449 async fn save(
450 &mut self,
451 node: TreeNode,
452 pair: &(blake3::Hash, blake3::Hash),
453 ) -> io::Result<()> {
454 match self.tree.pre_order_offset(node) {
455 Some(offset) => {
456 let offset_u64 = offset * 64;
457 let offset = usize::try_from(offset_u64).unwrap();
458 let data = self.data.as_mut();
459 data[offset..offset + 32].copy_from_slice(pair.0.as_bytes());
460 data[offset + 32..offset + 64].copy_from_slice(pair.1.as_bytes());
461 Ok(())
462 }
463 None => Err(io::Error::new(
464 io::ErrorKind::InvalidInput,
465 "invalid node for this outboard",
466 )),
467 }
468 }
469
470 async fn sync(&mut self) -> io::Result<()> {
471 Ok(())
472 }
473}
474
475fn load_raw_pre_mem(tree: &BaoTree, data: &[u8], node: TreeNode) -> Option<[u8; 64]> {
476 let offset = tree.pre_order_offset(node)?;
481 let offset = usize::try_from(offset * 64).unwrap();
482 let slice = &data[offset..offset + 64];
483 Some(slice.try_into().unwrap())
484}
485
486fn load_pre(tree: &BaoTree, data: &[u8], node: TreeNode) -> Option<(blake3::Hash, blake3::Hash)> {
487 load_raw_pre_mem(tree, data, node).map(parse_hash_pair)
488}
489
490pub(crate) fn parse_hash_pair(buf: [u8; 64]) -> (blake3::Hash, blake3::Hash) {
491 let l_hash = blake3::Hash::from(<[u8; 32]>::try_from(&buf[..32]).unwrap());
492 let r_hash = blake3::Hash::from(<[u8; 32]>::try_from(&buf[32..]).unwrap());
493 (l_hash, r_hash)
494}