1use crate::recyclable::Recyclable;
8use core::ops::{Deref, DerefMut};
9use core::ptr::NonNull;
10use kalloc::AllocError;
11
12#[repr(C)]
19pub struct UniquePtr<T>
20where
21 T: Recyclable,
22{
23 ptr: NonNull<T>,
24}
25
26impl<T: Recyclable> UniquePtr<T> {
27 pub unsafe fn from_raw(ptr: *mut T) -> Self {
35 unsafe { UniquePtr { ptr: NonNull::new_unchecked(ptr) } }
37 }
38
39 pub fn try_new(value: T) -> Result<UniquePtr<T>, AllocError> {
45 let ptr = T::allocate(value)?;
46 Ok(UniquePtr { ptr })
47 }
48
49 pub fn as_ptr(this: &Self) -> *const T {
51 this.ptr.as_ptr()
52 }
53
54 pub fn as_mut_ptr(this: &mut Self) -> *mut T {
56 this.ptr.as_ptr()
57 }
58
59 pub fn into_raw(this: Self) -> *mut T {
63 let ptr = this.ptr.as_ptr();
64 core::mem::forget(this);
65 ptr
66 }
67}
68
69impl<T: Recyclable> Deref for UniquePtr<T> {
70 type Target = T;
71 fn deref(&self) -> &Self::Target {
72 unsafe { self.ptr.as_ref() }
73 }
74}
75
76impl<T: Recyclable> DerefMut for UniquePtr<T> {
77 fn deref_mut(&mut self) -> &mut Self::Target {
78 unsafe { self.ptr.as_mut() }
79 }
80}
81
82impl<T: Recyclable> Drop for UniquePtr<T> {
83 fn drop(&mut self) {
84 unsafe {
85 T::recycle(self.ptr);
86 }
87 }
88}
89
90unsafe impl<T: Recyclable + Send> Send for UniquePtr<T> {}
91unsafe impl<T: Recyclable + Sync> Sync for UniquePtr<T> {}
92
93#[macro_export]
96macro_rules! impl_opaque_unique_facade {
97 (
98 $(#[$meta:meta])*
99 $vis:vis struct $name:ident,
100 $destroy_fn:path $(,)?
101 ) => {
102 $(#[$meta])*
103 #[repr(C)]
104 $vis struct $name {
105 _facade: $crate::OpaqueFacade,
106 }
107
108 unsafe impl $crate::Recyclable for $name {
110 unsafe fn recycle(ptr: core::ptr::NonNull<Self>) {
111 unsafe {
113 $destroy_fn(ptr.as_ptr() as *mut Self);
114 }
115 }
116 }
117 };
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use core::ffi::c_void;
124 use core::sync::atomic::{AtomicBool, Ordering};
125 use kalloc::Box;
126 use zr::Opaque;
127 extern crate alloc;
128 use alloc::sync::Arc;
129
130 #[derive(fbl::Recyclable)]
131 pub struct TestRustObject {
132 destroyed: Arc<AtomicBool>,
133 }
134
135 impl Drop for TestRustObject {
136 fn drop(&mut self) {
137 self.destroyed.store(true, Ordering::Relaxed);
138 }
139 }
140
141 #[test]
142 fn test_unique_ptr_drops() {
143 let destroyed = Arc::new(AtomicBool::new(false));
144 {
145 let obj = TestRustObject { destroyed: destroyed.clone() };
146 let _unique_ptr = UniquePtr::try_new(obj).unwrap();
147 assert!(!destroyed.load(Ordering::Relaxed));
148 } assert!(destroyed.load(Ordering::Relaxed));
151 }
152
153 #[test]
154 fn test_unique_ptr_into_raw() {
155 let destroyed = Arc::new(AtomicBool::new(false));
156 let raw_ptr;
157 {
158 let obj = TestRustObject { destroyed: destroyed.clone() };
159 let unique_ptr = UniquePtr::try_new(obj).unwrap();
160 assert!(!destroyed.load(Ordering::Relaxed));
161 raw_ptr = UniquePtr::into_raw(unique_ptr);
162 } assert!(!destroyed.load(Ordering::Relaxed));
165
166 unsafe {
168 drop(Box::from_raw(raw_ptr));
169 }
170 assert!(destroyed.load(Ordering::Relaxed));
171 }
172
173 unsafe extern "C" {
174 fn create_cpp_object(destroyed: *mut bool) -> *mut c_void;
175 fn destroy_cpp_object(ptr: *mut c_void);
176 }
177
178 pub struct TestCppObject;
179
180 unsafe impl Recyclable for Opaque<TestCppObject> {
181 unsafe fn recycle(ptr: NonNull<Self>) {
182 unsafe {
183 destroy_cpp_object(ptr.as_ptr() as *mut c_void);
184 }
185 }
186 }
187
188 #[test]
189 #[cfg_attr(miri, ignore = "miri does not support calling foreign functions")]
190 fn test_unique_ptr_cpp_drops() {
191 let destroyed = AtomicBool::new(false);
192 unsafe {
193 let raw_ptr = create_cpp_object(destroyed.as_ptr() as *mut bool);
194 assert!(!destroyed.load(Ordering::Relaxed));
195 {
196 let _unique_ptr = UniquePtr::from_raw(raw_ptr as *mut Opaque<TestCppObject>);
197 assert!(!destroyed.load(Ordering::Relaxed));
198 } assert!(destroyed.load(Ordering::Relaxed));
201 }
202 }
203
204 #[test]
205 fn test_unique_ptr_as_mut_ptr() {
206 let destroyed = Arc::new(AtomicBool::new(false));
207 let mut unique_ptr =
208 UniquePtr::try_new(TestRustObject { destroyed: destroyed.clone() }).unwrap();
209 let mut_ptr = UniquePtr::as_mut_ptr(&mut unique_ptr);
210 assert!(!mut_ptr.is_null());
211 }
212
213 #[test]
214 fn test_unique_ptr_deref_mut() {
215 let destroyed = Arc::new(AtomicBool::new(false));
216 let mut unique_ptr =
217 UniquePtr::try_new(TestRustObject { destroyed: destroyed.clone() }).unwrap();
218 let _deref_mut: &mut TestRustObject = &mut unique_ptr;
219 }
220
221 #[test]
222 fn test_unique_ptr_cpp_alloc_fail() {
223 let dummy_val = Opaque::uninit();
224 let res = Opaque::<TestCppObject>::allocate(dummy_val);
225 assert!(res.is_err());
226 }
227}