use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use crate::error::StreamingError;
pub struct MappedFile {
path: PathBuf,
data: Vec<u8>,
file_size: u64,
}
impl MappedFile {
pub fn open(path: impl AsRef<Path>) -> Result<Self, StreamingError> {
let path = path.as_ref().to_path_buf();
let mut file = File::open(&path)?;
let file_size = file.seek(SeekFrom::End(0))?;
file.seek(SeekFrom::Start(0))?;
let mut data = Vec::with_capacity(file_size as usize);
file.read_to_end(&mut data)?;
Ok(Self {
path,
data,
file_size,
})
}
pub fn read_range(&self, start: u64, len: usize) -> Result<&[u8], StreamingError> {
let start_usize = start as usize;
let end = start_usize + len;
if end > self.data.len() {
return Err(StreamingError::Other(format!(
"Range [{start_usize}, {end}) out of bounds (file size {})",
self.file_size
)));
}
Ok(&self.data[start_usize..end])
}
#[must_use]
pub fn as_slice(&self) -> &[u8] {
&self.data
}
#[must_use]
pub fn file_size(&self) -> u64 {
self.file_size
}
#[must_use]
pub fn path(&self) -> &Path {
&self.path
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn read_ranges(&self, ranges: &[(u64, usize)]) -> Vec<Result<&[u8], StreamingError>> {
ranges
.iter()
.map(|(start, len)| self.read_range(*start, *len))
.collect()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PrefetchPriority {
Low,
Normal,
High,
}
impl PartialOrd for PrefetchPriority {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PrefetchPriority {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let rank = |p: &PrefetchPriority| match p {
PrefetchPriority::Low => 0u8,
PrefetchPriority::Normal => 1,
PrefetchPriority::High => 2,
};
rank(self).cmp(&rank(other))
}
}
#[derive(Debug, Clone)]
pub struct PrefetchHint {
pub offset: u64,
pub length: usize,
pub priority: PrefetchPriority,
}
pub struct PrefetchScheduler {
hints: Vec<PrefetchHint>,
max_prefetch_bytes: usize,
}
impl PrefetchScheduler {
#[must_use]
pub fn new(max_prefetch_bytes: usize) -> Self {
Self {
hints: Vec::new(),
max_prefetch_bytes,
}
}
pub fn add_hint(&mut self, hint: PrefetchHint) {
self.hints.push(hint);
}
#[must_use]
pub fn sorted_hints(&self) -> Vec<&PrefetchHint> {
let mut sorted: Vec<&PrefetchHint> = self.hints.iter().collect();
sorted.sort_by(|a, b| b.priority.cmp(&a.priority).then(a.offset.cmp(&b.offset)));
sorted
}
#[must_use]
pub fn hint_count(&self) -> usize {
self.hints.len()
}
#[must_use]
pub fn total_bytes_hinted(&self) -> usize {
self.hints.iter().map(|h| h.length).sum()
}
#[must_use]
pub fn max_prefetch_bytes(&self) -> usize {
self.max_prefetch_bytes
}
pub fn clear(&mut self) {
self.hints.clear();
}
}