Skip to main content

hopper_native/
borrow.rs

1//! Deterministic borrow guards for account data.
2//!
3//! `Ref` and `RefMut` provide RAII borrow tracking on the `borrow_state`
4//! field of `RuntimeAccount`. When dropped, they restore the borrow
5//! state, preventing use-after-free and double-mutable-borrow bugs.
6//!
7//! These replace `core::cell::RefCell` without requiring alloc.
8
9use crate::NOT_BORROWED;
10
11/// Shared (immutable) borrow guard for account data.
12///
13/// On drop, decrements the borrow count in `RuntimeAccount.borrow_state`.
14pub struct Ref<'a, T: ?Sized> {
15    value: &'a T,
16    state: *mut u8,
17}
18
19impl<'a, T: ?Sized> Ref<'a, T> {
20    /// Create a new shared borrow guard.
21    ///
22    /// The caller must have already incremented `*state` to reflect
23    /// the new shared borrow.
24    #[inline(always)]
25    pub(crate) fn new(value: &'a T, state: *mut u8) -> Self {
26        Self { value, state }
27    }
28
29    /// Create a shared borrow guard from raw parts.
30    ///
31    /// # Safety
32    ///
33    /// The caller must ensure:
34    /// - The borrow state at `state` was already incremented
35    /// - `value` is valid for lifetime `'a`
36    /// - `state` points to a valid `RuntimeAccount.borrow_state`
37    #[inline(always)]
38    pub unsafe fn from_raw_parts(value: &'a T, state: *mut u8) -> Self {
39        Self { value, state }
40    }
41
42    /// Decompose into raw parts without running the destructor.
43    ///
44    /// The caller takes responsibility for eventually releasing the
45    /// borrow (decrementing `*state`).
46    #[inline(always)]
47    pub fn into_raw_parts(self) -> (&'a T, *mut u8) {
48        let value = self.value;
49        let state = self.state;
50        core::mem::forget(self);
51        (value, state)
52    }
53}
54
55impl<T: ?Sized> core::ops::Deref for Ref<'_, T> {
56    type Target = T;
57
58    #[inline(always)]
59    fn deref(&self) -> &T {
60        self.value
61    }
62}
63
64impl<T: ?Sized> Drop for Ref<'_, T> {
65    fn drop(&mut self) {
66        // SAFETY: state points to RuntimeAccount.borrow_state in the
67        // BPF input buffer. We decrement the shared borrow count,
68        // restoring NOT_BORROWED when the last shared borrow is released.
69        unsafe {
70            let current = *self.state;
71            if current == 1 {
72                *self.state = NOT_BORROWED;
73            } else {
74                *self.state = current - 1;
75            }
76        }
77    }
78}
79
80/// Exclusive (mutable) borrow guard for account data.
81///
82/// On drop, restores `RuntimeAccount.borrow_state` to `NOT_BORROWED`.
83pub struct RefMut<'a, T: ?Sized> {
84    value: &'a mut T,
85    state: *mut u8,
86}
87
88impl<'a, T: ?Sized> RefMut<'a, T> {
89    /// Create a new exclusive borrow guard.
90    ///
91    /// The caller must have already set `*state = 0` to indicate
92    /// exclusive borrow.
93    #[inline(always)]
94    pub(crate) fn new(value: &'a mut T, state: *mut u8) -> Self {
95        Self { value, state }
96    }
97
98    /// Create an exclusive borrow guard from raw parts.
99    ///
100    /// # Safety
101    ///
102    /// The caller must ensure:
103    /// - The borrow state at `state` was set to 0 (exclusive)
104    /// - `value` is valid and unique for lifetime `'a`
105    /// - `state` points to a valid `RuntimeAccount.borrow_state`
106    #[inline(always)]
107    pub unsafe fn from_raw_parts(value: &'a mut T, state: *mut u8) -> Self {
108        Self { value, state }
109    }
110
111    /// Decompose into raw parts without running the destructor.
112    ///
113    /// The caller takes responsibility for eventually releasing the
114    /// borrow (restoring `*state` to `NOT_BORROWED`).
115    #[inline(always)]
116    pub fn into_raw_parts(self) -> (&'a mut T, *mut u8) {
117        let manual = core::mem::ManuallyDrop::new(self);
118        let value = unsafe { core::ptr::read(&manual.value) };
119        let state = manual.state;
120        (value, state)
121    }
122}
123
124impl<T: ?Sized> core::ops::Deref for RefMut<'_, T> {
125    type Target = T;
126
127    #[inline(always)]
128    fn deref(&self) -> &T {
129        self.value
130    }
131}
132
133impl<T: ?Sized> core::ops::DerefMut for RefMut<'_, T> {
134    #[inline(always)]
135    fn deref_mut(&mut self) -> &mut T {
136        self.value
137    }
138}
139
140impl<T: ?Sized> Drop for RefMut<'_, T> {
141    fn drop(&mut self) {
142        // SAFETY: state points to RuntimeAccount.borrow_state.
143        // Restore to NOT_BORROWED when the exclusive borrow is released.
144        unsafe {
145            *self.state = NOT_BORROWED;
146        }
147    }
148}