diff options
Diffstat (limited to 'safe_libc/src/boxed.rs')
-rw-r--r-- | safe_libc/src/boxed.rs | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/safe_libc/src/boxed.rs b/safe_libc/src/boxed.rs new file mode 100644 index 0000000..a0bbfb4 --- /dev/null +++ b/safe_libc/src/boxed.rs @@ -0,0 +1,78 @@ +use core::{marker, mem, ptr}; +use core::ops::{Deref, DerefMut}; + +pub trait Dealloc<T: ?Sized> { + unsafe fn dealloc(p: *mut T); +} + +#[repr(transparent)] +pub struct BoxLike<T: ?Sized, D: Dealloc<T>> { + inner: ptr::NonNull<T>, + _phantom: marker::PhantomData<T>, + _dropper: marker::PhantomData<D>, +} + +impl<T: ?Sized, D: Dealloc<T>> BoxLike<T, D> { + #[inline] + pub unsafe fn from_raw_unchecked(p: *mut T) -> Self { + BoxLike { + inner: ptr::NonNull::new_unchecked(p), + _phantom: marker::PhantomData, + _dropper: marker::PhantomData, + } + } + + #[inline] + pub unsafe fn from_raw(p: *mut T) -> Option<Self> { + if p.is_null() { + None + } else { + Some(Self::from_raw_unchecked(p)) + } + } + + #[inline] + pub fn into_raw(self) -> *mut T { + let p = self.inner.as_ptr(); + mem::forget(self); + p + } +} + +impl<T: ?Sized, D: Dealloc<T>> Drop for BoxLike<T, D> { + #[inline] + fn drop(&mut self) { + let p = self.inner.as_ptr(); + unsafe { + ptr::drop_in_place(p); + D::dealloc(p); + } + } +} + +impl<T: ?Sized, D: Dealloc<T>> Deref for BoxLike<T, D> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { self.inner.as_ref() } + } +} + +impl<T: ?Sized, D: Dealloc<T>> DerefMut for BoxLike<T, D> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { self.inner.as_mut() } + } +} + +pub struct DeallocFree; + +impl<T: ?Sized> Dealloc<T> for DeallocFree { + #[inline] + unsafe fn dealloc(p: *mut T) { + libc::free(p as _); + } +} + +pub type CBox<T> = BoxLike<T, DeallocFree>; |