tycho_vm/
saferc.rs

1use std::mem::ManuallyDrop;
2use std::rc::Rc;
3use std::sync::Arc;
4
5use tycho_types::error::Error;
6use tycho_types::prelude::*;
7
8// === SafeRc impl ===
9
10/// A data which can be used in [`SafeRc`].
11pub trait SafeDelete: 'static {
12    fn rc_into_safe_delete(self: Rc<Self>) -> Rc<dyn SafeDelete>;
13}
14
15impl<T: 'static> SafeDelete for T {
16    #[inline]
17    fn rc_into_safe_delete(self: Rc<Self>) -> Rc<dyn SafeDelete> {
18        self
19    }
20}
21
22/// [`Rc`]-like object with a linear drop.
23///
24/// Allows to build a deeply
25/// nested data without causing a stack overflow.
26#[repr(transparent)]
27pub struct SafeRc<T: SafeDelete + ?Sized>(pub(crate) ManuallyDrop<Rc<T>>);
28
29impl<T: SafeDelete> SafeRc<T> {
30    #[inline]
31    pub fn new(value: T) -> Self {
32        Self(ManuallyDrop::new(Rc::new(value)))
33    }
34
35    #[inline]
36    pub fn try_unwrap(this: Self) -> Result<T, Self> {
37        match Rc::try_unwrap(Self::into_inner(this)) {
38            Ok(value) => Ok(value),
39            Err(rc) => Err(Self(ManuallyDrop::new(rc))),
40        }
41    }
42}
43
44impl<T: SafeDelete + ?Sized> SafeRc<T> {
45    #[inline]
46    pub fn into_inner(mut this: Self) -> Rc<T> {
47        // SAFETY: Item was taken only once.
48        let value = unsafe { ManuallyDrop::take(&mut this.0) };
49        // Forget `self` to prevent `drop` from calling.
50        std::mem::forget(this);
51
52        value
53    }
54
55    #[inline]
56    pub fn get_mut(this: &mut Self) -> Option<&mut T> {
57        Rc::get_mut(&mut *this.0)
58    }
59
60    #[inline]
61    pub fn ptr_eq(lhs: &Self, rhs: &Self) -> bool {
62        Rc::<T>::ptr_eq(&*lhs.0, &*rhs.0)
63    }
64
65    #[inline]
66    pub fn as_ptr(&self) -> *const T {
67        Rc::as_ptr(&*self.0)
68    }
69}
70
71impl<T: SafeDelete + Clone> SafeRc<T> {
72    #[inline]
73    pub fn unwrap_or_clone(this: Self) -> T {
74        Rc::unwrap_or_clone(Self::into_inner(this))
75    }
76}
77
78// === Common traits impl ===
79
80impl<T: Default + SafeDelete> Default for SafeRc<T> {
81    fn default() -> Self {
82        Self(ManuallyDrop::new(Rc::<T>::default()))
83    }
84}
85
86impl<T: SafeDelete + ?Sized> Clone for SafeRc<T> {
87    #[inline]
88    fn clone(&self) -> Self {
89        Self(self.0.clone())
90    }
91}
92
93impl<T: SafeDelete + std::fmt::Display + ?Sized> std::fmt::Display for SafeRc<T> {
94    #[inline]
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        std::fmt::Display::fmt(&*self.0, f)
97    }
98}
99
100impl<T: SafeDelete + std::fmt::Debug + ?Sized> std::fmt::Debug for SafeRc<T> {
101    #[inline]
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        std::fmt::Debug::fmt(&*self.0, f)
104    }
105}
106
107impl<T: Eq + SafeDelete + ?Sized> Eq for SafeRc<T> {}
108
109impl<T: PartialEq + SafeDelete + ?Sized> PartialEq for SafeRc<T> {
110    #[inline]
111    fn eq(&self, other: &Self) -> bool {
112        T::eq(&*self.0, &*other.0)
113    }
114}
115
116impl<T: Ord + SafeDelete + ?Sized> Ord for SafeRc<T> {
117    #[inline]
118    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
119        T::cmp(&*self.0, &*other.0)
120    }
121}
122
123impl<T: PartialOrd + SafeDelete + ?Sized> PartialOrd for SafeRc<T> {
124    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
125        T::partial_cmp(&*self.0, &*other.0)
126    }
127}
128
129impl<T: SafeDelete + ?Sized> Drop for SafeRc<T> {
130    fn drop(&mut self) {
131        // SAFETY: Item was taken only once.
132        let value = unsafe { ManuallyDrop::take(&mut self.0) };
133
134        // // TODO: Somehow move this to stack module?
135        // castaway::match_type!(value, {
136        //     // Just drop the value for non-recursive types.
137        //     () as _v => {},
138        //     crate::stack::NaN as _v => {},
139        //     num_bigint::BigInt as _v => {},
140        //     tycho_types::cell::Cell as _v => {},
141        //     tycho_types::cell::CellBuilder as _v => {},
142        //     crate::util::OwnedCellSlice as _v => {},
143        //     // Go through retire othersize (Cont, Stack, Tuple, etc.).
144        //     value => {
145        //         if Rc::strong_count(&value) == 1 {
146        //             SafeDeleter::retire(value.rc_into_safe_delete());
147        //         }
148        //     }
149        // });
150
151        if Rc::strong_count(&value) == 1 {
152            SafeDeleter::retire(value.rc_into_safe_delete());
153        }
154    }
155}
156
157impl<T: SafeDelete + ?Sized> std::ops::Deref for SafeRc<T> {
158    type Target = T;
159
160    #[inline]
161    fn deref(&self) -> &Self::Target {
162        &self.0
163    }
164}
165
166impl<T: SafeDelete + ?Sized> AsRef<T> for SafeRc<T> {
167    #[inline]
168    fn as_ref(&self) -> &T {
169        &self.0
170    }
171}
172
173impl<T: SafeDelete + ?Sized> From<Rc<T>> for SafeRc<T> {
174    #[inline]
175    fn from(value: Rc<T>) -> Self {
176        Self(ManuallyDrop::new(value))
177    }
178}
179
180impl<T: SafeDelete> From<T> for SafeRc<T> {
181    #[inline]
182    fn from(value: T) -> Self {
183        Self::new(value)
184    }
185}
186
187#[cfg(feature = "arbitrary")]
188impl<'a, T: SafeDelete + arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a> for SafeRc<T> {
189    #[inline]
190    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
191        u.arbitrary().map(Self::new)
192    }
193
194    #[inline]
195    fn size_hint(depth: usize) -> (usize, Option<usize>) {
196        Self::try_size_hint(depth).unwrap_or_default()
197    }
198
199    #[inline]
200    fn try_size_hint(
201        depth: usize,
202    ) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
203        <T as arbitrary::Arbitrary>::try_size_hint(depth)
204    }
205}
206
207// === `Rc::make_mut` glue ===
208
209/// `Rc::make_mut` glue.
210pub trait SafeRcMakeMut: SafeDelete {
211    fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self;
212}
213
214impl<T: SafeRcMakeMut + ?Sized> SafeRc<T> {
215    #[inline]
216    pub fn make_mut(&mut self) -> &mut T {
217        T::rc_make_mut(&mut *self.0)
218    }
219}
220
221impl SafeRcMakeMut for () {
222    #[inline]
223    fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
224        Rc::make_mut(rc)
225    }
226}
227
228impl<T: Clone + 'static> SafeRcMakeMut for Box<T> {
229    #[inline]
230    fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
231        Rc::make_mut(rc)
232    }
233}
234
235impl<T: ?Sized + 'static> SafeRcMakeMut for Rc<T> {
236    #[inline]
237    fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
238        Rc::make_mut(rc)
239    }
240}
241
242impl<T: ?Sized + 'static> SafeRcMakeMut for Arc<T> {
243    #[inline]
244    fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
245        Rc::make_mut(rc)
246    }
247}
248
249impl<T: Clone + 'static> SafeRcMakeMut for Vec<T> {
250    #[inline]
251    fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
252        Rc::make_mut(rc)
253    }
254}
255
256impl SafeRcMakeMut for String {
257    #[inline]
258    fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
259        Rc::make_mut(rc)
260    }
261}
262
263// === Cell traits impl ===
264
265impl<'a, T: Load<'a> + SafeDelete> Load<'a> for SafeRc<T> {
266    #[inline]
267    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
268        let value = ok!(Rc::<T>::load_from(slice));
269        Ok(Self(ManuallyDrop::new(value)))
270    }
271}
272
273impl<T: Store + SafeDelete + ?Sized> Store for SafeRc<T> {
274    #[inline]
275    fn store_into(&self, b: &mut CellBuilder, c: &dyn CellContext) -> Result<(), Error> {
276        T::store_into(&*self.0, b, c)
277    }
278}
279
280// === Linear deleter ===
281
282struct SafeDeleter {
283    to_delete: std::cell::RefCell<Vec<Rc<dyn SafeDelete>>>,
284    is_active: std::cell::Cell<bool>,
285}
286
287impl SafeDeleter {
288    fn retire(value: Rc<dyn SafeDelete>) {
289        thread_local! {
290            static DELETER: SafeDeleter = const {
291                SafeDeleter {
292                    to_delete: std::cell::RefCell::new(Vec::new()),
293                    is_active: std::cell::Cell::new(false),
294                }
295            };
296        }
297
298        let mut value = ManuallyDrop::new(value);
299
300        match DELETER.try_with(|deleter| {
301            // SAFETY: Value is going to be taken only once, because this
302            // closure will run only if `LocalKey` still exists.
303            let value = unsafe { ManuallyDrop::take(&mut value) };
304
305            if deleter.is_active.get() {
306                // Delay child value drop if we are already dropping some parent value.
307                deleter.to_delete.borrow_mut().push(value);
308                return;
309            }
310
311            // Activate delayed drop of children.
312            deleter.is_active.set(true);
313
314            // Drop the parent value. This will fill the `to_delete` vector
315            // with children values.
316            drop(value);
317
318            // Iterate and "drop" children.
319            loop {
320                // Take one child value.
321                let mut to_delete = deleter.to_delete.borrow_mut();
322                match to_delete.pop() {
323                    Some(value) => {
324                        // Make sure to drop the `RefMut` guard first.
325                        drop(to_delete);
326                        // "Drop" the child.
327                        drop(value);
328                    }
329                    None => break,
330                }
331            }
332
333            // Disable delayed delete.
334            deleter.is_active.set(false);
335        }) {
336            Ok(()) => {}
337            // SAFETY: `LocalKey` does not exist anymore (we are removing some other
338            // thread local SafeRc). So the closure above will not run and
339            // we are dropping the value like always.
340            Err(_) => drop(unsafe { ManuallyDrop::take(&mut value) }),
341        }
342    }
343}
344
345#[cfg(test)]
346mod tests {
347    use super::*;
348
349    #[test]
350    #[cfg_attr(miri, ignore)]
351    fn drop_deep_tuple() {
352        let mut tuple = SafeRc::new_dyn_value(());
353        for _ in 0..1000000 {
354            tuple = SafeRc::new_dyn_value(vec![tuple]);
355        }
356    }
357}