use std::fs::File;
use std::os::fd::AsRawFd;
pub struct MappedFileMut {
inner: MappedFile,
}
impl MappedFileMut {
pub fn from_existing_file(file: File) -> std::io::Result<Self> {
MappedFile::from_existing_file_ext(
file,
libc::MAP_SHARED,
libc::PROT_READ | libc::PROT_WRITE,
)
.map(|inner| Self { inner })
}
pub fn length(&self) -> usize {
self.inner.length
}
pub unsafe fn read_exact_at(&self, offset: usize, buffer: &mut [u8]) {
unsafe {
std::ptr::copy_nonoverlapping(
self.inner.ptr.cast::<u8>().add(offset),
buffer.as_mut_ptr(),
buffer.len(),
);
}
}
pub unsafe fn write_all_at(&mut self, offset: usize, buffer: &[u8]) {
unsafe {
std::ptr::copy_nonoverlapping(
buffer.as_ptr(),
self.inner.ptr.cast::<u8>().add(offset),
buffer.len(),
);
}
}
pub fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.inner.ptr.cast::<u8>(), self.inner.length) }
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.inner.ptr.cast::<u8>(), self.inner.length) }
}
}
impl AsRef<MappedFile> for MappedFileMut {
fn as_ref(&self) -> &MappedFile {
&self.inner
}
}
impl AsRef<[u8]> for MappedFileMut {
fn as_ref(&self) -> &[u8] {
self.inner.as_slice()
}
}
impl AsMut<[u8]> for MappedFileMut {
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_slice()
}
}
impl std::ops::Deref for MappedFileMut {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.inner.as_slice()
}
}
impl std::ops::DerefMut for MappedFileMut {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
pub struct MappedFile {
length: usize,
ptr: *mut libc::c_void,
}
impl MappedFile {
pub fn from_existing_file(file: File) -> std::io::Result<Self> {
Self::from_existing_file_ext(file, libc::MAP_PRIVATE, libc::PROT_READ)
}
fn from_existing_file_ext(
file: File,
flags: libc::c_int,
prot: libc::c_int,
) -> std::io::Result<Self> {
let length = file.metadata()?.len() as usize;
let ptr = unsafe {
libc::mmap(
std::ptr::null_mut(),
length,
prot,
flags,
file.as_raw_fd(),
0,
)
};
if ptr == libc::MAP_FAILED {
return Err(std::io::Error::last_os_error());
}
if unsafe { libc::madvise(ptr, length, libc::MADV_RANDOM) } != 0 {
return Err(std::io::Error::last_os_error());
}
Ok(Self { length, ptr })
}
pub fn length(&self) -> usize {
self.length
}
pub unsafe fn read_exact_at(&self, offset: usize, buffer: &mut [u8]) {
unsafe {
std::ptr::copy_nonoverlapping(
self.ptr.cast::<u8>().add(offset),
buffer.as_mut_ptr(),
buffer.len(),
);
}
}
pub fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.ptr.cast::<u8>(), self.length) }
}
}
impl AsRef<[u8]> for MappedFile {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl std::ops::Deref for MappedFile {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl Drop for MappedFile {
fn drop(&mut self) {
if unsafe { libc::munmap(self.ptr, self.length) } != 0 {
panic!("failed to unmap file: {}", std::io::Error::last_os_error());
}
}
}
unsafe impl Send for MappedFile {}
unsafe impl Sync for MappedFile {}