use crate::error::Result;
pub trait BlockSource {
fn len(&self) -> u64;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn read_at(&mut self, offset: u64, buf: &mut [u8]) -> Result<()>;
}
pub struct SliceSource<'a> {
data: &'a [u8],
}
impl<'a> SliceSource<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data }
}
}
impl BlockSource for SliceSource<'_> {
fn len(&self) -> u64 {
self.data.len() as u64
}
fn read_at(&mut self, offset: u64, buf: &mut [u8]) -> Result<()> {
let start =
usize::try_from(offset).map_err(|_| crate::FoldError::Io("offset overflows usize"))?;
let end = start
.checked_add(buf.len())
.ok_or(crate::FoldError::Io("offset+len overflow"))?;
if end > self.data.len() {
return Err(crate::FoldError::Io("read past end of source"));
}
buf.copy_from_slice(&self.data[start..end]);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slice_source_reads_and_bounds_check() {
let bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
let mut s = SliceSource::new(&bytes);
assert_eq!(s.len(), 8);
assert!(!s.is_empty());
let mut buf = [0u8; 3];
s.read_at(2, &mut buf).unwrap();
assert_eq!(buf, [2, 3, 4]);
let mut over = [0u8; 4];
assert!(s.read_at(6, &mut over).is_err());
}
}