Skip to main content

stk/vm/
access.rs

1use crate::value::Slot;
2use crate::vm::StackError;
3use std::cell::Cell;
4use std::fmt;
5use std::ops;
6
7#[derive(Debug, Clone, Default)]
8pub(super) struct Access(Cell<isize>);
9
10impl Access {
11    /// Test if we have shared access without modifying the internal count.
12    #[inline]
13    pub(super) fn test_shared(&self, slot: Slot) -> Result<(), StackError> {
14        let b = self.0.get().wrapping_sub(1);
15
16        if b >= 0 {
17            return Err(StackError::SlotInaccessibleShared { slot });
18        }
19
20        Ok(())
21    }
22
23    /// Mark that we want shared access to the given access token.
24    #[inline]
25    pub(super) fn shared(&self, slot: Slot) -> Result<(), StackError> {
26        let b = self.0.get().wrapping_sub(1);
27
28        if b >= 0 {
29            return Err(StackError::SlotInaccessibleShared { slot });
30        }
31
32        self.0.set(b);
33        Ok(())
34    }
35
36    /// Unshare the current access.
37    #[inline]
38    pub(super) fn release_shared(&self) {
39        let b = self.0.get().wrapping_add(1);
40        debug_assert!(b <= 0);
41        self.0.set(b);
42    }
43
44    /// Unshare the current access.
45    #[inline]
46    pub(super) fn release_exclusive(&self) {
47        let b = self.0.get().wrapping_sub(1);
48        debug_assert!(b == 0);
49        self.0.set(b);
50    }
51
52    /// Mark that we want exclusive access to the given access token.
53    #[inline]
54    pub(super) fn exclusive(&self, slot: Slot) -> Result<(), StackError> {
55        let b = self.0.get().wrapping_add(1);
56
57        if b != 1 {
58            return Err(StackError::SlotInaccessibleExclusive { slot });
59        }
60
61        self.0.set(b);
62        Ok(())
63    }
64}
65
66/// A raw reference guard.
67pub struct RawRefGuard {
68    pub(super) access: *const Access,
69}
70
71impl Drop for RawRefGuard {
72    fn drop(&mut self) {
73        unsafe { (*self.access).release_shared() };
74    }
75}
76
77/// Guard for a value borrowed from a slot in the virtual machine.
78///
79/// These guards are necessary, since we need to guarantee certain forms of
80/// access depending on what we do. Releasing the guard releases the access.
81///
82/// These also aid in function call integration, since they can be "arm" the
83/// virtual machine to release shared guards through its unsafe functions.
84///
85/// See [disarm][Vm::disarm] for more information.
86pub struct Ref<'a, T: ?Sized + 'a> {
87    pub(super) value: &'a T,
88    pub(super) raw: RawRefGuard,
89}
90
91impl<'a, T: ?Sized> Ref<'a, T> {
92    /// Convert into a reference with an unbounded lifetime.
93    ///
94    /// # Safety
95    ///
96    /// The returned reference must not outlive the VM that produced it.
97    /// Calling [disarm][Vm::disarm] must not be done until all referenced
98    /// produced through these methods are no longer live.
99    pub unsafe fn unsafe_into_ref<'out>(this: Self) -> (&'out T, RawRefGuard) {
100        let value = &*(this.value as *const _);
101        (value, this.raw)
102    }
103}
104
105impl<T: ?Sized> ops::Deref for Ref<'_, T> {
106    type Target = T;
107
108    fn deref(&self) -> &Self::Target {
109        self.value
110    }
111}
112
113impl<T: ?Sized> fmt::Debug for Ref<'_, T>
114where
115    T: fmt::Debug,
116{
117    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
118        fmt::Debug::fmt(self.value, fmt)
119    }
120}
121
122/// A raw mutable guard.
123pub struct RawMutGuard {
124    pub(super) access: *const Access,
125}
126
127impl Drop for RawMutGuard {
128    fn drop(&mut self) {
129        unsafe { (*self.access).release_exclusive() }
130    }
131}
132
133/// Guard for a value exclusively borrowed from a slot in the virtual machine.
134///
135/// These guards are necessary, since we need to guarantee certain forms of
136/// access depending on what we do. Releasing the guard releases the access.
137///
138/// These also aid in function call integration, since they can be "arm" the
139/// virtual machine to release shared guards through its unsafe functions.
140///
141/// See [disarm][Vm::disarm] for more information.
142pub struct Mut<'a, T: ?Sized> {
143    pub(super) value: &'a mut T,
144    pub(super) raw: RawMutGuard,
145}
146
147impl<'a, T: ?Sized> Mut<'a, T> {
148    /// Convert into a reference with an unbounded lifetime.
149    ///
150    /// # Safety
151    ///
152    /// The returned reference must not outlive the VM that produced it.
153    /// Calling [disarm][Vm::disarm] must not be done until all referenced
154    /// produced through these methods are no longer live.
155    pub unsafe fn unsafe_into_mut<'out>(this: Self) -> (&'out mut T, RawMutGuard) {
156        let value = &mut *(this.value as *mut _);
157        (value, this.raw)
158    }
159}
160
161impl<T: ?Sized> ops::Deref for Mut<'_, T> {
162    type Target = T;
163
164    fn deref(&self) -> &Self::Target {
165        self.value
166    }
167}
168
169impl<T: ?Sized> ops::DerefMut for Mut<'_, T> {
170    fn deref_mut(&mut self) -> &mut Self::Target {
171        self.value
172    }
173}