use std::collections::HashMap;
use std::fs::File;
use std::ops::Range;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::RwLock;
use memmap2::MmapOptions;
use vfs::VfsError;
use vfs::error::VfsErrorKind;
use crate::data::idx_vfs::Prime;
#[derive(Debug)]
pub struct MmapPkgSource {
pkgs_dir: PathBuf,
pkgs: RwLock<HashMap<String, Arc<memmap2::Mmap>>>,
}
impl MmapPkgSource {
pub fn new<P: AsRef<Path>>(pkgs_dir: P) -> Self {
Self { pkgs_dir: pkgs_dir.as_ref().to_owned(), pkgs: Default::default() }
}
fn ensure_loaded(&self, volume: &str) -> Result<(), VfsError> {
{
let pkgs = self.pkgs.read().unwrap();
if pkgs.contains_key(volume) {
return Ok(());
}
}
let pkg_path = self.pkgs_dir.join(volume);
if !pkg_path.exists() {
return Err(VfsError::from(VfsErrorKind::FileNotFound));
}
let file = File::open(&pkg_path).map_err(|e| VfsError::from(VfsErrorKind::IoError(e)))?;
let mmap = unsafe { MmapOptions::new().map(&file) }.map_err(|e| VfsError::from(VfsErrorKind::IoError(e)))?;
self.pkgs.write().unwrap().insert(volume.to_string(), Arc::new(mmap));
Ok(())
}
fn get_mmap(&self, volume: &str) -> Result<Arc<memmap2::Mmap>, VfsError> {
self.ensure_loaded(volume)?;
let pkgs = self.pkgs.read().unwrap();
Ok(Arc::clone(pkgs.get(volume).unwrap()))
}
}
#[derive(Clone, Debug)]
pub struct MmapSlice {
mmap: Arc<memmap2::Mmap>,
range: Range<usize>,
}
impl AsRef<[u8]> for MmapSlice {
fn as_ref(&self) -> &[u8] {
&self.mmap[self.range.clone()]
}
}
impl Prime for MmapPkgSource {
fn prime_volume(&self, volume: &str, range: Range<usize>) -> Result<impl AsRef<[u8]>, VfsError> {
let mmap = self.get_mmap(volume)?;
Ok(MmapSlice { mmap, range })
}
}
#[cfg(feature = "async_vfs")]
#[async_trait::async_trait]
impl crate::data::idx_vfs::AsyncPrime for MmapPkgSource {
async fn prime_volume(&self, volume: &str, range: Range<usize>) -> Result<impl AsRef<[u8]>, VfsError> {
let mmap = self.get_mmap(volume)?;
Ok(MmapSlice { mmap, range })
}
}