use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom};
use std::sync::Arc;
use crate::reader::pread;
pub enum SegmentSource {
File(File),
Sub {
file: Arc<File>,
base: u64,
len: u64,
},
Mem(Arc<[u8]>),
}
impl SegmentSource {
#[must_use]
pub fn sub(file: Arc<File>, base: u64, len: u64) -> Self {
SegmentSource::Sub { file, base, len }
}
#[must_use]
pub fn from_bytes(bytes: impl Into<Arc<[u8]>>) -> Self {
SegmentSource::Mem(bytes.into())
}
#[must_use]
pub fn len(&self) -> u64 {
match self {
SegmentSource::File(f) => f.metadata().map_or(0, |m| m.len()),
SegmentSource::Sub { len, .. } => *len,
SegmentSource::Mem(b) => b.len() as u64,
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
match self {
SegmentSource::File(f) => pread(f, buf, offset),
SegmentSource::Sub { file, base, len } => {
let avail = len.saturating_sub(offset);
if avail == 0 {
return Ok(0);
}
let want = (buf.len() as u64).min(avail) as usize;
pread(file, &mut buf[..want], base + offset)
}
SegmentSource::Mem(bytes) => {
let off = offset.min(bytes.len() as u64) as usize;
let src = &bytes[off..];
let n = src.len().min(buf.len());
buf[..n].copy_from_slice(&src[..n]);
Ok(n)
}
}
}
}
impl std::fmt::Debug for SegmentSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SegmentSource::File(_) => f.debug_struct("File").field("len", &self.len()).finish(),
SegmentSource::Sub { base, len, .. } => f
.debug_struct("Sub")
.field("base", base)
.field("len", len)
.finish(),
SegmentSource::Mem(b) => f.debug_struct("Mem").field("len", &b.len()).finish(),
}
}
}
pub(crate) struct SegmentCursor<'a> {
src: &'a SegmentSource,
pos: u64,
}
impl<'a> SegmentCursor<'a> {
pub(crate) fn new(src: &'a SegmentSource) -> Self {
Self { src, pos: 0 }
}
pub(crate) fn segment_len(&self) -> u64 {
self.src.len()
}
}
impl Read for SegmentCursor<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.src.read_at(buf, self.pos)?;
self.pos += n as u64;
Ok(n)
}
}
impl Seek for SegmentCursor<'_> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let new_pos: i64 = match pos {
SeekFrom::Start(p) => p as i64,
SeekFrom::End(p) => self.src.len() as i64 + p,
SeekFrom::Current(p) => self.pos as i64 + p,
};
if new_pos < 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"seek to negative position",
));
}
self.pos = new_pos as u64;
Ok(self.pos)
}
}