use crate::error::{Mf4Error, Result};
use crate::io::{ByteSlice, ByteSource};
#[derive(Debug, Clone)]
pub struct MemorySource {
data: Vec<u8>,
}
impl MemorySource {
pub fn new(data: Vec<u8>) -> Self {
Self { data }
}
pub fn as_slice(&self) -> &[u8] {
&self.data
}
}
impl ByteSource for MemorySource {
fn len(&self) -> u64 {
self.data.len() as u64
}
fn read_bytes(&self, offset: u64, len: usize) -> Result<ByteSlice<'_>> {
let total_len = self.data.len() as u64;
if offset >= total_len {
return Err(Mf4Error::truncated(offset, len, 0));
}
let start = offset as usize;
let available = self.data.len().saturating_sub(start);
if len > available {
return Err(Mf4Error::truncated(offset, len, available));
}
let end = match start.checked_add(len) {
Some(end) if end <= self.data.len() => end,
_ => return Err(Mf4Error::truncated(offset, len, available)),
};
Ok(ByteSlice::borrowed(&self.data[start..end]))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_memory_source_basic() {
let data = b"Hello, MF4 World!".to_vec();
let source = MemorySource::new(data);
assert_eq!(source.len(), 17);
assert_eq!(source.as_slice(), b"Hello, MF4 World!");
let slice = source.read_bytes(0, 5).unwrap();
assert_eq!(&*slice, b"Hello");
let slice = source.read_bytes(7, 3).unwrap();
assert_eq!(&*slice, b"MF4");
}
#[test]
fn test_memory_source_out_of_bounds() {
let data = b"Short".to_vec();
let source = MemorySource::new(data);
let result = source.read_bytes(0, 100);
assert!(result.is_err());
let result = source.read_bytes(100, 1);
assert!(result.is_err());
}
#[test]
fn test_memory_source_zero_copy() {
let data = b"Test data for zero-copy verification".to_vec();
let source = MemorySource::new(data);
let slice = source.read_bytes(0, 4).unwrap();
assert!(matches!(slice, ByteSlice::Borrowed(_)));
assert_eq!(&*slice, b"Test");
}
#[test]
fn test_memory_source_empty() {
let source = MemorySource::new(Vec::new());
assert_eq!(source.len(), 0);
assert!(source.is_empty());
let result = source.read_bytes(0, 10);
assert!(result.is_err());
}
}