use crate::{advise_free, alloc, clear, dealloc, protect, Error, Protection, Result};
use core::{
borrow::{Borrow, BorrowMut},
mem::forget,
ops::{Bound, RangeBounds},
ptr::{self, NonNull},
slice,
};
pub struct ByteBuffer {
ptr: NonNull<u8>,
size: usize,
}
unsafe impl Send for ByteBuffer {}
unsafe impl Sync for ByteBuffer {}
impl ByteBuffer {
pub fn new(size: usize, protection: Protection) -> Result<Self> {
let ptr = unsafe { alloc(ptr::null_mut(), size, protection)? };
Ok(Self { ptr, size })
}
#[inline(always)]
pub unsafe fn from_raw_parts(ptr: NonNull<u8>, size: usize) -> Self {
Self { ptr, size }
}
pub fn clear(&mut self, range: impl RangeBounds<usize>, protection: Protection) -> Result<()> {
let start = match range.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(start) => start + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(end) => end + 1,
Bound::Excluded(end) => *end,
Bound::Unbounded => self.size,
};
if start == end {
return Ok(());
}
if end > self.size {
return Err(Error::InvalidInput);
}
unsafe { clear(self.ptr.add(start), end - start, protection) }
}
pub fn protect(
&mut self,
range: impl RangeBounds<usize>,
protection: Protection,
) -> Result<()> {
let start = match range.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(start) => start + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(end) => end + 1,
Bound::Excluded(end) => *end,
Bound::Unbounded => self.size,
};
if start == end {
return Ok(());
}
if end > self.size {
return Err(Error::InvalidInput);
}
unsafe { protect(self.ptr.add(start), end - start, protection) }
}
pub fn advise_free(&mut self, range: impl RangeBounds<usize>) -> Result<()> {
let start = match range.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(start) => start + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(end) => end + 1,
Bound::Excluded(end) => *end,
Bound::Unbounded => self.size,
};
if start == end {
return Ok(());
}
if end > self.size {
return Err(Error::InvalidInput);
}
unsafe { advise_free(self.ptr.add(start), end - start) }
}
#[inline(always)]
pub fn into_raw_parts(self) -> (NonNull<u8>, usize) {
let ptr = self.ptr;
let size = self.size;
forget(self);
(ptr, size)
}
#[inline(always)]
pub fn get(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.size) }
}
#[inline(always)]
pub fn get_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.size) }
}
#[inline(always)]
pub fn get_raw(&self) -> NonNull<[u8]> {
NonNull::slice_from_raw_parts(self.ptr, self.size)
}
}
impl AsRef<[u8]> for ByteBuffer {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.get()
}
}
impl Borrow<[u8]> for ByteBuffer {
#[inline(always)]
fn borrow(&self) -> &[u8] {
self.get()
}
}
impl AsMut<[u8]> for ByteBuffer {
#[inline(always)]
fn as_mut(&mut self) -> &mut [u8] {
self.get_mut()
}
}
impl BorrowMut<[u8]> for ByteBuffer {
#[inline(always)]
fn borrow_mut(&mut self) -> &mut [u8] {
self.get_mut()
}
}
impl Drop for ByteBuffer {
fn drop(&mut self) {
unsafe {
let _ = dealloc(self.ptr, self.size);
}
}
}