ps_datachunk/serialized/
mod.rs

1use std::{ops::Deref, sync::Arc};
2
3use bytes::Bytes;
4use ps_buffer::{Buffer, SharedBuffer};
5use ps_hash::{hash, Hash};
6
7use crate::{utils::HASH_SIZE, DataChunk, EncryptedDataChunk, PsDataChunkError, Result};
8
9#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
10pub struct SerializedDataChunk {
11    buffer: Buffer,
12    hash: Arc<Hash>,
13}
14
15impl SerializedDataChunk {
16    #[must_use]
17    pub const fn data_length(&self) -> usize {
18        self.buffer.len().saturating_sub(HASH_SIZE)
19    }
20
21    #[must_use]
22    pub const fn is_empty(&self) -> bool {
23        self.buffer.len() <= HASH_SIZE
24    }
25
26    /// # Safety
27    ///
28    /// Called guarantees that `hash` is `hash(data)`
29    ///
30    /// This method does **NOT** verify `hash`!
31    ///
32    /// Call only if `hash` is surely known.
33    pub fn from_parts<D>(data: D, hash: Arc<Hash>) -> Result<Self>
34    where
35        D: AsRef<[u8]>,
36    {
37        let data = data.as_ref();
38        let buffer_length = HASH_SIZE + data.len();
39
40        let mut buffer = Buffer::with_capacity(buffer_length)?;
41
42        buffer.extend_from_slice(hash.as_bytes())?;
43        buffer.extend_from_slice(data)?;
44
45        let chunk = Self { buffer, hash };
46
47        Ok(chunk)
48    }
49
50    /// # Safety
51    ///
52    /// Called guarantees that `hash` is `hash(data)`
53    ///
54    /// This method does **NOT** verify `hash`!
55    ///
56    /// This method only verifies the internal checksum of `hash`, and will return `Err(PsDataChunkError::InvalidChecksum)` if this is invalid.
57    pub fn try_from_parts<D, H>(data: D, hash: H) -> Result<Self>
58    where
59        D: AsRef<[u8]>,
60        H: AsRef<[u8]>,
61    {
62        let data = data.as_ref();
63        let hash = hash.as_ref();
64
65        let hash = Hash::try_from(hash)?.into();
66
67        Self::from_parts(data, hash)
68    }
69
70    /// Allocate a `SerializedDataChunk` containing `data`
71    pub fn from_data<D>(data: D) -> Result<Self>
72    where
73        D: AsRef<[u8]>,
74    {
75        let data = data.as_ref();
76
77        Self::from_parts(data, hash(data)?.into())
78    }
79
80    /// Returns a reference to this [`SerializedDataChunk`]'s serialized bytes
81    #[inline]
82    #[must_use]
83    pub fn serialized_bytes(&self) -> &[u8] {
84        &self.buffer
85    }
86
87    /// Constructs a `SerializedDataChunk` from a serialized buffer.
88    ///
89    /// `buffer` is validated to be interpretable as a `SerializedDataChunk`,
90    /// and its `hash` is recalculated and verified. However, other things,
91    /// such as padding and buffer length, are not validated.
92    pub fn from_serialized_buffer(buffer: Buffer) -> Result<Self> {
93        if buffer.len() < HASH_SIZE {
94            return Err(PsDataChunkError::InvalidDataChunk);
95        }
96
97        let hash = &buffer[..HASH_SIZE];
98        let data = &buffer[HASH_SIZE..];
99        let calculated_hash = ps_hash::hash(data)?;
100
101        if hash != calculated_hash.as_bytes() {
102            return Err(PsDataChunkError::InvalidHash);
103        }
104
105        let chunk = Self {
106            buffer,
107            hash: Arc::from(calculated_hash),
108        };
109
110        Ok(chunk)
111    }
112
113    #[inline]
114    /// extracts the serialized `Buffer` from this `SerializedDataChunk`
115    pub fn into_buffer(self) -> Buffer {
116        self.buffer
117    }
118
119    #[inline]
120    /// extracts the serialized `Buffer` and `Hash` from this `SerializedDataChunk`
121    pub fn into_parts(self) -> (Buffer, Arc<Hash>) {
122        (self.buffer, self.hash)
123    }
124}
125
126impl DataChunk for SerializedDataChunk {
127    fn data_ref(&self) -> &[u8] {
128        &self.buffer[HASH_SIZE..]
129    }
130
131    fn encrypt(&self) -> Result<EncryptedDataChunk> {
132        Ok(ps_cypher::encrypt(&self.buffer)?.into())
133    }
134
135    fn hash_ref(&self) -> &Hash {
136        &self.hash
137    }
138
139    fn hash(&self) -> Arc<Hash> {
140        self.hash.clone()
141    }
142
143    /// Transforms this [`DataChunk`] into [`Bytes`].
144    fn into_bytes(self) -> Bytes {
145        Bytes::from_owner(SharedBuffer::from(self.buffer)).slice(HASH_SIZE..)
146    }
147
148    /// Transforms this chunk into an [`OwnedDataChunk`]
149    fn into_owned(self) -> crate::OwnedDataChunk {
150        let hash = self.hash();
151
152        crate::OwnedDataChunk::from_data_and_hash(self, hash)
153    }
154}
155
156impl AsRef<[u8]> for SerializedDataChunk {
157    fn as_ref(&self) -> &[u8] {
158        self
159    }
160}
161
162impl Deref for SerializedDataChunk {
163    type Target = [u8];
164
165    fn deref(&self) -> &Self::Target {
166        self.data_ref()
167    }
168}