Copied over enums for control functions into re-exported submodule `flags`. Fortune for mapped-file's current commit: Curse − 凶master
commit
be452a99ff
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/Cargo.lock
|
@ -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"
|
@ -0,0 +1,132 @@
|
||||
//! All flags for controlling a `MappedFile<T>`.
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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<u8>);
|
||||
|
||||
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<T>
|
||||
{
|
||||
file: T,
|
||||
map: MappedSlice,
|
||||
}
|
||||
|
||||
//TODO: continue copying from the `TODO` line in `utf8encode/src/mmap.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<T>` *owns* all memory in between `mem` and `end`.
|
||||
#[derive(Debug)]
|
||||
pub struct UniqueSlice<T> {
|
||||
pub(crate) mem: NonNull<T>,
|
||||
pub(crate) end: NonNull<T>,
|
||||
}
|
||||
|
||||
impl<T> ops::Drop for UniqueSlice<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if mem::needs_drop::<T>() {
|
||||
unsafe {
|
||||
ptr::drop_in_place(self.as_raw_slice_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Borrow<[T]> for UniqueSlice<T>
|
||||
{
|
||||
#[inline]
|
||||
fn borrow(&self) -> &[T]
|
||||
{
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
impl<T> BorrowMut<[T]> for UniqueSlice<T>
|
||||
{
|
||||
#[inline]
|
||||
fn borrow_mut(&mut self) -> &mut [T]
|
||||
{
|
||||
self.as_slice_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Hash for UniqueSlice<T>
|
||||
{
|
||||
#[inline]
|
||||
fn hash<H>(&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<T> Ord for UniqueSlice<T>
|
||||
{
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering
|
||||
{
|
||||
self.end.cmp(&other.end)
|
||||
}
|
||||
}
|
||||
impl<T> PartialOrd for UniqueSlice<T>
|
||||
{
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering>
|
||||
{
|
||||
self.end.partial_cmp(&other.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for UniqueSlice<T>{}
|
||||
impl<T> PartialEq for UniqueSlice<T>
|
||||
{
|
||||
#[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<T> AsRef<[T]> for UniqueSlice<T>
|
||||
{
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[T]
|
||||
{
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<[T]> for UniqueSlice<T>
|
||||
{
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut [T]
|
||||
{
|
||||
self.as_slice_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Deref for UniqueSlice<T>
|
||||
{
|
||||
type Target= [T];
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target
|
||||
{
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::DerefMut for UniqueSlice<T>
|
||||
{
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target
|
||||
{
|
||||
self.as_slice_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UniqueSlice<T>
|
||||
{
|
||||
#[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<NonNull<T>>
|
||||
{
|
||||
if self.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.mem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UniqueSlice<T>
|
||||
{
|
||||
#[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::<T>()
|
||||
}
|
||||
}
|
||||
#[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()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue