1use std::ops::Deref;
2
3use ps_hash::hash;
4use rancor::{Error, Strategy};
5use rkyv::{
6 api::high::HighSerializer,
7 bytecheck::CheckBytes,
8 ser::allocator::ArenaHandle,
9 util::AlignedVec,
10 validation::{archive::ArchiveValidator, shared::SharedValidator, Validator},
11 Archive, Serialize,
12};
13
14use crate::*;
15
16#[derive(Debug, Clone)]
17pub struct AlignedDataChunk {
18 data: AlignedVec,
19 hash: Arc<Hash>,
20}
21
22impl AlignedDataChunk {
23 pub fn from_parts<D, H>(data: D, hash: H) -> Self
24 where
25 D: Into<AlignedVec>,
26 H: Into<Arc<Hash>>,
27 {
28 let data = data.into();
29 let hash = hash.into();
30
31 Self { data, hash }
32 }
33
34 pub fn from_data_vec(data: AlignedVec) -> Self {
35 let hash = hash(&data);
36
37 Self::from_parts(data, hash)
38 }
39
40 pub fn is_empty(&self) -> bool {
41 self.data.is_empty()
42 }
43
44 pub fn len(&self) -> usize {
45 self.data.len()
46 }
47}
48
49impl AsRef<[u8]> for AlignedDataChunk {
50 fn as_ref(&self) -> &[u8] {
51 self
52 }
53}
54
55impl Deref for AlignedDataChunk {
56 type Target = [u8];
57
58 fn deref(&self) -> &Self::Target {
59 &self.data
60 }
61}
62
63impl AlignedDataChunk {
64 pub fn try_from<T>(value: &T) -> Result<Self>
65 where
66 for<'a> T: Archive + Serialize<HighSerializer<AlignedVec, ArenaHandle<'a>, Error>>,
67 {
68 let data = rkyv::to_bytes::<Error>(value)?;
69 let chunk = Self::from_data_vec(data);
70
71 Ok(chunk)
72 }
73
74 pub fn try_bytes_as<T: rkyv::Archive>(data: &[u8]) -> Result<&T::Archived>
75 where
76 for<'a> <T as rkyv::Archive>::Archived:
77 CheckBytes<Strategy<Validator<ArchiveValidator<'a>, SharedValidator>, rancor::Error>>,
78 {
79 Ok(rkyv::access::<T::Archived, Error>(data)?)
80 }
81
82 pub fn try_as<T: rkyv::Archive>(&self) -> Result<&T::Archived>
83 where
84 for<'a> <T as Archive>::Archived:
85 CheckBytes<Strategy<Validator<ArchiveValidator<'a>, SharedValidator>, rancor::Error>>,
86 {
87 Self::try_bytes_as::<T>(self.data_ref())
88 }
89}
90
91impl DataChunkTrait for AlignedDataChunk {
92 fn data_ref(&self) -> &[u8] {
93 self
94 }
95 fn hash_ref(&self) -> &[u8] {
96 self.hash.as_bytes()
97 }
98 fn hash(&self) -> Arc<Hash> {
99 self.hash.clone()
100 }
101}
102
103impl<'lt> DataChunk<'lt> {
104 pub fn try_from<T>(value: &T) -> Result<Self>
105 where
106 T: Archive + for<'a> Serialize<HighSerializer<AlignedVec, ArenaHandle<'a>, Error>>,
107 {
108 Ok(Self::Aligned(AlignedDataChunk::try_from(value)?))
109 }
110
111 pub fn try_as<T: rkyv::Archive>(&'lt self) -> Result<&'lt T::Archived>
112 where
113 for<'a> <T as Archive>::Archived:
114 CheckBytes<Strategy<Validator<ArchiveValidator<'a>, SharedValidator>, rancor::Error>>,
115 {
116 AlignedDataChunk::try_bytes_as::<T>(self.data_ref())
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use utils::offsets;
123
124 use super::*;
125
126 #[test]
127 fn test_chunk_length_divisibility_and_part_alignment() -> Result<()> {
128 for i in 12..256 {
129 let data = (vec![i as u8; i], ());
130 let chunk = AlignedDataChunk::try_from::<_>(&data)?;
131
132 assert_eq!(chunk.serialize()?.serialized_bytes().len() % 16, 0);
133
134 let (hash_offset, size_offset, size) = offsets(i);
135
136 assert_eq!(hash_offset % 16, 0);
137 assert_eq!(size_offset % 8, 0);
138 assert_eq!(size % 16, 0);
139 }
140
141 Ok(())
142 }
143}