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#[cfg(test)]
94mod tests {
95 use super::*;
96 use core::ffi::c_void;
97 use core::sync::atomic::{AtomicBool, Ordering};
98 use kalloc::Box;
99 use zr::Opaque;
100 extern crate alloc;
101 use alloc::sync::Arc;
102
103 #[derive(fbl::Recyclable)]
104 pub struct TestRustObject {
105 destroyed: Arc<AtomicBool>,
106 }
107
108 impl Drop for TestRustObject {
109 fn drop(&mut self) {
110 self.destroyed.store(true, Ordering::Relaxed);
111 }
112 }
113
114 #[test]
115 fn test_unique_ptr_drops() {
116 let destroyed = Arc::new(AtomicBool::new(false));
117 {
118 let obj = TestRustObject { destroyed: destroyed.clone() };
119 let _unique_ptr = UniquePtr::try_new(obj).unwrap();
120 assert!(!destroyed.load(Ordering::Relaxed));
121 } assert!(destroyed.load(Ordering::Relaxed));
124 }
125
126 #[test]
127 fn test_unique_ptr_into_raw() {
128 let destroyed = Arc::new(AtomicBool::new(false));
129 let raw_ptr;
130 {
131 let obj = TestRustObject { destroyed: destroyed.clone() };
132 let unique_ptr = UniquePtr::try_new(obj).unwrap();
133 assert!(!destroyed.load(Ordering::Relaxed));
134 raw_ptr = UniquePtr::into_raw(unique_ptr);
135 } assert!(!destroyed.load(Ordering::Relaxed));
138
139 unsafe {
141 drop(Box::from_raw(raw_ptr));
142 }
143 assert!(destroyed.load(Ordering::Relaxed));
144 }
145
146 unsafe extern "C" {
147 fn create_cpp_object(destroyed: *mut bool) -> *mut c_void;
148 fn destroy_cpp_object(ptr: *mut c_void);
149 }
150
151 pub struct TestCppObject;
152
153 unsafe impl Recyclable for Opaque<TestCppObject> {
154 unsafe fn recycle(ptr: NonNull<Self>) {
155 unsafe {
156 destroy_cpp_object(ptr.as_ptr() as *mut c_void);
157 }
158 }
159
160 fn allocate(_value: Self) -> Result<NonNull<Self>, AllocError> {
161 Err(AllocError)
162 }
163 }
164
165 #[test]
166 #[cfg_attr(miri, ignore = "miri does not support calling foreign functions")]
167 fn test_unique_ptr_cpp_drops() {
168 let destroyed = AtomicBool::new(false);
169 unsafe {
170 let raw_ptr = create_cpp_object(destroyed.as_ptr() as *mut bool);
171 assert!(!destroyed.load(Ordering::Relaxed));
172 {
173 let _unique_ptr = UniquePtr::from_raw(raw_ptr as *mut Opaque<TestCppObject>);
174 assert!(!destroyed.load(Ordering::Relaxed));
175 } assert!(destroyed.load(Ordering::Relaxed));
178 }
179 }
180
181 #[test]
182 fn test_unique_ptr_as_mut_ptr() {
183 let destroyed = Arc::new(AtomicBool::new(false));
184 let mut unique_ptr =
185 UniquePtr::try_new(TestRustObject { destroyed: destroyed.clone() }).unwrap();
186 let mut_ptr = UniquePtr::as_mut_ptr(&mut unique_ptr);
187 assert!(!mut_ptr.is_null());
188 }
189
190 #[test]
191 fn test_unique_ptr_deref_mut() {
192 let destroyed = Arc::new(AtomicBool::new(false));
193 let mut unique_ptr =
194 UniquePtr::try_new(TestRustObject { destroyed: destroyed.clone() }).unwrap();
195 let _deref_mut: &mut TestRustObject = &mut unique_ptr;
196 }
197
198 #[test]
199 fn test_unique_ptr_cpp_alloc_fail() {
200 let dummy_val = Opaque::uninit();
201 let res = Opaque::<TestCppObject>::allocate(dummy_val);
202 assert!(res.is_err());
203 }
204}