generic_cursors/
refcell.rs

1use std::{
2    cell::{BorrowMutError, RefCell, RefMut},
3    future::Future,
4    marker::PhantomData,
5    pin::Pin,
6};
7
8pub struct RefCellRefMutStack<'root, T: ?Sized> {
9    /// Ensures this mutrefstack does not exceed the lifetime of its root.
10    lifetime: PhantomData<&'root mut T>,
11    /// The stack of pointers. Each one borrows from the one prior, except the first which is the `root` and may never be popped.
12    /// Note: the `'root` lifetime is a "lie", only used because there's no raw pointer counterpart for `RefMut`.
13    /// The `RefMut`s are not publicly accessible so this is fine.
14    data: Vec<RefMut<'root, T>>,
15}
16
17pub enum MoveDecision<'root, 'this, T: ?Sized> {
18    Ascend,
19    Stay,
20    Descend(&'this RefCell<T>),
21    Inject(&'root RefCell<T>),
22}
23
24pub enum MoveError {
25    AscendAtRoot,
26    BorrowMutError(BorrowMutError),
27}
28
29impl<'root, T: ?Sized> RefCellRefMutStack<'root, T> {
30    /// Create a new MutRefStack from a mutable reference to the root
31    /// of a recursive data structure.
32    pub fn new(root: &'root RefCell<T>) -> Result<Self, BorrowMutError> {
33        let root: *const RefCell<T> = root;
34        let borrow = unsafe { (*root).try_borrow_mut()? };
35        Ok(Self {
36            lifetime: PhantomData,
37            data: vec![borrow],
38        })
39    }
40
41    pub fn raw_top_mut(&mut self) -> *mut T {
42        let refmut: *mut RefMut<T> = self.data.last_mut().unwrap();
43        unsafe { &mut **refmut }
44    }
45
46    /// Obtain a shared reference to the top of the stack.
47    pub fn top(&self) -> &T {
48        &*self.data.last().unwrap()
49    }
50
51    /// Obtain a mutable reference to the top of the stack.
52    pub fn top_mut(&mut self) -> &mut T {
53        &mut *self.data.last_mut().unwrap()
54    }
55
56    /// Is this MutRefStack currently at its root?
57    pub fn is_at_root(&self) -> bool {
58        self.data.len() == 1
59    }
60
61    /// Inject a new reference to the top of the stack. The reference still must live
62    /// as long as the root of the stack.
63    pub fn inject_top(&mut self, new_top: &'root RefCell<T>) -> Result<&mut T, BorrowMutError> {
64        let new_top: *const RefCell<T> = new_top;
65        let borrow = unsafe { (*new_top).try_borrow_mut()? };
66        self.data.push(borrow);
67        Ok(self.top_mut())
68    }
69
70    /// Inject a new reference to the top of the stack. The reference still must live
71    /// as long as the root of the stack.
72    pub fn inject_with(
73        &mut self,
74        f: impl FnOnce(&mut T) -> Option<&'root RefCell<T>>,
75    ) -> Option<Result<&mut T, BorrowMutError>> {
76        let old_top: *mut T = self.raw_top_mut();
77        let new_top: &RefCell<T> = unsafe { f(&mut *old_top)? };
78        let new_top: *const RefCell<T> = new_top;
79        let borrow = unsafe { (*new_top).try_borrow_mut() };
80        match borrow {
81            Ok(borrow) => {
82                self.data.push(borrow);
83                Some(Ok(self.top_mut()))
84            }
85            Err(err) => Some(Err(err)),
86        }
87    }
88
89    /// Descend into the recursive data structure, returning a mutable reference to the new top element.
90    /// Rust's borrow checker enforces that the closure cannot inject any lifetime (other than `'static`),
91    /// because the closure must work for any lifetime `'node`.
92    pub fn descend_with(
93        &mut self,
94        f: impl for<'node> FnOnce(&'node mut T) -> Option<&'node RefCell<T>>,
95    ) -> Option<Result<&mut T, BorrowMutError>> {
96        let old_top: *mut T = self.raw_top_mut();
97        let new_top: &RefCell<T> = unsafe { f(&mut *old_top)? };
98        let new_top: *const RefCell<T> = new_top;
99        let borrow = unsafe { (*new_top).try_borrow_mut() };
100        match borrow {
101            Ok(borrow) => {
102                self.data.push(borrow);
103                Some(Ok(self.top_mut()))
104            }
105            Err(err) => Some(Err(err)),
106        }
107    }
108
109    /// Ascend back up from the recursive data structure, returning a mutable reference to the new top element, if it changed.
110    /// If we are not currently at the root, ascend and return a reference to the new top.
111    /// If we are already at the root, returns None (the top is the root and does not change).
112    pub fn ascend(&mut self) -> Option<&mut T> {
113        match self.data.len() {
114            0 => unreachable!("root pointer must always exist"),
115            1 => None,
116            _ => {
117                self.data.pop();
118                Some(self.top_mut())
119            }
120        }
121    }
122
123    /// Ascend back up from the recursive data structure while the given closure returns `true`, returning a mutable reference to the new top element.
124    /// If we are not currently at the root, and the predicate returns `true`, ascend and continue.
125    /// If we are already at the root, or if the predicate returned false, returns a reference to the top element.
126    pub fn ascend_while<P>(&mut self, mut predicate: P) -> &mut T
127    where
128        P: FnMut(&mut T) -> bool,
129    {
130        while !self.is_at_root() && predicate(self.top_mut()) {
131            let Some(_) = self.ascend() else {
132                unreachable!();
133            };
134        }
135        self.top_mut()
136    }
137
138    /// Ascend from, descend from, inject a new stack top, or stay at the current node,
139    /// based on the return value of the closure.
140    pub fn move_with<F>(&mut self, f: F) -> Result<&mut T, MoveError>
141    where
142        F: for<'a> FnOnce(&'a mut T) -> MoveDecision<'root, 'a, T>,
143    {
144        let old_top: *mut T = self.raw_top_mut();
145        let result = unsafe { f(&mut *old_top) };
146        match result {
147            MoveDecision::Ascend => self.ascend().ok_or(MoveError::AscendAtRoot),
148            MoveDecision::Stay => Ok(self.top_mut()),
149            MoveDecision::Inject(new_top) | MoveDecision::Descend(new_top) => {
150                let new_top: *const RefCell<T> = new_top;
151                let borrow = unsafe { (*new_top).try_borrow_mut() };
152                match borrow {
153                    Ok(borrow) => {
154                        self.data.push(borrow);
155                        Ok(self.top_mut())
156                    }
157                    Err(err) => Err(MoveError::BorrowMutError(err)),
158                }
159            }
160        }
161    }
162
163    pub async fn move_with_async<F>(&mut self, f: F) -> Result<&mut T, MoveError>
164    where
165        F: for<'a> FnOnce(
166            &'a mut T,
167        )
168            -> Pin<Box<dyn Future<Output = MoveDecision<'root, 'a, T>> + 'a>>,
169    {
170        let old_top: *mut T = self.raw_top_mut();
171        let result = unsafe { f(&mut *old_top) }.await;
172        match result {
173            MoveDecision::Ascend => self.ascend().ok_or(MoveError::AscendAtRoot),
174            MoveDecision::Stay => Ok(self.top_mut()),
175            MoveDecision::Inject(new_top) | MoveDecision::Descend(new_top) => {
176                let new_top: *const RefCell<T> = new_top;
177                let borrow = unsafe { (*new_top).try_borrow_mut() };
178                match borrow {
179                    Ok(borrow) => {
180                        self.data.push(borrow);
181                        Ok(self.top_mut())
182                    }
183                    Err(err) => Err(MoveError::BorrowMutError(err)),
184                }
185            }
186        }
187    }
188
189    /// Return reference to the top element of this stack, forgetting about the stack entirely.
190    /// Note that this leaks all `RefMut`s above the top.
191    pub fn into_top(mut self) -> RefMut<'root, T> {
192        let ret = self.data.pop().unwrap();
193        unsafe {
194            // We need to not drop the parent RefMuts, if any
195            self.data.set_len(0);
196        }
197        ret
198    }
199
200    /// Pop all `RefMut`s off the stack and go back to the root.
201    pub fn to_root(&mut self) -> &mut T {
202        for _ in 1..self.data.len() {
203            // We need to drop the RefMut's in the reverse order.
204            // Vec::truncate does not specify drop order, but it's probably wrong anyway.
205            self.data.pop();
206        }
207        self.top_mut()
208    }
209}
210
211impl<'root, T: ?Sized> Drop for RefCellRefMutStack<'root, T> {
212    fn drop(&mut self) {
213        for _ in 0..self.data.len() {
214            // We need to drop the RefMut's in the reverse order.
215            // Vec::truncate does not specify drop order, but it's probably wrong anyway.
216            self.data.pop();
217        }
218    }
219}