use core::{
fmt,
fmt::{Debug, Display},
slice,
};
use region::{Allocation, Protection};
#[derive(Debug)]
pub enum VirtualMemoryError {
Region(region::Error),
AllocationOutOfBounds,
}
impl From<region::Error> for VirtualMemoryError {
#[inline]
fn from(error: region::Error) -> Self {
Self::Region(error)
}
}
impl Display for VirtualMemoryError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Region(error) => write!(
f,
"encountered failure while operating with virtual memory: {}",
error
),
Self::AllocationOutOfBounds => write!(f, "virtual memory allocation is too big"),
}
}
}
pub struct VirtualMemory {
allocation: Allocation,
}
impl Debug for VirtualMemory {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VirtualMemory")
.field("len", &self.allocation.len())
.finish()
}
}
unsafe impl Sync for VirtualMemory {}
unsafe impl Send for VirtualMemory {}
impl VirtualMemory {
const MAX_ALLOCATION_SIZE: usize = u32::MAX as usize;
pub fn new(len: usize) -> Result<Self, VirtualMemoryError> {
assert_ne!(len, 0, "cannot allocate empty virtual memory");
if len > Self::MAX_ALLOCATION_SIZE {
return Err(VirtualMemoryError::AllocationOutOfBounds);
}
let allocation = region::alloc(len, Protection::READ_WRITE)?;
Ok(Self { allocation })
}
#[inline]
pub fn data(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.allocation.as_ptr(), self.allocation.len()) }
}
#[inline]
pub fn data_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.allocation.as_mut_ptr(), self.allocation.len()) }
}
}