use crate::{DrivenError, Result};
use memmap2::Mmap;
use std::fs::File;
use std::path::Path;
#[derive(Debug)]
pub struct MappedRule {
mmap: Mmap,
path: std::path::PathBuf,
}
impl MappedRule {
pub fn open(path: &Path) -> Result<Self> {
let file = File::open(path).map_err(|e| {
DrivenError::Io(std::io::Error::new(
e.kind(),
format!("Failed to open {}: {}", path.display(), e),
))
})?;
let mmap = unsafe { Mmap::map(&file) }.map_err(|e| {
DrivenError::Io(std::io::Error::other(format!(
"Failed to mmap {}: {}",
path.display(),
e
)))
})?;
Ok(Self {
mmap,
path: path.to_path_buf(),
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.mmap
}
pub fn len(&self) -> usize {
self.mmap.len()
}
pub fn is_empty(&self) -> bool {
self.mmap.is_empty()
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn advise_sequential(&self) -> Result<()> {
#[cfg(unix)]
{
self.mmap.advise(memmap2::Advice::Sequential).map_err(|e| {
DrivenError::Io(std::io::Error::new(
std::io::ErrorKind::Other,
e.to_string(),
))
})?;
}
Ok(())
}
pub fn advise_willneed(&self) -> Result<()> {
#[cfg(unix)]
{
self.mmap.advise(memmap2::Advice::WillNeed).map_err(|e| {
DrivenError::Io(std::io::Error::new(
std::io::ErrorKind::Other,
e.to_string(),
))
})?;
}
Ok(())
}
}
#[derive(Debug, Default)]
pub struct RuleMapping;
impl RuleMapping {
pub fn can_map(path: &Path) -> bool {
path.is_file() && path.metadata().map(|m| m.len() > 0).unwrap_or(false)
}
pub fn strategy(size: u64) -> MappingStrategy {
if size < 4096 {
MappingStrategy::ReadAll } else if size < 1024 * 1024 {
MappingStrategy::MapPrivate } else {
MappingStrategy::MapShared }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MappingStrategy {
ReadAll,
MapPrivate,
MapShared,
}
#[derive(Debug)]
pub struct PreloadedRule {
data: Vec<u8>,
path: std::path::PathBuf,
}
impl PreloadedRule {
pub fn load(path: &Path) -> Result<Self> {
let data = std::fs::read(path)?;
Ok(Self {
data,
path: path.to_path_buf(),
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn path(&self) -> &Path {
&self.path
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mapping_strategy() {
assert_eq!(RuleMapping::strategy(100), MappingStrategy::ReadAll);
assert_eq!(RuleMapping::strategy(10_000), MappingStrategy::MapPrivate);
assert_eq!(
RuleMapping::strategy(10_000_000),
MappingStrategy::MapShared
);
}
}