use std::convert::TryFrom;
use std::fs::{File, OpenOptions};
use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::slice;
use std::{cmp, fmt, io, marker};
use crate::os::{advise, flush, lock, map_anon, map_file, protect, unlock, unmap};
use crate::sealed::FromPtr;
use crate::{
Advise, ConvertResult, Error, Extent, Flush, Input, Operation, Protect, Result, Size, Span,
SpanMut,
};
pub struct Map(MapMut);
impl Map {
pub fn with_options() -> Options<Self> {
Options::new()
}
pub fn into_map_mut(self) -> ConvertResult<MapMut, Self> {
let (ptr, len) = unsafe { Size::page().bounds(self.0.ptr, self.0.len) };
match unsafe { protect(ptr, len, Protect::ReadWrite) } {
Ok(()) => Ok(self.0),
Err(err) => Err((err, self)),
}
}
pub fn advise(&self, adv: Advise) -> Result<()> {
self.0.advise(adv)
}
pub fn advise_range(&self, off: usize, len: usize, adv: Advise) -> Result<()> {
self.0.advise_range(off, len, adv)
}
pub fn lock(&self) -> Result<()> {
self.0.lock()
}
pub fn lock_range(&self, off: usize, len: usize) -> Result<()> {
self.0.lock_range(off, len)
}
pub fn unlock(&self) -> Result<()> {
self.0.unlock()
}
pub fn unlock_range(&self, off: usize, len: usize) -> Result<()> {
self.0.unlock_range(off, len)
}
}
impl FromPtr for Map {
unsafe fn from_ptr(ptr: *mut u8, len: usize) -> Self {
Self(MapMut::from_ptr(ptr, len))
}
}
impl Span for Map {
#[inline]
fn len(&self) -> usize {
self.0.len()
}
#[inline]
fn as_ptr(&self) -> *const u8 {
self.0.as_ptr()
}
}
impl Deref for Map {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.0.ptr, self.0.len) }
}
}
impl AsRef<[u8]> for Map
where
<Map as Deref>::Target: AsRef<[u8]>,
{
#[inline]
fn as_ref(&self) -> &[u8] {
self.deref()
}
}
impl TryFrom<MapMut> for Map {
type Error = (Error, MapMut);
fn try_from(map: MapMut) -> ConvertResult<Self, MapMut> {
map.into_map()
}
}
impl fmt::Debug for Map {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Map")
.field("ptr", &self.0.ptr)
.field("len", &self.0.len)
.finish()
}
}
#[derive(Debug)]
pub struct MapMut {
ptr: *mut u8,
len: usize,
}
impl MapMut {
pub fn with_options() -> Options<Self> {
let mut opts = Options::new();
opts.write();
opts
}
pub fn new(hint: usize) -> Result<Self> {
Self::with_options().len(Extent::Min(hint)).alloc()
}
pub fn into_map(self) -> ConvertResult<Map, Self> {
let (ptr, len) = unsafe { Size::page().bounds(self.ptr, self.len) };
match unsafe { protect(ptr, len, Protect::ReadWrite) } {
Ok(()) => Ok(Map(self)),
Err(err) => Err((err, self)),
}
}
pub fn flush(&self, file: &File, mode: Flush) -> Result<()> {
unsafe {
let (ptr, len) = Size::page().bounds(self.ptr, self.len);
flush(ptr, file, len, mode)
}
}
pub fn flush_range(&self, file: &File, off: usize, len: usize, mode: Flush) -> Result<()> {
if off + len > self.len {
Err(Error::input(Operation::Flush, Input::InvalidRange))
} else {
unsafe {
let (ptr, len) = Size::page().bounds(self.ptr.add(off), len);
flush(ptr, file, len, mode)
}
}
}
pub fn advise(&self, adv: Advise) -> Result<()> {
unsafe {
let (ptr, len) = Size::page().bounds(self.ptr, self.len);
advise(ptr, len, adv)
}
}
pub fn advise_range(&self, off: usize, len: usize, adv: Advise) -> Result<()> {
if off + len > self.len {
Err(Error::input(Operation::Advise, Input::InvalidRange))
} else {
unsafe {
let (ptr, len) = Size::page().bounds(self.ptr.add(off), len);
advise(ptr, len, adv)
}
}
}
pub fn lock(&self) -> Result<()> {
unsafe {
let (ptr, len) = Size::page().bounds(self.ptr, self.len);
lock(ptr, len)
}
}
pub fn lock_range(&self, off: usize, len: usize) -> Result<()> {
if off + len > self.len {
Err(Error::input(Operation::Lock, Input::InvalidRange))
} else {
unsafe {
let (ptr, len) = Size::page().bounds(self.ptr.add(off), len);
lock(ptr, len)
}
}
}
pub fn unlock(&self) -> Result<()> {
unsafe {
let (ptr, len) = Size::page().bounds(self.ptr, self.len);
unlock(ptr, len)
}
}
pub fn unlock_range(&self, off: usize, len: usize) -> Result<()> {
if off + len > self.len {
Err(Error::input(Operation::Unlock, Input::InvalidRange))
} else {
unsafe {
let (ptr, len) = Size::page().bounds(self.ptr.add(off), len);
unlock(ptr, len)
}
}
}
}
impl FromPtr for MapMut {
unsafe fn from_ptr(ptr: *mut u8, len: usize) -> Self {
Self { ptr, len }
}
}
impl Span for MapMut {
#[inline]
fn len(&self) -> usize {
self.len
}
#[inline]
fn as_ptr(&self) -> *const u8 {
self.ptr
}
}
impl SpanMut for MapMut {
#[inline]
fn as_mut_ptr(&mut self) -> *mut u8 {
self.ptr
}
}
impl Drop for MapMut {
fn drop(&mut self) {
unsafe {
if self.len > 0 {
let (ptr, len) = Size::alloc().bounds(self.ptr, self.len);
unmap(ptr, len).unwrap_or_default();
}
}
}
}
impl Deref for MapMut {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.ptr, self.len) }
}
}
impl DerefMut for MapMut {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
}
}
impl AsRef<[u8]> for MapMut
where
<MapMut as Deref>::Target: AsRef<[u8]>,
{
#[inline]
fn as_ref(&self) -> &[u8] {
self.deref()
}
}
impl AsMut<[u8]> for MapMut
where
<MapMut as Deref>::Target: AsMut<[u8]>,
{
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.deref_mut()
}
}
impl TryFrom<Map> for MapMut {
type Error = (Error, Map);
fn try_from(map: Map) -> ConvertResult<Self, Map> {
map.into_map_mut()
}
}
pub struct Options<T: FromPtr> {
open_options: OpenOptions,
resize: Extent,
len: Extent,
offset: usize,
protect: Protect,
truncate: bool,
_marker: marker::PhantomData<fn() -> T>,
}
impl<T: FromPtr> Options<T> {
pub fn new() -> Self {
let mut open_options = OpenOptions::new();
open_options.read(true);
Self {
open_options,
resize: Extent::End,
len: Extent::End,
offset: 0,
protect: Protect::ReadOnly,
truncate: false,
_marker: marker::PhantomData,
}
}
pub fn write(&mut self) -> &mut Self {
self.open_options.write(true);
self.protect = Protect::ReadWrite;
self
}
pub fn copy(&mut self) -> &mut Self {
self.open_options.write(false);
self.protect = Protect::ReadCopy;
self
}
pub fn create(&mut self, create: bool) -> &mut Self {
self.open_options.create(create);
self
}
pub fn create_new(&mut self, create_new: bool) -> &mut Self {
self.open_options.create_new(create_new);
self
}
pub fn truncate(&mut self, truncate: bool) -> &mut Self {
self.open_options.truncate(truncate);
self.truncate = truncate;
self
}
pub fn offset(&mut self, offset: usize) -> &mut Self {
self.offset = offset;
self
}
pub fn len<E: Into<Extent>>(&mut self, value: E) -> &mut Self {
self.len = value.into();
self
}
pub fn resize<E: Into<Extent>>(&mut self, value: E) -> &mut Self {
self.resize = value.into();
self
}
pub fn open<P: AsRef<Path>>(&self, path: P) -> Result<(T, File)> {
let f = self.open_options.open(path).map_err(map_file_err)?;
Ok((self.map(&f)?, f))
}
pub fn open_if<P: AsRef<Path>>(&self, path: P) -> Result<(Option<T>, File)> {
let f = self.open_options.open(path).map_err(map_file_err)?;
Ok((self.map_if(&f)?, f))
}
pub fn map(&self, f: &File) -> Result<T> {
self.map_if(f)?
.ok_or_else(|| Error::input(Operation::MapFile, Input::InvalidRange))
}
pub fn map_if(&self, f: &File) -> Result<Option<T>> {
let off = self.offset;
let mut flen = f.metadata().map_err(map_file_err)?.len() as usize;
let resize = |sz: usize| f.set_len(sz as u64).map(|_| sz).map_err(map_file_err);
if self.truncate && flen > 0 {
flen = resize(0)?;
}
flen = match self.resize {
Extent::Exact(sz) => resize(sz)?,
Extent::Min(sz) if sz > flen => resize(sz)?,
Extent::Max(sz) if sz < flen => resize(sz)?,
_ => flen,
};
if flen < off {
return Ok(None);
}
let max = flen - off;
let len = match self.len {
Extent::Min(l) | Extent::Exact(l) if l > max => return Ok(None),
Extent::Min(_) | Extent::End => max,
Extent::Max(l) => cmp::min(l, max),
Extent::Exact(l) => l,
};
let mapoff = Size::alloc().truncate(off);
let maplen = len + (off - mapoff);
let ptr = map_file(f, mapoff, maplen, self.protect)?;
unsafe { Ok(Some(T::from_ptr(ptr.add(off - mapoff), len))) }
}
pub fn alloc(&self) -> Result<T> {
let off = Size::page().offset(self.offset);
let len = match self.len {
Extent::End => Size::alloc().round(off + 1) - off,
Extent::Min(l) => Size::alloc().round(off + l) - off,
Extent::Max(l) | Extent::Exact(l) => l,
};
let ptr = map_anon(off + len, self.protect)?;
unsafe { Ok(T::from_ptr(ptr.add(off), len)) }
}
}
impl<T: FromPtr> Default for Options<T> {
fn default() -> Self {
Self::new()
}
}
fn map_file_err(e: io::Error) -> Error {
Error::io(Operation::MapFile, e)
}