use std::ops::Deref;
use bytes::Bytes;
use ps_buffer::{Buffer, SharedBuffer};
use ps_hash::{hash, Hash, HASH_SIZE};
use crate::{DataChunk, EncryptedDataChunk, PsDataChunkError, Result};
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct SerializedDataChunk {
buffer: Buffer,
hash: Hash,
}
impl SerializedDataChunk {
#[must_use]
pub const fn data_length(&self) -> usize {
self.buffer.len().saturating_sub(HASH_SIZE)
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.buffer.len() <= HASH_SIZE
}
pub fn from_parts<D>(data: D, hash: Hash) -> Result<Self>
where
D: AsRef<[u8]>,
{
let data = data.as_ref();
let buffer_length = HASH_SIZE + data.len();
let mut buffer = Buffer::with_capacity(buffer_length)?;
buffer.extend_from_slice(hash.to_string())?;
buffer.extend_from_slice(data)?;
let chunk = Self { buffer, hash };
Ok(chunk)
}
pub fn try_from_parts<D, H>(data: D, hash: H) -> Result<Self>
where
D: AsRef<[u8]>,
H: AsRef<[u8]>,
{
let data = data.as_ref();
let hash = hash.as_ref();
let hash = Hash::try_from(hash)?;
Self::from_parts(data, hash)
}
pub fn from_data<D>(data: D) -> Result<Self>
where
D: AsRef<[u8]>,
{
let data = data.as_ref();
Self::from_parts(data, hash(data)?)
}
#[inline]
#[must_use]
pub fn serialized_bytes(&self) -> &[u8] {
&self.buffer
}
pub fn from_serialized_buffer(buffer: Buffer) -> Result<Self> {
if buffer.len() < HASH_SIZE {
return Err(PsDataChunkError::InvalidDataChunk);
}
let hash = &buffer[..HASH_SIZE];
let data = &buffer[HASH_SIZE..];
let calculated_hash = ps_hash::hash(data)?;
if hash != calculated_hash.to_string().as_bytes() {
return Err(PsDataChunkError::InvalidHash);
}
let chunk = Self {
buffer,
hash: calculated_hash,
};
Ok(chunk)
}
#[inline]
pub fn into_buffer(self) -> Buffer {
self.buffer
}
#[inline]
pub fn into_parts(self) -> (Buffer, Hash) {
(self.buffer, self.hash)
}
}
impl DataChunk for SerializedDataChunk {
fn data_ref(&self) -> &[u8] {
&self.buffer[HASH_SIZE..]
}
fn encrypt(&self) -> Result<EncryptedDataChunk> {
Ok(ps_cypher::encrypt(&self.buffer)?.into())
}
fn hash_ref(&self) -> &Hash {
&self.hash
}
fn hash(&self) -> Hash {
self.hash
}
fn into_bytes(self) -> Bytes {
Bytes::from_owner(SharedBuffer::from(self.buffer)).slice(HASH_SIZE..)
}
fn into_owned(self) -> crate::OwnedDataChunk {
let hash = self.hash();
crate::OwnedDataChunk::from_data_and_hash(self, hash)
}
}
impl AsRef<[u8]> for SerializedDataChunk {
fn as_ref(&self) -> &[u8] {
self
}
}
impl Deref for SerializedDataChunk {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.data_ref()
}
}