use core::fmt::Debug;
pub trait BlockRead {
type Error: Debug;
fn read_at(&mut self, offset_bytes: u64, buf: &mut [u8]) -> Result<(), Self::Error>;
}
impl BlockRead for &[u8] {
type Error = SliceReadError;
fn read_at(&mut self, offset_bytes: u64, buf: &mut [u8]) -> Result<(), Self::Error> {
let start: usize = offset_bytes
.try_into()
.map_err(|_| SliceReadError::OffsetTooLarge)?;
let end = start
.checked_add(buf.len())
.ok_or(SliceReadError::Overflow)?;
if end > self.len() {
return Err(SliceReadError::OutOfBounds);
}
buf.copy_from_slice(&self[start..end]);
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SliceReadError {
OffsetTooLarge,
Overflow,
OutOfBounds,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slice_adapter_reads_in_bounds() {
let data: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8];
let mut reader: &[u8] = data;
let mut buf = [0u8; 4];
reader.read_at(2, &mut buf).unwrap();
assert_eq!(&buf, &[3, 4, 5, 6]);
}
#[test]
fn slice_adapter_rejects_out_of_bounds() {
let data: &[u8] = &[1, 2, 3];
let mut reader: &[u8] = data;
let mut buf = [0u8; 4];
assert_eq!(
reader.read_at(0, &mut buf),
Err(SliceReadError::OutOfBounds)
);
}
}