use std::{
fs,
marker::PhantomData,
ops::{Index, IndexMut},
os::unix::prelude::AsRawFd,
slice::{Iter, IterMut},
};
pub use mmap::MapOption;
use mmap::MemoryMap;
use rayon::prelude::*;
pub struct EasyMmap<'a, T> {
_map: MemoryMap,
_data: &'a mut [T],
capacity: usize,
_file: Option<fs::File>,
}
impl<'a, T> EasyMmap<'a, T>
where
T: Copy,
{
fn new(capacity: usize, options: &[MapOption], file: Option<fs::File>) -> EasyMmap<'a, T> {
let map = MemoryMap::new(capacity * std::mem::size_of::<T>(), options).unwrap();
let slice = unsafe { std::slice::from_raw_parts_mut(map.data().cast::<T>(), capacity) };
EasyMmap {
_map: map,
_data: slice,
capacity,
_file: file,
}
}
pub fn len(&self) -> usize {
self.capacity
}
pub fn iter(&self) -> Iter<'_, T> {
self._data.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
self._data.iter_mut()
}
pub fn par_iter(&self) -> impl ParallelIterator<Item = &T> where T: Send + Sync {
self._data.par_iter()
}
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut T> where T : Send + Sync{
self._data.par_iter_mut()
}
pub fn get_data_as_slice(&self) -> &[T] {
self._data
}
pub fn get_data_as_slice_mut(&mut self) -> &mut [T] {
self._data
}
pub fn fill(&mut self, f: impl Fn(usize) -> T) {
for (i, v) in self._data.iter_mut().enumerate() {
*v = f(i);
}
}
}
impl<'a, T> Index<usize> for EasyMmap<'a, T>
where
T: Copy,
{
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
if index >= self.len() {
panic!(
"Index {} is out of bounds for type {}",
index,
std::any::type_name::<T>(),
);
};
&self._data[index]
}
}
impl<'a, T> IndexMut<usize> for EasyMmap<'a, T>
where
T: Copy,
{
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index >= self.len() {
panic!(
"Index {} is out of bounds for type {}",
index,
std::any::type_name::<T>(),
)
}
&mut self._data[index]
}
}
pub struct EasyMmapBuilder<T> {
file: Option<fs::File>,
capacity: usize,
options: Vec<MapOption>,
_type: PhantomData<T>,
}
impl<'a, T> EasyMmapBuilder<T> {
pub fn new() -> EasyMmapBuilder<T> {
EasyMmapBuilder {
file: None,
capacity: 0,
options: Vec::new(),
_type: PhantomData,
}
}
pub fn build(mut self) -> EasyMmap<'a, T>
where
T: Copy,
{
if self.file.is_some() {
let file = self.file.unwrap();
file.set_len((self.capacity * std::mem::size_of::<T>()) as u64)
.unwrap();
self.options.push(MapOption::MapFd(file.as_raw_fd()));
self.options .push(MapOption::MapNonStandardFlags(libc::MAP_SHARED));
self.file = Some(file);
}
EasyMmap::new(self.capacity, &self.options, self.file)
}
pub fn file(mut self, file: fs::File) -> EasyMmapBuilder<T> {
self.file = Some(file);
self
}
pub fn capacity(mut self, capacity: usize) -> EasyMmapBuilder<T> {
self.capacity = capacity;
self
}
pub fn options(mut self, options: &[MapOption]) -> EasyMmapBuilder<T> {
self.options = options.to_vec();
self
}
pub fn add_option(mut self, option: MapOption) -> EasyMmapBuilder<T> {
self.options.push(option);
self
}
pub fn readable(mut self) -> EasyMmapBuilder<T> {
self.options.push(MapOption::MapReadable);
self
}
pub fn writable(mut self) -> EasyMmapBuilder<T> {
self.options.push(MapOption::MapWritable);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_random_file() -> fs::File {
fs::OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(format!("/tmp/map{}", rand::random::<u64>()))
.unwrap()
}
#[test]
fn map_create() {
let map = &mut EasyMmapBuilder::<u32>::new()
.capacity(10)
.options(&[])
.build();
assert_eq!(map.len(), 10);
}
#[test]
fn map_write_read() {
let map = &mut EasyMmapBuilder::<u32>::new()
.capacity(1)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
map[0] = 1;
assert_eq!(map[0], 1);
}
#[test]
fn map_iter() {
let map = &mut EasyMmapBuilder::<u32>::new()
.capacity(5)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
for i in 0..5 {
map[i] = i as u32;
}
assert_eq!(
map.iter().map(|x| *x).collect::<Vec<_>>(),
vec![0, 1, 2, 3, 4]
);
}
#[test]
#[should_panic]
fn map_oob_write() {
let map = &mut EasyMmapBuilder::<u32>::new()
.capacity(1)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
map[1] = 1;
}
#[test]
#[should_panic]
fn map_oob_read() {
let map = &mut EasyMmapBuilder::<u32>::new()
.capacity(1)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
map[1];
}
#[test]
fn map_create_file() {
let file = create_random_file();
let map = &mut EasyMmapBuilder::<u32>::new()
.file(file)
.capacity(10)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
assert_eq!(map.len(), 10);
map[0] = 1;
assert_eq!(map[0], 1);
}
#[test]
fn test_large_size() {
let map = &mut EasyMmapBuilder::new()
.capacity(65535)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
for i in 0..65535 {
map[i] = i as u64;
}
for i in 0..65535 {
assert_eq!(map[i], i as u64);
}
}
#[test]
fn test_struct() {
#[derive(Clone, Copy)]
struct TestStruct {
v1: i64,
v2: bool,
}
let length = 100000;
let file = create_random_file();
let map = &mut EasyMmapBuilder::new()
.capacity(length)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.file(file)
.build();
for i in 0..length {
map[i] = TestStruct {
v1: i as i64,
v2: i % 2 == 0,
};
}
for i in 0..length {
let s = map[i];
assert_eq!(s.v1, i as i64);
assert_eq!(s.v2, i % 2 == 0);
}
}
#[test]
fn test_iter() {
let mut map = EasyMmapBuilder::<i32>::new()
.capacity(5)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
for i in 0..5 {
map[i] = i as i32;
}
for (i, x) in map.iter().enumerate() {
assert_eq!(i as i32, *x);
}
}
#[test]
fn test_iter_mut() {
let mut map = EasyMmapBuilder::<i32>::new()
.capacity(5)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
for (i, x) in map.iter_mut().enumerate() {
*x = i as i32;
}
for (i, x) in map.iter().enumerate() {
assert_eq!(i as i32, *x);
}
}
#[test]
fn test_complex_iterator() {
let mut map = EasyMmapBuilder::<u32>::new()
.capacity(5)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
map.iter_mut()
.enumerate()
.for_each(|(idx, x)| *x = idx as u32);
let v = map
.iter()
.map(|x| *x * 3)
.filter(|x| x % 2 == 0)
.collect::<Vec<u32>>();
map.iter_mut().zip(v).for_each(|(x, y)| *x = y);
assert_eq!(
map.iter().map(|x| *x).collect::<Vec<_>>(),
vec![0, 6, 12, 3, 4]
);
}
#[test]
fn get_data_slice() {
let mut map = EasyMmapBuilder::<u32>::new()
.capacity(5)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
map.iter_mut()
.enumerate()
.for_each(|(idx, x)| *x = idx as u32);
let slice = map.get_data_as_slice();
assert_eq!(slice.len(), 5);
assert_eq!(slice[0], map[0]);
assert_eq!(slice[1], map[1]);
assert_eq!(slice[2], map[2]);
assert_eq!(slice[3], map[3]);
assert_eq!(slice[4], map[4]);
let slice = map.get_data_as_slice_mut();
assert_eq!(slice.len(), 5);
slice[0] = 10;
assert_eq!(map[0], 10);
}
#[test]
fn easier_builder() {
let mut map = EasyMmapBuilder::<i32>::new()
.capacity(1)
.readable()
.writable()
.build();
map[0] = 1;
assert_eq!(map[0], 1);
}
#[test]
fn fill_constant() {
let mut map = EasyMmapBuilder::<i32>::new()
.capacity(5)
.readable()
.writable()
.build();
map.fill(|_| 1);
assert_eq!(map.get_data_as_slice(), vec![1, 1, 1, 1, 1]);
}
#[test]
fn fill_large() {
let mut map = EasyMmapBuilder::<i32>::new()
.capacity(100000)
.readable()
.writable()
.build();
map.fill(|i| i as i32);
assert_eq!(map.get_data_as_slice(), (0..100000).collect::<Vec<_>>());
}
#[test]
fn open_written_file() {
let values = vec![1, 2, 3, 4, 5, 10, 20, 50];
let filename = format!("/tmp/file{}", rand::random::<i32>());
fs::write(&filename, &values).expect("Failed to write values to file");
let file = fs::OpenOptions::new()
.read(true)
.write(true)
.create(false)
.open(&filename)
.expect("Failed to open file");
let map = EasyMmapBuilder::<u8>::new()
.capacity(values.len())
.writable()
.readable()
.file(file)
.build();
assert_eq!(map.get_data_as_slice(), values);
}
#[test]
fn parallel_iterators() {
let mut map = EasyMmapBuilder::<i32>::new()
.capacity(5)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
map.fill(|i| i as i32);
assert_eq!(
map.par_iter().map(|x| *x).collect::<Vec<_>>(),
(0..5).collect::<Vec<_>>()
);
}
#[test]
fn parallel_iterators_mut() {
let mut map = EasyMmapBuilder::<i32>::new()
.capacity(5)
.options(&[MapOption::MapReadable, MapOption::MapWritable])
.build();
map.fill(|i| i as i32);
map.par_iter_mut().for_each(|x| *x += 1);
assert_eq!(
map.par_iter().map(|x| *x).collect::<Vec<_>>(),
(1..6).collect::<Vec<_>>()
);
}
}