use std::fmt;
use std::io;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct SourceSlice {
pub offset: u64,
pub size: usize,
}
pub trait Source<'s>: fmt::Debug {
fn view(&mut self, slices: &[SourceSlice]) -> Result<Box<dyn SourceView<'s>>, io::Error>;
}
pub trait SourceView<'s>: fmt::Debug {
fn as_slice(&self) -> &[u8];
}
#[derive(Clone)]
struct ReadView {
bytes: Vec<u8>,
}
impl fmt::Debug for ReadView {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ReadView({} bytes)", self.bytes.len())
}
}
impl SourceView<'_> for ReadView {
fn as_slice(&self) -> &[u8] {
self.bytes.as_slice()
}
}
impl<'s, T> Source<'s> for T
where
T: io::Read + io::Seek + fmt::Debug + 's,
{
fn view(&mut self, slices: &[SourceSlice]) -> Result<Box<dyn SourceView<'s>>, io::Error> {
let len = slices.iter().fold(0, |acc, s| acc + s.size);
let mut v = ReadView {
bytes: Vec::with_capacity(len),
};
v.bytes.resize(len, 0);
{
let bytes = v.bytes.as_mut_slice();
let mut output_offset: usize = 0;
for slice in slices {
self.seek(io::SeekFrom::Start(slice.offset))?;
self.read_exact(&mut bytes[output_offset..(output_offset + slice.size)])?;
output_offset += slice.size;
}
}
Ok(Box::new(v))
}
}
#[cfg(test)]
mod tests {
mod read_view {
use crate::source::*;
use std::io::Cursor;
use std::io::ErrorKind;
#[test]
fn test_basic_reading() {
let mut data = vec![0; 4096];
data[42] = 42;
let mut source: Box<dyn Source<'_>> = Box::new(Cursor::new(data.as_slice()));
let source_slices = vec![SourceSlice {
offset: 40,
size: 4,
}];
let view = source
.view(source_slices.as_slice())
.expect("viewing must succeed");
assert_eq!(&[0u8, 0, 42, 0], view.as_slice());
}
#[test]
fn test_discontinuous_reading() {
let mut data = vec![0; 4096];
data[42] = 42;
data[88] = 88;
let mut source: Box<dyn Source<'_>> = Box::new(Cursor::new(data.as_slice()));
let source_slices = vec![
SourceSlice {
offset: 88,
size: 1,
},
SourceSlice {
offset: 40,
size: 4,
},
];
let view = source
.view(source_slices.as_slice())
.expect("viewing must succeed");
assert_eq!(&[88u8, 0, 0, 42, 0], view.as_slice());
}
#[test]
fn test_duplicate_reading() {
let mut data = vec![0; 4096];
data[42] = 42;
data[88] = 88;
let mut source: Box<dyn Source<'_>> = Box::new(Cursor::new(data.as_slice()));
let source_slices = vec![
SourceSlice {
offset: 88,
size: 1,
},
SourceSlice {
offset: 40,
size: 4,
},
SourceSlice {
offset: 88,
size: 1,
},
];
let view = source
.view(source_slices.as_slice())
.expect("viewing must succeed");
assert_eq!(&[88u8, 0, 0, 42, 0, 88], view.as_slice());
}
#[test]
fn test_eof_reading() {
let data = vec![0; 4096];
let mut source: Box<dyn Source<'_>> = Box::new(Cursor::new(data.as_slice()));
let source_slices = vec![SourceSlice {
offset: 4095,
size: 2,
}];
let r = source.view(source_slices.as_slice());
match r {
Ok(_) => panic!("should have failed"),
Err(e) => {
assert_eq!(ErrorKind::UnexpectedEof, e.kind());
}
}
}
}
}