generic_cursors/
refcell.rs1use std::{
2 cell::{BorrowMutError, RefCell, RefMut},
3 future::Future,
4 marker::PhantomData,
5 pin::Pin,
6};
7
8pub struct RefCellRefMutStack<'root, T: ?Sized> {
9 lifetime: PhantomData<&'root mut T>,
11 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 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 pub fn top(&self) -> &T {
48 &*self.data.last().unwrap()
49 }
50
51 pub fn top_mut(&mut self) -> &mut T {
53 &mut *self.data.last_mut().unwrap()
54 }
55
56 pub fn is_at_root(&self) -> bool {
58 self.data.len() == 1
59 }
60
61 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 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 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 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 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 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 pub fn into_top(mut self) -> RefMut<'root, T> {
192 let ret = self.data.pop().unwrap();
193 unsafe {
194 self.data.set_len(0);
196 }
197 ret
198 }
199
200 pub fn to_root(&mut self) -> &mut T {
202 for _ in 1..self.data.len() {
203 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 self.data.pop();
217 }
218 }
219}