#![doc = include_str!("../README.md")]
use memmap2::{MmapMut, MmapOptions};
use std::{marker::PhantomData, path::Path};
#[repr(transparent)]
pub struct MmapCell<T> {
raw: MmapMut,
_inner: PhantomData<T>,
}
impl<T> Drop for MmapCell<T> {
fn drop(&mut self) {
let _ = self.raw.flush();
}
}
impl<T> MmapCell<T> {
pub unsafe fn new(m: MmapMut) -> MmapCell<T> {
MmapCell {
raw: m,
_inner: PhantomData,
}
}
pub fn new_anon() -> Result<MmapCell<T>, std::io::Error> {
Ok(unsafe { MmapCell::new(MmapOptions::new().len(size_of::<T>()).map_anon()?) })
}
pub unsafe fn new_named<P: AsRef<Path>>(path: P) -> Result<MmapCell<T>, std::io::Error> {
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(path)?;
file.set_len(size_of::<T>() as u64)?;
let m = unsafe { MmapMut::map_mut(&file)? };
Ok(unsafe { MmapCell::new(m) })
}
pub unsafe fn open_named<P: AsRef<Path>>(path: P) -> Result<MmapCell<T>, std::io::Error> {
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(false)
.truncate(false)
.open(path)?;
let m = unsafe { MmapMut::map_mut(&file)? };
Ok(unsafe { MmapCell::new(m) })
}
pub fn get<'a>(&self) -> &'a T {
unsafe {
self.raw
.as_ptr()
.cast::<T>()
.as_ref()
.expect("not null pointer")
}
}
pub fn get_mut<'a>(&mut self) -> &'a mut T {
unsafe {
self.raw
.as_mut_ptr()
.cast::<T>()
.as_mut()
.expect("non null pointer")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestStruct {
thing1: i32,
}
#[test]
fn anon_mmapcell() {
let mut anon_cell = MmapCell::<TestStruct>::new_anon().unwrap();
anon_cell.get_mut().thing1 = 3;
assert!(anon_cell.get().thing1 == 3);
}
}