use super::*;
pub trait LogReader: Log {
unsafe fn read(&self, id: &Self::Id, offset: u32, len: u32) -> Result<&[u8], Error>
where
Self::Id: Eq,
{
if self.id().ne(id) {
return Err(Error::IdMismatch);
}
if len == 0 {
return Ok(&[]);
}
let offset = offset as usize;
let len = len as usize;
let allocator = self.allocator();
let allocated = allocator.allocated();
let data_offset = allocator.data_offset();
let opts = self.options();
if offset < data_offset {
return Err(Error::out_of_bounds(
offset as u32,
(len + CHECKSUM_LEN) as u32,
data_offset as u32,
allocated as u32,
));
}
if (offset + len + CHECKSUM_LEN) > allocated {
return Err(Error::out_of_bounds(
offset as u32,
(len + CHECKSUM_LEN) as u32,
data_offset as u32,
allocated as u32,
));
}
let buf = unsafe { allocator.get_bytes(offset, len + CHECKSUM_LEN) };
if opts.validate_checksum {
let checksum = u64::from_le_bytes((&buf[len..len + CHECKSUM_LEN]).try_into().unwrap());
let digest = self.checksum(&buf[..len]);
if checksum != digest {
return Err(Error::checksum_mismatch());
}
}
Ok(&buf[..len])
}
}
pub trait LogReaderExt: LogReader {
unsafe fn read_generic<T: Type>(
&self,
id: &Self::Id,
offset: u32,
len: u32,
) -> Result<T::Ref<'_>, Error>
where
Self::Id: Eq,
{
self
.read(id, offset, len)
.map(|buf| <T::Ref<'_> as TypeRef>::from_slice(buf))
}
}
impl<L: LogReader> LogReaderExt for L {}
pub trait GenericLogReader: Log {
type Type;
unsafe fn read(
&self,
id: &Self::Id,
offset: u32,
len: u32,
) -> Result<<Self::Type as Type>::Ref<'_>, Error>
where
Self::Type: Type,
Self::Id: Eq;
}
impl<L> GenericLogReader for L
where
L: common::AsLog,
L::Log: LogReader,
{
type Type = L::Type;
unsafe fn read(
&self,
id: &<L::Log as Log>::Id,
offset: u32,
len: u32,
) -> Result<<Self::Type as Type>::Ref<'_>, Error>
where
Self::Type: Type,
Self::Id: Eq,
{
self.as_log().read_generic::<Self::Type>(id, offset, len)
}
}