use std::{slice, fs::File, ffi::c_void, num::NonZeroUsize};
use std::os::unix::prelude::*;
use nix::{errno::Errno, sys::mman::{mmap, munmap, ProtFlags, MapFlags}};
pub struct MappedFile {
addr: *mut c_void,
len: usize,
}
#[derive(Debug)]
pub enum MapError {
ZeroLength,
Io(std::io::Error),
}
impl From<std::io::Error> for MapError {
fn from(err: std::io::Error) -> Self {
MapError::Io(err)
}
}
impl From<Errno> for MapError {
fn from(err: Errno) -> Self {
MapError::Io(std::io::Error::from_raw_os_error(err as i32))
}
}
impl MappedFile {
pub fn new(f: &File) -> Result<Self, MapError> {
let len: NonZeroUsize = NonZeroUsize::new(f.metadata()?.len().try_into().unwrap())
.ok_or(MapError::ZeroLength)?;
unsafe {
let addr = mmap(None, len, ProtFlags::PROT_READ, MapFlags::MAP_SHARED, f.as_raw_fd(), 0)?;
Ok(MappedFile {
addr,
len: len.into(),
})
}
}
pub fn data(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(self.addr as *const u8, self.len)
}
}
}
impl Drop for MappedFile {
fn drop(&mut self) {
unsafe {
munmap(self.addr, self.len).expect("munmap failed");
}
}
}