Skip to main content

value_box/
value_box.rs

1use std::any::{type_name, Any};
2use std::ffi::c_void;
3use std::mem::size_of;
4use std::ptr::NonNull;
5
6use crate::{BoxerError, Result, ReturnBoxerResult};
7
8
9#[repr(transparent)]
10pub struct ValueBox<T: Any> {
11    value: T,
12}
13
14impl<T: Any> ValueBox<T> {
15    pub fn new(object: T) -> Self {
16        Self { value: object }
17    }
18
19    pub fn has_value(&self) -> bool {
20        true
21    }
22
23    pub fn replace_value(&mut self, object: T) -> T {
24        std::mem::replace(&mut self.value, object)
25    }
26
27    pub fn set_value(&mut self, object: T) {
28        self.value = object;
29    }
30
31    pub fn clone_value(&self) -> T
32    where
33        T: Clone,
34    {
35        self.value.clone()
36    }
37
38    pub fn into_value(self) -> T {
39        self.value
40    }
41
42    pub fn into_raw(self) -> *mut Self {
43        let ptr: *mut T = into_raw(Box::new(self.value));
44        ptr.cast()
45    }
46
47    pub fn into_erased_raw(self) -> *mut ErasedValueBox {
48        self.into_raw().cast()
49    }
50}
51
52impl<T: Any> AsRef<T> for ValueBox<T> {
53    fn as_ref(&self) -> &T {
54        &self.value
55    }
56}
57
58impl<T: Any> AsMut<T> for ValueBox<T> {
59    fn as_mut(&mut self) -> &mut T {
60        &mut self.value
61    }
62}
63
64#[repr(C)]
65pub struct ErasedValueBox {
66    _private: [u8; 0],
67}
68
69pub trait ErasedValueBoxPointer {
70    /// Evaluate a given function with a non-null pointer to the boxed value.
71    /// The pointer must not outlive the closure.
72    fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
73    where
74        F: FnOnce(NonNull<c_void>) -> Result<R>;
75
76    /// Evaluate a given function with a non-null pointer to the boxed value.
77    /// The pointer must not outlive the closure.
78    fn with_ptr_ok<R: Any, F>(&self, op: F) -> Result<R>
79    where
80        F: FnOnce(NonNull<c_void>) -> R,
81    {
82        self.with_ptr(|pointer| Ok(op(pointer)))
83    }
84}
85
86pub trait ValueBoxPointer<T: Any> {
87    /// Take the value out of the box.
88    fn take_value(&self) -> Result<T>;
89
90    /// Erase the concrete value type while keeping the same raw pointer.
91    fn erase(self) -> *mut ErasedValueBox;
92
93    /// Evaluate a given function with a reference to the boxed value.
94    /// The reference can not outlive the closure.
95    fn with_ref<R: Any, F>(&self, op: F) -> Result<R>
96    where
97        F: FnOnce(&T) -> Result<R>;
98
99    /// Try to unbox the value and evaluate a given function with either Some
100    /// if the value was there or None if the pointer was a null pointer.
101    /// Returns an error if the value box wasn't a null pointer, but the boxed value
102    /// was already taken or of the wrong type.
103    fn with_option_ref<R: Any, F>(&self, op: F) -> Result<R>
104    where
105        F: FnOnce(Option<&T>) -> Result<R>,
106    {
107        if self.has_value() {
108            self.with_ref(|value| op(Some(value)))
109        } else {
110            op(None)
111        }
112    }
113
114    /// Evaluate a given function with a reference to the boxed value.
115    /// The the reference can not outlive the closure.
116    fn with_ref_ok<R: Any, F>(&self, op: F) -> Result<R>
117    where
118        F: FnOnce(&T) -> R,
119    {
120        self.with_ref(|value| Ok(op(value)))
121    }
122
123    /// Evaluate a given function with a mutable reference to the boxed value.
124    /// The lifetime of the reference can not outlive the closure.
125    fn with_mut<R: Any, F>(&self, op: F) -> Result<R>
126    where
127        F: FnOnce(&mut T) -> Result<R>;
128
129    /// Evaluate a given function that can not fail with a mutable reference to the boxed value.
130    /// The lifetime of the reference can not outlive the closure.
131    fn with_mut_ok<R: Any, F>(&self, op: F) -> Result<R>
132    where
133        F: FnOnce(&mut T) -> R,
134    {
135        self.with_mut(|value| Ok(op(value)))
136    }
137
138    /// Evaluate a given function with a clone of the boxed value.
139    /// The boxed type `T` must implement [`Clone`].
140    fn with_clone<R: Any, F>(&self, op: F) -> Result<R>
141    where
142        F: FnOnce(T) -> Result<R>,
143        T: Clone,
144    {
145        self.with_ref(|value| op(value.clone()))
146    }
147
148    /// Evaluate a given function with a clone of the boxed value.
149    /// The boxed type `T` must implement [`Clone`].
150    fn with_clone_ok<R: Any, F>(&self, op: F) -> Result<R>
151    where
152        F: FnOnce(T) -> R,
153        T: Clone,
154    {
155        self.with_clone(|value| Ok(op(value)))
156    }
157
158    /// Evaluate a given function with references to given boxed values.
159    /// The lifetime of the reference can not outlive the closure.
160    fn with_ref_ref<R: Any, F, P: Any>(&self, ptr: *mut ValueBox<P>, op: F) -> Result<R>
161    where
162        F: FnOnce(&T, &P) -> Result<R>,
163    {
164        self.with_ref(|t| ptr.with_ref(|p| op(t, p)))
165    }
166
167    /// Evaluate a given function with references to given boxed values.
168    /// The lifetime of the reference can not outlive the closure.
169    fn with_ref_ref_ref<R: Any, F, P1: Any, P2: Any>(
170        &self,
171        ptr1: *mut ValueBox<P1>,
172        ptr2: *mut ValueBox<P2>,
173        op: F,
174    ) -> Result<R>
175    where
176        F: FnOnce(&T, &P1, &P2) -> Result<R>,
177    {
178        self.with_ref(|t| ptr1.with_ref(|p1| ptr2.with_ref(|p2| op(t, p1, p2))))
179    }
180
181    /// Evaluate a given function with references to given boxed values.
182    /// The lifetime of the reference can not outlive the closure.
183    fn with_ref_ref_ref_ref<R: Any, F, P1: Any, P2: Any, P3: Any>(
184        &self,
185        ptr1: *mut ValueBox<P1>,
186        ptr2: *mut ValueBox<P2>,
187        ptr3: *mut ValueBox<P3>,
188        op: F,
189    ) -> Result<R>
190    where
191        F: FnOnce(&T, &P1, &P2, &P3) -> Result<R>,
192    {
193        self.with_ref(|t| {
194            ptr1.with_ref(|p1| ptr2.with_ref(|p2| ptr3.with_ref(|p3| op(t, p1, p2, p3))))
195        })
196    }
197
198    /// Evaluate a given function with the value taken out of the box
199    /// and place the new value back. The value returned by the function
200    /// must be of the same type as the box
201    fn replace_value<F>(&self, op: F) -> Result<()>
202    where
203        F: FnOnce(T) -> T;
204
205    fn release(self);
206
207    fn has_value(&self) -> bool {
208        self.with_ref_ok(|_| ()).is_ok()
209    }
210
211    #[deprecated(since = "0.1.0", note = "please use `has_value` instead")]
212    fn is_valid(&self) -> bool {
213        self.has_value()
214    }
215
216    #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
217    fn with_not_null<Block>(&self, block: Block)
218    where
219        Block: FnOnce(&mut T),
220    {
221        self.with_mut_ok(|value| block(value)).log();
222    }
223
224    #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
225    fn with_not_null_return<Block, Return: Any>(&self, default: Return, block: Block) -> Return
226    where
227        Block: FnOnce(&mut T) -> Return,
228    {
229        self.with_mut_ok(|value| block(value)).or_log(default)
230    }
231
232    #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
233    fn with_value<DefaultBlock, Block, Return: Any>(
234        &self,
235        default: DefaultBlock,
236        block: Block,
237    ) -> Return
238    where
239        DefaultBlock: FnOnce() -> Return,
240        Block: FnOnce(T) -> Return,
241        T: Clone,
242    {
243        self.with_clone_ok(block).unwrap_or_else(|_| default())
244    }
245
246    #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
247    fn with_not_null_value<Block>(&self, block: Block)
248    where
249        Block: FnOnce(T),
250        T: Clone,
251    {
252        self.with_ref_ok(|value| block(value.clone())).log();
253    }
254
255    #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
256    fn with_not_null_value_return<Block, Return: Any>(
257        &self,
258        default: Return,
259        block: Block,
260    ) -> Return
261    where
262        Block: FnOnce(T) -> Return,
263        T: Clone,
264    {
265        self.with_ref_ok(|reference| block(reference.clone()))
266            .unwrap_or(default)
267    }
268}
269
270impl<T: Any> ValueBoxPointer<T> for *mut ValueBox<T> {
271    fn take_value(&self) -> Result<T> {
272        if self.is_null() {
273            return BoxerError::NullPointer(type_name::<T>().to_string()).into();
274        }
275
276        let value_box = unsafe { *from_raw(*self) };
277        Ok(value_box.into_value())
278    }
279
280    fn erase(self) -> *mut ErasedValueBox {
281        self.cast()
282    }
283
284    fn with_ref<R: Any, F>(&self, op: F) -> Result<R>
285    where
286        F: FnOnce(&T) -> Result<R>,
287    {
288        if self.is_null() {
289            return BoxerError::NullPointer(type_name::<T>().to_string()).into();
290        }
291
292        unsafe { op(&(**self).value) }
293    }
294
295    fn with_mut<R: Any, F>(&self, op: F) -> Result<R>
296    where
297        F: FnOnce(&mut T) -> Result<R>,
298    {
299        if self.is_null() {
300            return BoxerError::NullPointer(type_name::<T>().to_string()).into();
301        }
302
303        unsafe { op(&mut (**self).value) }
304    }
305
306    fn replace_value<F>(&self, op: F) -> Result<()>
307    where
308        F: FnOnce(T) -> T,
309    {
310        if self.is_null() {
311            return BoxerError::NullPointer(type_name::<T>().to_string()).into();
312        }
313
314        let value = unsafe { &mut (**self).value };
315        let guard = AbortOnPanic;
316        let previous_value = unsafe { std::ptr::read(value) };
317        let new_value = op(previous_value);
318        unsafe { std::ptr::write(value, new_value) };
319        std::mem::forget(guard);
320        Ok(())
321    }
322
323    #[allow(clippy::not_unsafe_ptr_arg_deref)]
324    fn release(self) {
325        let result = if self.is_null() {
326            BoxerError::NullPointer(type_name::<T>().to_string()).into()
327        } else {
328            unsafe { Ok(from_raw(self)) }
329        };
330        result.log();
331    }
332
333    fn has_value(&self) -> bool {
334        !self.is_null()
335    }
336}
337
338impl<T: Any> ErasedValueBoxPointer for *mut ValueBox<T> {
339    fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
340    where
341        F: FnOnce(NonNull<c_void>) -> Result<R>,
342    {
343        if self.is_null() {
344            return BoxerError::NullPointer(type_name::<T>().to_string()).into();
345        }
346
347        let pointer = NonNull::new((*self).cast::<c_void>())
348            .expect("nonnull pointer must be available after null check");
349        op(pointer)
350    }
351}
352
353impl ErasedValueBoxPointer for *mut ErasedValueBox {
354    fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
355    where
356        F: FnOnce(NonNull<c_void>) -> Result<R>,
357    {
358        if self.is_null() {
359            return BoxerError::NullPointer("erased value box".to_string()).into();
360        }
361
362        let pointer = NonNull::new((*self).cast::<c_void>())
363            .expect("nonnull pointer must be available after null check");
364        op(pointer)
365    }
366}
367
368impl ErasedValueBoxPointer for *const ErasedValueBox {
369    fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
370    where
371        F: FnOnce(NonNull<c_void>) -> Result<R>,
372    {
373        if self.is_null() {
374            return BoxerError::NullPointer("erased value box".to_string()).into();
375        }
376
377        let pointer = NonNull::new((*self).cast_mut().cast::<c_void>())
378            .expect("nonnull pointer must be available after null check");
379        op(pointer)
380    }
381}
382
383/// Tell Rust to take back the control over memory
384/// This is dangerous! Rust takes control over the memory back
385///
386/// # Safety
387///
388/// `pointer` must come from [`Box::into_raw`] for the same `T`, must not be
389/// null, and must not have already been reclaimed.
390pub unsafe fn from_raw<T>(pointer: *mut T) -> Box<T> {
391    assert!(!pointer.is_null(), "from_raw(): Pointer must not be null!");
392    assert_eq!(
393        size_of::<*mut T>(),
394        size_of::<*mut std::ffi::c_void>(),
395        "The pointer must be compatible with void*"
396    );
397    unsafe { Box::from_raw(pointer) }
398}
399
400pub fn into_raw<T>(_box: Box<T>) -> *mut T {
401    assert_eq!(
402        size_of::<*mut T>(),
403        size_of::<*mut std::ffi::c_void>(),
404        "The pointer must be compatible with void*"
405    );
406    Box::into_raw(_box)
407}
408
409struct AbortOnPanic;
410
411impl Drop for AbortOnPanic {
412    fn drop(&mut self) {
413        if std::thread::panicking() {
414            std::process::abort();
415        }
416    }
417}
418
419#[cfg(test)]
420mod test {
421    #![allow(deprecated)]
422    #![allow(dead_code)]
423
424    use std::error::Error;
425    use std::ffi::c_void;
426    use std::fmt::{Display, Formatter};
427    use std::mem::size_of;
428    use std::rc::Rc;
429
430    use crate::value_box::{ErasedValueBox, ErasedValueBoxPointer, ValueBox, ValueBoxPointer};
431
432    use super::*;
433
434    #[derive(Debug)]
435    pub struct CustomError {}
436
437    impl Display for CustomError {
438        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
439            f.write_str("CustomError")
440        }
441    }
442
443    impl Error for CustomError {}
444
445    #[test]
446    pub fn value_box_size_in_memory() -> Result<()> {
447        assert_eq!(size_of::<ValueBox<c_void>>(), size_of::<c_void>());
448        assert_eq!(size_of::<ValueBox<(u64, u64)>>(), size_of::<(u64, u64)>());
449        assert_eq!(size_of::<ValueBox<()>>(), size_of::<()>());
450        assert_eq!(
451            size_of::<ValueBox<Box<dyn Error>>>(),
452            size_of::<Box<dyn Error>>()
453        );
454
455        Ok(())
456    }
457
458    #[test]
459    pub fn value_box_as_ref_mut() -> Result<()> {
460        let value_box = ValueBox::new(5);
461        let value_box_ptr = value_box.into_raw();
462        let value = value_box_ptr.with_ref_ok(|value| *value)?;
463        assert_eq!(value, 5);
464        value_box_ptr.release();
465
466        Ok(())
467    }
468
469    #[test]
470    pub fn value_box_as_non_null() -> Result<()> {
471        let value_box = ValueBox::new(5_i32);
472        let value_box_ptr = value_box.into_raw();
473        let value = value_box_ptr.with_ptr_ok(|pointer| unsafe {
474            *(pointer.as_ptr().cast::<i32>())
475        })?;
476        assert_eq!(value, 5);
477        value_box_ptr.release();
478
479        Ok(())
480    }
481
482    #[test]
483    pub fn erased_value_box_as_non_null() -> Result<()> {
484        let value_box = ValueBox::new(7_i32);
485        let value_box_ptr = value_box.into_raw();
486        let erased_value_box_ptr = value_box_ptr.erase();
487        let value = erased_value_box_ptr.with_ptr_ok(|pointer| unsafe {
488            *(pointer.as_ptr().cast::<i32>())
489        })?;
490        assert_eq!(value, 7);
491        value_box_ptr.release();
492
493        Ok(())
494    }
495
496    #[test]
497    pub fn value_box_into_erased_raw() -> Result<()> {
498        let erased_value_box_ptr = ValueBox::new(9_i32).into_erased_raw();
499        let value = erased_value_box_ptr.with_ptr_ok(|pointer| unsafe {
500            *(pointer.as_ptr().cast::<i32>())
501        })?;
502        assert_eq!(value, 9);
503        unsafe { from_raw::<i32>(erased_value_box_ptr.cast()) };
504
505        Ok(())
506    }
507
508    #[test]
509    pub fn const_erased_value_box_as_non_null() -> Result<()> {
510        let value_box_ptr = ValueBox::new(11_i32).into_raw();
511        let erased_value_box_ptr = value_box_ptr.erase() as *const ErasedValueBox;
512        let value = erased_value_box_ptr.with_ptr_ok(|pointer| unsafe {
513            *(pointer.as_ptr().cast::<i32>())
514        })?;
515        assert_eq!(value, 11);
516        value_box_ptr.release();
517
518        Ok(())
519    }
520
521    #[test]
522    fn value_box_with_not_null_value() {
523        let value_box = ValueBox::new(5);
524
525        let value_box_ptr = value_box.into_raw();
526        assert!(!value_box_ptr.is_null());
527
528        let mut result = 0;
529        value_box_ptr.with_not_null_value(|value| result = value * 2);
530        assert!(!value_box_ptr.is_null());
531        assert_eq!(result, 10);
532
533        value_box_ptr.release();
534    }
535
536    #[test]
537    fn value_box_with_not_null_value_return() {
538        let value_box = ValueBox::new(5);
539
540        let value_box_ptr = value_box.into_raw();
541        assert!(!value_box_ptr.is_null());
542
543        let result = value_box_ptr.with_not_null_value_return(0, |value| value * 2);
544        assert!(!value_box_ptr.is_null());
545        assert_eq!(result, 10);
546
547        value_box_ptr.release();
548    }
549
550    #[test]
551    fn value_box_drop() {
552        let value = Rc::new(42);
553
554        let ptr = ValueBox::new(value.clone()).into_raw();
555        assert_eq!(Rc::strong_count(&value), 2);
556        ptr.release();
557
558        assert_eq!(Rc::strong_count(&value), 1);
559    }
560}