use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use crate::error::FitsError;
use crate::error::Result;
mod sealed {
pub trait Sealed {}
}
impl<R> sealed::Sealed for StreamSource<R> {}
impl sealed::Sealed for SliceSource<'_> {}
#[cfg(feature = "mmap")]
impl sealed::Sealed for MmapSource {}
pub trait Source: sealed::Sealed {
fn size(&self) -> u64;
fn slice<'a>(
&'a mut self,
offset: u64,
len: usize,
scratch: &'a mut Vec<u8>,
) -> Result<&'a [u8]>;
fn read_owned(&mut self, offset: u64, len: usize) -> Result<Vec<u8>>;
}
fn check_range(offset: u64, len: usize, size: u64) -> Result<()> {
if offset.checked_add(len as u64).is_none_or(|end| end > size) {
return Err(FitsError::UnexpectedEof);
}
Ok(())
}
#[derive(Debug)]
pub struct StreamSource<R> {
inner: R,
len: u64,
}
impl<R: Read + Seek> StreamSource<R> {
pub(crate) fn new(mut inner: R) -> Result<StreamSource<R>> {
let len = inner.seek(SeekFrom::End(0))?;
Ok(StreamSource { inner, len })
}
}
impl<R: Read + Seek> Source for StreamSource<R> {
fn size(&self) -> u64 {
self.len
}
fn slice<'a>(
&'a mut self,
offset: u64,
len: usize,
scratch: &'a mut Vec<u8>,
) -> Result<&'a [u8]> {
check_range(offset, len, self.len)?;
self.inner.seek(SeekFrom::Start(offset))?;
scratch.resize(len, 0);
self.inner.read_exact(scratch.as_mut_slice())?;
Ok(&scratch[..len])
}
fn read_owned(&mut self, offset: u64, len: usize) -> Result<Vec<u8>> {
check_range(offset, len, self.len)?;
self.inner.seek(SeekFrom::Start(offset))?;
let mut buf = vec![0u8; len];
self.inner.read_exact(&mut buf)?;
Ok(buf)
}
}
#[derive(Debug)]
pub struct SliceSource<'a> {
bytes: &'a [u8],
}
impl<'a> SliceSource<'a> {
pub(crate) fn new(bytes: &'a [u8]) -> SliceSource<'a> {
SliceSource { bytes }
}
}
impl Source for SliceSource<'_> {
fn size(&self) -> u64 {
self.bytes.len() as u64
}
fn slice<'a>(
&'a mut self,
offset: u64,
len: usize,
_scratch: &'a mut Vec<u8>,
) -> Result<&'a [u8]> {
check_range(offset, len, self.bytes.len() as u64)?;
let off = offset as usize;
Ok(&self.bytes[off..off + len])
}
fn read_owned(&mut self, offset: u64, len: usize) -> Result<Vec<u8>> {
check_range(offset, len, self.bytes.len() as u64)?;
let off = offset as usize;
Ok(self.bytes[off..off + len].to_vec())
}
}
#[cfg(feature = "mmap")]
#[derive(Debug)]
pub struct MmapSource {
map: memmap2::Mmap,
}
#[cfg(feature = "mmap")]
impl MmapSource {
pub(crate) fn open(path: &std::path::Path) -> Result<MmapSource> {
let file = std::fs::File::open(path)?;
let map = unsafe { memmap2::Mmap::map(&file)? };
Ok(MmapSource { map })
}
}
#[cfg(feature = "mmap")]
impl Source for MmapSource {
fn size(&self) -> u64 {
self.map.len() as u64
}
fn slice<'a>(
&'a mut self,
offset: u64,
len: usize,
_scratch: &'a mut Vec<u8>,
) -> Result<&'a [u8]> {
check_range(offset, len, self.map.len() as u64)?;
let off = offset as usize;
Ok(&self.map[off..off + len])
}
fn read_owned(&mut self, offset: u64, len: usize) -> Result<Vec<u8>> {
check_range(offset, len, self.map.len() as u64)?;
let off = offset as usize;
Ok(self.map[off..off + len].to_vec())
}
}