summaryrefslogtreecommitdiffstats
path: root/safe_libc/src/boxed.rs
diff options
context:
space:
mode:
Diffstat (limited to 'safe_libc/src/boxed.rs')
-rw-r--r--safe_libc/src/boxed.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/safe_libc/src/boxed.rs b/safe_libc/src/boxed.rs
new file mode 100644
index 0000000..72c961c
--- /dev/null
+++ b/safe_libc/src/boxed.rs
@@ -0,0 +1,146 @@
+use crate::util;
+
+use core::{mem, ptr};
+use core::ops::{Deref, DerefMut};
+
+fn alloc<T>(len: usize) -> *mut T {
+ if util::zst::<T>(len) {
+ return ptr::null_mut();
+ }
+ let size = len.checked_mul(mem::size_of::<T>()).expect("allocation overflow");
+ let align = mem::align_of::<T>();
+ util::must_succeed(
+ unsafe {
+ libc::memalign(align as libc::size_t, size as libc::size_t) as *mut T
+ }
+ )
+}
+
+#[inline]
+fn dangling<T>() -> *mut T {
+ mem::align_of::<T>() as *mut T
+}
+
+#[inline]
+fn slice_len<T>(p: *const [T]) -> usize {
+ unsafe { mem::transmute::<*const [T], [usize; 2]>(p)[1] }
+}
+
+pub struct CBox<T: ?Sized>(*mut T);
+
+impl<T: ?Sized> CBox<T> {
+ #[inline]
+ pub unsafe fn from_raw_unchecked(p: *mut T) -> CBox<T> {
+ CBox(p)
+ }
+
+ #[inline]
+ pub fn into_raw(self) -> *mut T {
+ let p = self.0;
+ mem::forget(self);
+ p
+ }
+
+ #[inline]
+ pub fn as_ptr(&self) -> *const T {
+ self.0
+ }
+
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self.0
+ }
+}
+
+impl<T> CBox<T> {
+ #[inline]
+ pub fn new(value: T) -> CBox<T> {
+ let p = alloc(1);
+ unsafe {
+ ptr::write(p, value);
+ CBox::from_raw_unchecked(p)
+ }
+ }
+
+ #[inline]
+ pub unsafe fn from_raw(p: *mut T) -> CBox<T> {
+ util::check_ptr(p, 1);
+ CBox(p)
+ }
+
+ #[inline]
+ pub unsafe fn slice_from_raw_parts_unchecked(p: *mut T, len: usize) -> CBox<[T]> {
+ CBox(ptr::slice_from_raw_parts_mut(p, len))
+ }
+
+ #[inline]
+ pub unsafe fn slice_from_raw_parts(p: *mut T, len: usize) -> CBox<[T]> {
+ util::check_ptr(p, len);
+ CBox::slice_from_raw_parts_unchecked(p, len)
+ }
+
+ #[inline]
+ fn safe_ptr(&self) -> *mut T {
+ if util::zst::<T>(1) {
+ return dangling();
+ }
+
+ debug_assert!(!self.0.is_null(), "NULL ptr");
+ self.0
+ }
+}
+
+impl<T> CBox<[T]> {
+ #[inline]
+ fn safe_ptr(&self) -> *mut [T] {
+ if self.0.is_null() {
+ let len = slice_len(self.0);
+ debug_assert!(util::zst::<T>(len), "NULL ptr");
+ return ptr::slice_from_raw_parts_mut(dangling(), len);
+ }
+
+ self.0
+ }
+}
+
+impl<T: ?Sized> Drop for CBox<T> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ ptr::drop_in_place(self.0);
+ libc::free(self.0 as *mut libc::c_void);
+ }
+ }
+}
+
+impl<T> Deref for CBox<T> {
+ type Target = T;
+
+ #[inline]
+ fn deref(&self) -> &T {
+ unsafe { &*self.safe_ptr() }
+ }
+}
+
+impl<T> DerefMut for CBox<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.safe_ptr() }
+ }
+}
+
+impl<T> Deref for CBox<[T]> {
+ type Target = [T];
+
+ #[inline]
+ fn deref(&self) -> &[T] {
+ unsafe { &*self.safe_ptr() }
+ }
+}
+
+impl<T> DerefMut for CBox<[T]> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut [T] {
+ unsafe { &mut *self.safe_ptr() }
+ }
+}