summaryrefslogtreecommitdiffstats
path: root/safe_libc/src/boxed.rs
blob: a0bbfb48ce1cf801acea1f4da42694fe62e1f24c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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>;