value_box/
value_box.rs

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