spore_vm/val/
protected_val.rs

1use std::ops::Deref;
2
3#[allow(unused_imports)]
4use log::*;
5
6use crate::Vm;
7
8use super::{
9    custom::{CustomValError, CustomValMut, CustomValRef},
10    CustomType, Val,
11};
12
13/// Holds a value from the [Vm] that is guaranteed to not be garbage collected.
14///
15/// The underlying value is protected from garbage collection until `ProtectedVal` is dropped.
16#[derive(Debug)]
17pub struct ProtectedVal<'a> {
18    pub(crate) vm: &'a mut Vm,
19    pub(crate) val: Val<'a>,
20}
21
22impl<'a> ProtectedVal<'a> {
23    /// Create a new `Val` from an [crate::val::UnsafeVal].
24    ///
25    /// # Safety
26    /// `v` must be a valid from originating (and not garbage collected) from `vm`.
27    pub fn new(vm: &'a mut Vm, v: Val<'a>) -> ProtectedVal<'a> {
28        vm.objects.keep_reachable(v.inner);
29        ProtectedVal { vm, val: v }
30    }
31
32    /// Split the protected val into its [Vm] and [Val].
33    ///
34    /// Despite the split, the returned `Val` will still be safe from garbage collection.
35    pub fn split(&mut self) -> (&mut Vm, &Val) {
36        (self.vm, &self.val)
37    }
38
39    /// Run function `f` on the [Vm] and [Val] and return the result. This is a convenient way of
40    /// gaining mutable reference to the underlying vm.
41    pub fn with<T>(&mut self, f: impl Fn(&mut Vm, &Val) -> T) -> T {
42        let (vm, val) = self.split();
43        f(vm, val)
44    }
45}
46
47impl<'a> Drop for ProtectedVal<'a> {
48    fn drop(&mut self) {
49        self.vm.objects.allow_unreachable(self.val.inner);
50    }
51}
52
53impl<'a> Deref for ProtectedVal<'a> {
54    type Target = Val<'a>;
55
56    fn deref(&self) -> &Self::Target {
57        &self.val
58    }
59}
60
61impl<'a> ProtectedVal<'a> {
62    /// Get a reference to the underlying [Vm].
63    pub fn vm(&self) -> &Vm {
64        self.vm
65    }
66
67    /// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value (if `Some`)
68    /// or returns `None` (if `None`).
69    pub fn map<T>(&mut self, f: impl Fn(&mut Vm, &ProtectedVal<'a>) -> T) -> T {
70        let protected_val_ptr: *const ProtectedVal = self;
71        // Unsafe OK: Protected val will still be safe from garbage collection as drop has not been
72        // called.
73        f(self.vm, unsafe { &*protected_val_ptr })
74    }
75
76    /// Try to get the string as a value or return its underlying value.
77    pub fn try_str(&'a self) -> Result<&'a str, Val> {
78        self.val.try_str(self.vm)
79    }
80
81    /// Try to get the custom value of type `T` or return its underlying value if `self` is not of
82    /// type `T`.
83    pub fn try_custom<T: CustomType>(&self) -> Result<CustomValRef<T>, CustomValError> {
84        self.val.try_custom(self.vm)
85    }
86
87    /// Returns the value as a custom type of `T` or [Err] if [Self] is not of the given custom
88    /// value.
89    pub fn try_custom_mut<T: CustomType>(&self) -> Result<CustomValMut<T>, CustomValError> {
90        self.val.try_custom_mut(self.vm)
91    }
92
93    /// Get the [Val] that the mutable box is pointing to or `Err<Val>` if `self` is not a mutable
94    /// box.
95    pub fn get_mutable_box_ref(&self) -> Result<Val, Val<'a>> {
96        self.val.try_mutable_box_ref(self.vm)
97    }
98}
99
100impl<'a> std::fmt::Display for ProtectedVal<'a> {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        self.val.format_quoted(self.vm).fmt(f)
103    }
104}