From be452a99ff2a37297c3370752d4616a83d7d2779 Mon Sep 17 00:00:00 2001 From: Avril Date: Thu, 1 Sep 2022 22:07:37 +0100 Subject: [PATCH] Added `UniqueSlice`, `MappedSlice`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copied over enums for control functions into re-exported submodule `flags`. Fortune for mapped-file's current commit: Curse − 凶 --- .gitignore | 2 + Cargo.toml | 10 +++ src/flags.rs | 132 ++++++++++++++++++++++++++++++ src/lib.rs | 42 ++++++++++ src/uniq.rs | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 411 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/flags.rs create mode 100644 src/lib.rs create mode 100644 src/uniq.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..875e0f0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "mapped-file" +description = "construct a memory mapping over any file object" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libc = "0.2.132" diff --git a/src/flags.rs b/src/flags.rs new file mode 100644 index 0000000..4a263ac --- /dev/null +++ b/src/flags.rs @@ -0,0 +1,132 @@ +//! All flags for controlling a `MappedFile`. +use libc::c_int; + + +/// Permissions for the mapped pages. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)] +pub enum Perm +{ +#[default] + ReadWrite, + Readonly, + Writeonly, + RX, + WRX, +} + +/// Flags for mapping a file descriptor. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)] +pub enum Flags +{ +#[default] + Shared, + Private, +} + +impl Flags +{ +#[inline(always)] + pub(super) const fn get_flags(self) -> c_int + { + use libc::{ + MAP_SHARED, + MAP_PRIVATE, + }; + match self { + Self::Shared => MAP_SHARED, + Self::Private => MAP_PRIVATE, + } + } +#[inline(always)] + pub(super) const fn requires_write_access(&self) -> bool + { + match self { + Self::Shared => true, + _ => false + } + } +} + +impl Perm +{ +#[inline(always)] + pub(super) const fn get_prot(self) -> c_int + { + use libc::{ + PROT_READ, PROT_WRITE, PROT_EXEC, + }; + match self { + Self::ReadWrite => PROT_READ | PROT_WRITE, + Self::Readonly => PROT_READ, + Self::Writeonly => PROT_WRITE, + Self::RX => PROT_READ | PROT_EXEC, + Self::WRX => PROT_READ | PROT_WRITE | PROT_EXEC, + } + } +#[inline(always)] + pub(super) const fn open_rw(&self, flags: Flags) -> (bool, bool) + { + let wr = flags.requires_write_access(); + match self { + Self::ReadWrite | Self::WRX => (true, wr), + Self::Readonly | Self::RX => (true, false), + Self::Writeonly => (false, wr), + } + } +} + +/// Options for flushing a mapping. These will control how the `msync()` is called. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)] +pub enum Flush +{ +#[default] + Wait, + Async, + Invalidate, + InvalidateAsync, +} + +impl Flush +{ +#[inline(always)] + const fn get_ms(self) -> c_int + { + use libc::{ + MS_SYNC, MS_ASYNC, + MS_INVALIDATE, + }; + match self { + Self::Wait => MS_SYNC, + Self::Async => MS_ASYNC, + Self::Invalidate => MS_SYNC | MS_INVALIDATE, + Self::InvalidateAsync => MS_ASYNC | MS_INVALIDATE, + } + } +} + +/// Advice to the kernel about how to load the mapped pages. These will control `madvise()`. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)] +pub enum Advice { +#[default] + Normal, + Sequential, + RandomAccess, +} + +impl Advice +{ +#[inline(always)] + const fn get_madv(self) -> c_int + { + use libc::{ + MADV_NORMAL, + MADV_SEQUENTIAL, + MADV_RANDOM, + }; + match self { + Self::Normal => MADV_NORMAL, + Self::Sequential => MADV_SEQUENTIAL, + Self::RandomAccess => MADV_RANDOM, + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..fe864b4 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,42 @@ + +use libc::{ + mmap, + MAP_FAILED, +}; + +use std::{ + ops, + mem, + ptr, +}; + +mod uniq; +use uniq::UniqueSlice; + +mod flags; +pub use flags::*; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +struct MappedSlice(UniqueSlice); + +impl ops::Drop for MappedSlice +{ + #[inline] + fn drop(&mut self) + { + unsafe { + libc::munmap(self.0.as_mut_ptr() as *mut _, self.0.len()); + } + } +} + +/// A memory mapping over file `T`. +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct MappedFile +{ + file: T, + map: MappedSlice, +} + +//TODO: continue copying from the `TODO` line in `utf8encode/src/mmap.rs` diff --git a/src/uniq.rs b/src/uniq.rs new file mode 100644 index 0000000..0ef9553 --- /dev/null +++ b/src/uniq.rs @@ -0,0 +1,225 @@ +//! Unique owned slices of virtual memory +use std::{ + ptr::{ + self, + NonNull, + }, + mem, + borrow::{ + Borrow, BorrowMut + }, + ops, + hash::Hash, +}; + +/// A slice in which nothing is aliased. The `UniqueSlice` *owns* all memory in between `mem` and `end`. +#[derive(Debug)] +pub struct UniqueSlice { + pub(crate) mem: NonNull, + pub(crate) end: NonNull, +} + +impl ops::Drop for UniqueSlice { +#[inline] + fn drop(&mut self) { + if mem::needs_drop::() { + unsafe { + ptr::drop_in_place(self.as_raw_slice_mut()); + } + } + } +} + +impl Borrow<[T]> for UniqueSlice +{ +#[inline] + fn borrow(&self) -> &[T] + { + self.as_slice() + } +} +impl BorrowMut<[T]> for UniqueSlice +{ +#[inline] + fn borrow_mut(&mut self) -> &mut [T] + { + self.as_slice_mut() + } +} + +impl Hash for UniqueSlice +{ +#[inline] + fn hash(&self, hasher: &mut H) + where H: std::hash::Hasher + { + ptr::hash(self.mem.as_ptr() as *const _, hasher); + ptr::hash(self.end.as_ptr() as *const _, hasher); + } +} + +impl Ord for UniqueSlice +{ +#[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering + { + self.end.cmp(&other.end) + } +} +impl PartialOrd for UniqueSlice +{ +#[inline] + fn partial_cmp(&self, other: &Self) -> Option + { + self.end.partial_cmp(&other.end) + } +} + +impl Eq for UniqueSlice{} +impl PartialEq for UniqueSlice +{ +#[inline] + fn eq(&self, other: &Self) -> bool + { + ptr::eq(self.mem.as_ptr(), other.mem.as_ptr()) && + ptr::eq(self.end.as_ptr(), other.end.as_ptr()) + } +} + +impl AsRef<[T]> for UniqueSlice +{ +#[inline] + fn as_ref(&self) -> &[T] + { + self.as_slice() + } +} + +impl AsMut<[T]> for UniqueSlice +{ +#[inline] + fn as_mut(&mut self) -> &mut [T] + { + self.as_slice_mut() + } +} + +impl ops::Deref for UniqueSlice +{ + type Target= [T]; +#[inline] + fn deref(&self) -> &Self::Target + { + self.as_slice() + } +} + +impl ops::DerefMut for UniqueSlice +{ +#[inline] + fn deref_mut(&mut self) -> &mut Self::Target + { + self.as_slice_mut() + } +} + +impl UniqueSlice +{ +#[inline(always)] + pub fn is_empty(&self) -> bool + { + ptr::eq(self.mem.as_ptr(), self.end.as_ptr()) + } +#[inline(always)] + pub fn get_ptr(&self) -> Option> + { + if self.is_empty() { + None + } else { + Some(self.mem) + } + } +} + +impl UniqueSlice +{ +#[inline] + pub fn as_slice(&self) -> &[T] + { + unsafe { &*self.as_raw_slice() } + } +#[inline] + pub fn as_slice_mut(&mut self) -> &mut [T] + { + unsafe { &mut *self.as_raw_slice_mut() } + } +#[inline(always)] + pub fn as_raw_slice_mut(&mut self) -> *mut [T] + { + if self.is_empty() { + ptr::slice_from_raw_parts_mut(self.mem.as_ptr(), 0) + } else { + ptr::slice_from_raw_parts_mut(self.mem.as_ptr(), self.len()) + } + } +#[inline(always)] + pub fn as_raw_slice(&self) -> *const [T] + { + if self.is_empty() { + ptr::slice_from_raw_parts(self.mem.as_ptr() as *const _, 0) + } else { + ptr::slice_from_raw_parts(self.mem.as_ptr() as *const _, self.len()) + } + } +#[inline] + pub fn len(&self) -> usize + { + unsafe { + (self.end.as_ptr().sub(self.mem.as_ptr() as usize) as usize) / mem::size_of::() + } + } +#[inline(always)] + pub fn first(&self) -> Option<&T> + { + if self.is_empty() { + None + } else { + Some(unsafe { &*(self.mem.as_ptr() as *const _) }) + } + } +#[inline(always)] + pub fn last(&self) -> Option<&T> + { + if self.is_empty() { + None + } else { + Some(unsafe { &*(self.end.as_ptr().sub(1) as *const _) }) + } + } +#[inline(always)] + pub fn first_mut(&mut self) -> Option<&mut T> + { + if self.is_empty() { + None + } else { + Some(unsafe { &mut *self.mem.as_ptr() }) + } + } +#[inline(always)] + pub fn last_mut(&mut self) -> Option<&mut T> + { + if self.is_empty() { + None + } else { + Some(unsafe { &mut *self.end.as_ptr().sub(1) }) + } + } + + /// Get a range of pointers in the format `mem..end`. Where `mem` is the first element and `end` is 1 element past the last element. + #[inline] + pub const fn as_ptr_range(&self) -> std::ops::Range<*mut T> + { + self.mem.as_ptr()..self.end.as_ptr() + } +} +