use alloc::vec::Vec;
use core::{any::TypeId, marker::PhantomData, mem, ops::Deref, ptr, slice};
pub trait Ownership: 'static {}
impl Ownership for Borrowed {}
impl Ownership for Owned {}
pub struct Borrowed;
pub struct Owned;
#[repr(C)]
pub struct Region<O: Ownership> {
pub offset: u32,
pub capacity: u32,
pub length: u32,
_marker: PhantomData<O>,
}
const _: () = {
assert!(mem::size_of::<Region<Borrowed>>() == 12);
assert!(mem::size_of::<Region<Owned>>() == 12);
};
impl Region<Borrowed> {
pub fn from_slice(slice: &[u8]) -> Self {
unsafe {
let ptr: ptr::NonNull<u8> = ptr::NonNull::from(slice).cast();
Self::from_parts(ptr, slice.len(), slice.len())
}
}
}
impl Region<Owned> {
pub fn from_vec(mut vec: Vec<u8>) -> Self {
let region = unsafe {
let ptr = ptr::NonNull::new_unchecked(vec.as_mut_ptr());
Self::from_parts(ptr, vec.capacity(), vec.len())
};
mem::forget(vec);
region
}
pub unsafe fn from_heap_ptr(ptr: ptr::NonNull<Self>) -> Box<Self> {
Box::from_raw(ptr.as_ptr())
}
pub fn with_capacity(cap: usize) -> Self {
let data = Vec::with_capacity(cap);
let region = Self::from_vec(data);
region
}
pub fn into_vec(self) -> Vec<u8> {
let vector = unsafe {
Vec::from_raw_parts(
self.offset as *mut u8,
self.length as usize,
self.capacity as usize,
)
};
mem::forget(self);
vector
}
}
impl<O> Region<O>
where
O: Ownership,
{
unsafe fn from_parts(ptr: ptr::NonNull<u8>, capacity: usize, length: usize) -> Self {
Region {
offset: u32::try_from(ptr.as_ptr() as usize).expect("pointer doesn't fit in u32"),
capacity: u32::try_from(capacity).expect("capacity doesn't fit in u32"),
length: u32::try_from(length).expect("length doesn't fit in u32"),
_marker: PhantomData,
}
}
pub fn as_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.offset as *const u8, self.length as usize) }
}
pub fn as_ptr(&self) -> *const Self {
self
}
pub fn to_heap_ptr(self) -> *mut Self {
let boxed = Box::new(self);
Box::into_raw(boxed)
}
}
impl<O> Deref for Region<O>
where
O: Ownership,
{
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_bytes()
}
}
impl<O> Drop for Region<O>
where
O: Ownership,
{
fn drop(&mut self) {
if TypeId::of::<O>() == TypeId::of::<Owned>() {
let region_start = ptr::NonNull::new(self.offset as *mut u8).unwrap();
unsafe {
let data = Vec::from_raw_parts(
region_start.as_ptr(),
self.length as usize,
self.capacity as usize,
);
drop(data);
}
}
}
}
#[cfg(feature = "iterator")]
pub fn get_optional_region_address<O: Ownership>(region: &Option<&Region<O>>) -> u32 {
region.map(|r| r.as_ptr() as u32).unwrap_or(0)
}