use std::io;
use std::sync::Arc;
use fskit::ReadAt;
use crate::error::Error;
use crate::error::Result;
use crate::geometry::ByteLen;
use crate::geometry::ByteOffset;
use crate::geometry::ByteRange;
pub trait HexSource: Send + Sync {
fn len(&self) -> ByteLen;
fn is_empty(&self) -> bool {
self.len().is_zero()
}
fn read(&self, range: ByteRange) -> Result<Vec<u8>>;
}
impl<T: HexSource + ?Sized> HexSource for Arc<T> {
fn len(&self) -> ByteLen {
(**self).len()
}
fn read(&self, range: ByteRange) -> Result<Vec<u8>> {
(**self).read(range)
}
}
#[derive(Debug, Clone)]
pub struct MemorySource {
bytes: Arc<[u8]>,
}
impl MemorySource {
pub fn new(bytes: impl Into<Arc<[u8]>>) -> Self {
Self { bytes: bytes.into() }
}
}
impl HexSource for MemorySource {
fn len(&self) -> ByteLen {
ByteLen(self.bytes.len() as u64)
}
fn read(&self, range: ByteRange) -> Result<Vec<u8>> {
let source_len = ByteOffset(self.bytes.len() as u64);
if range.end() > source_len {
return Err(Error::OutOfBounds { range, len: source_len });
}
let start = range.start().get() as usize;
let end = range.end().get() as usize;
Ok(self.bytes[start..end].to_vec())
}
}
pub struct ReadAtSource<R: ReadAt<()> + Send + Sync> {
inner: R,
len: ByteLen,
}
impl<R: ReadAt<()> + Send + Sync> ReadAtSource<R> {
pub fn new(inner: R, len: ByteLen) -> Self {
Self { inner, len }
}
}
impl<R: ReadAt<()> + Send + Sync> HexSource for ReadAtSource<R> {
fn len(&self) -> ByteLen {
self.len
}
fn read(&self, range: ByteRange) -> Result<Vec<u8>> {
let source_end = ByteOffset(self.len.get());
if range.end() > source_end {
return Err(Error::OutOfBounds { range, len: source_end });
}
let bytes =
self.inner.read_at(&(), range.as_u64_range()).map_err(|source: io::Error| Error::Io { range, source })?;
Ok(bytes.as_ref().to_vec())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::geometry::ByteOffset;
#[test]
fn memory_source_reads() {
let src = MemorySource::new(vec![0, 1, 2, 3, 4, 5]);
assert_eq!(src.len().get(), 6);
let range = ByteRange::new(ByteOffset(1), ByteOffset(4)).unwrap();
assert_eq!(src.read(range).unwrap(), vec![1, 2, 3]);
}
#[test]
fn memory_source_out_of_bounds() {
let src = MemorySource::new(vec![0, 1, 2]);
let range = ByteRange::new(ByteOffset(0), ByteOffset(10)).unwrap();
match src.read(range) {
Err(Error::OutOfBounds { .. }) => {}
other => panic!("expected OutOfBounds, got {other:?}"),
}
}
}