use std::path::Path;
use std::sync::Arc;
use crate::array::Data;
use crate::buffer::Buffer;
use crate::{Array, DType, Error, Result, shape};
#[derive(Clone)]
pub struct MappedFile {
buffer: Arc<Buffer>,
}
impl std::fmt::Debug for MappedFile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MappedFile")
.field("len", &self.len())
.finish()
}
}
impl MappedFile {
pub fn open(path: impl AsRef<Path>) -> Result<Self> {
Ok(Self {
buffer: Arc::new(Buffer::map_file(path.as_ref())?),
})
}
pub fn len(&self) -> usize {
self.buffer.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn bytes(&self) -> &[u8] {
self.buffer.bytes()
}
pub fn section(&self, offset: usize, len: usize) -> Result<Self> {
if offset.checked_add(len).is_none_or(|end| end > self.len()) {
return Err(Error::Io(format!(
"{len} bytes at offset {offset} exceed the file's {} bytes",
self.len()
)));
}
let mut copy = Buffer::try_alloc(len)?;
copy.bytes_mut()
.copy_from_slice(&self.bytes()[offset..offset + len]);
Ok(Self {
buffer: Arc::new(copy),
})
}
pub fn array(&self, offset: usize, dtype: DType, shape: &[usize]) -> Result<Array> {
let nbytes = shape::checked_nbytes(shape, dtype.size())?;
if offset
.checked_add(nbytes)
.is_none_or(|end| end > self.len())
{
return Err(Error::Io(format!(
"{nbytes} bytes at offset {offset} exceed the file's {} bytes",
self.len()
)));
}
if offset.is_multiple_of(dtype.size()) {
let data = Data {
buffer: self.buffer.clone(),
offset: (offset / dtype.size()) as isize,
};
return Array::leaf(Ok(data), dtype, shape.into());
}
let mut copy = Buffer::try_alloc(nbytes)?;
copy.bytes_mut()
.copy_from_slice(&self.bytes()[offset..offset + nbytes]);
Array::from_buffer(copy, dtype, shape)
}
}