generational_box/
unsync.rs

1use crate::{
2    entry::{MemoryLocationBorrowInfo, RcStorageEntry, StorageEntry},
3    error,
4    references::{GenerationalRef, GenerationalRefMut},
5    AnyStorage, BorrowError, BorrowMutError, BorrowMutResult, BorrowResult, GenerationalLocation,
6    GenerationalPointer, Storage, ValueDroppedError,
7};
8use std::{
9    any::Any,
10    cell::{Ref, RefCell, RefMut},
11    fmt::Debug,
12    num::NonZeroU64,
13};
14
15type RefCellStorageEntryRef = Ref<'static, StorageEntry<RefCellStorageEntryData>>;
16type RefCellStorageEntryMut = RefMut<'static, StorageEntry<RefCellStorageEntryData>>;
17type AnyRef = Ref<'static, Box<dyn Any>>;
18type AnyRefMut = RefMut<'static, Box<dyn Any>>;
19
20thread_local! {
21    static UNSYNC_RUNTIME: RefCell<Vec<&'static UnsyncStorage>> = const { RefCell::new(Vec::new()) };
22}
23
24#[derive(Default)]
25pub(crate) enum RefCellStorageEntryData {
26    Reference(GenerationalPointer<UnsyncStorage>),
27    Rc(RcStorageEntry<Box<dyn Any>>),
28    Data(Box<dyn Any>),
29    #[default]
30    Empty,
31}
32
33impl Debug for RefCellStorageEntryData {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            Self::Reference(pointer) => write!(f, "Reference({:?})", pointer.location),
37            Self::Rc(_) => write!(f, "Rc"),
38            Self::Data(_) => write!(f, "Data"),
39            Self::Empty => write!(f, "Empty"),
40        }
41    }
42}
43
44/// A unsync storage. This is the default storage type.
45#[derive(Default)]
46pub struct UnsyncStorage {
47    borrow_info: MemoryLocationBorrowInfo,
48    data: RefCell<StorageEntry<RefCellStorageEntryData>>,
49}
50
51impl UnsyncStorage {
52    pub(crate) fn read(
53        pointer: GenerationalPointer<Self>,
54    ) -> BorrowResult<(AnyRef, GenerationalPointer<Self>)> {
55        Self::get_split_ref(pointer).map(|(resolved, guard)| {
56            (
57                Ref::map(guard, |data| match &data.data {
58                    RefCellStorageEntryData::Data(data) => data,
59                    RefCellStorageEntryData::Rc(data) => &data.data,
60                    _ => unreachable!(),
61                }),
62                resolved,
63            )
64        })
65    }
66
67    pub(crate) fn get_split_ref(
68        mut pointer: GenerationalPointer<Self>,
69    ) -> BorrowResult<(GenerationalPointer<Self>, RefCellStorageEntryRef)> {
70        loop {
71            let borrow = pointer
72                .storage
73                .data
74                .try_borrow()
75                .map_err(|_| pointer.storage.borrow_info.borrow_error())?;
76            if !borrow.valid(&pointer.location) {
77                return Err(BorrowError::Dropped(ValueDroppedError::new_for_location(
78                    pointer.location,
79                )));
80            }
81            match &borrow.data {
82                // If this is a reference, keep traversing the pointers
83                RefCellStorageEntryData::Reference(data) => {
84                    pointer = *data;
85                }
86                // Otherwise return the value
87                RefCellStorageEntryData::Rc(_) | RefCellStorageEntryData::Data(_) => {
88                    return Ok((pointer, borrow));
89                }
90                RefCellStorageEntryData::Empty => {
91                    return Err(BorrowError::Dropped(ValueDroppedError::new_for_location(
92                        pointer.location,
93                    )));
94                }
95            }
96        }
97    }
98
99    pub(crate) fn write(
100        pointer: GenerationalPointer<Self>,
101    ) -> BorrowMutResult<(AnyRefMut, GenerationalPointer<Self>)> {
102        Self::get_split_mut(pointer).map(|(resolved, guard)| {
103            (
104                RefMut::map(guard, |data| match &mut data.data {
105                    RefCellStorageEntryData::Data(data) => data,
106                    RefCellStorageEntryData::Rc(data) => &mut data.data,
107                    _ => unreachable!(),
108                }),
109                resolved,
110            )
111        })
112    }
113
114    pub(crate) fn get_split_mut(
115        mut pointer: GenerationalPointer<Self>,
116    ) -> BorrowMutResult<(GenerationalPointer<Self>, RefCellStorageEntryMut)> {
117        loop {
118            let borrow = pointer
119                .storage
120                .data
121                .try_borrow_mut()
122                .map_err(|_| pointer.storage.borrow_info.borrow_mut_error())?;
123            if !borrow.valid(&pointer.location) {
124                return Err(BorrowMutError::Dropped(
125                    ValueDroppedError::new_for_location(pointer.location),
126                ));
127            }
128            match &borrow.data {
129                // If this is a reference, keep traversing the pointers
130                RefCellStorageEntryData::Reference(data) => {
131                    pointer = *data;
132                }
133                // Otherwise return the value
134                RefCellStorageEntryData::Data(_) | RefCellStorageEntryData::Rc(_) => {
135                    return Ok((pointer, borrow));
136                }
137                RefCellStorageEntryData::Empty => {
138                    return Err(BorrowMutError::Dropped(
139                        ValueDroppedError::new_for_location(pointer.location),
140                    ));
141                }
142            }
143        }
144    }
145
146    fn create_new(
147        value: RefCellStorageEntryData,
148        #[allow(unused)] caller: &'static std::panic::Location<'static>,
149    ) -> GenerationalPointer<Self> {
150        UNSYNC_RUNTIME.with(|runtime| match runtime.borrow_mut().pop() {
151            Some(storage) => {
152                let mut write = storage.data.borrow_mut();
153                let location = GenerationalLocation {
154                    generation: write.generation(),
155                    #[cfg(any(debug_assertions, feature = "debug_borrows"))]
156                    created_at: caller,
157                };
158                write.data = value;
159                GenerationalPointer { storage, location }
160            }
161            None => {
162                let storage: &'static Self = &*Box::leak(Box::new(Self {
163                    borrow_info: Default::default(),
164                    data: RefCell::new(StorageEntry::new(value)),
165                }));
166
167                let location = GenerationalLocation {
168                    generation: NonZeroU64::MIN,
169                    #[cfg(any(debug_assertions, feature = "debug_borrows"))]
170                    created_at: caller,
171                };
172
173                GenerationalPointer { storage, location }
174            }
175        })
176    }
177}
178
179impl AnyStorage for UnsyncStorage {
180    type Ref<'a, R: ?Sized + 'a> = GenerationalRef<Ref<'a, R>>;
181    type Mut<'a, W: ?Sized + 'a> = GenerationalRefMut<RefMut<'a, W>>;
182
183    fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'a>(
184        ref_: Self::Ref<'a, T>,
185    ) -> Self::Ref<'b, T> {
186        ref_
187    }
188
189    fn downcast_lifetime_mut<'a: 'b, 'b, T: ?Sized + 'a>(
190        mut_: Self::Mut<'a, T>,
191    ) -> Self::Mut<'b, T> {
192        mut_
193    }
194
195    fn map<T: ?Sized, U: ?Sized>(
196        ref_: Self::Ref<'_, T>,
197        f: impl FnOnce(&T) -> &U,
198    ) -> Self::Ref<'_, U> {
199        ref_.map(|inner| Ref::map(inner, f))
200    }
201
202    fn map_mut<T: ?Sized, U: ?Sized>(
203        mut_ref: Self::Mut<'_, T>,
204        f: impl FnOnce(&mut T) -> &mut U,
205    ) -> Self::Mut<'_, U> {
206        mut_ref.map(|inner| RefMut::map(inner, f))
207    }
208
209    fn try_map<I: ?Sized, U: ?Sized>(
210        _self: Self::Ref<'_, I>,
211        f: impl FnOnce(&I) -> Option<&U>,
212    ) -> Option<Self::Ref<'_, U>> {
213        _self.try_map(|inner| Ref::filter_map(inner, f).ok())
214    }
215
216    fn try_map_mut<I: ?Sized, U: ?Sized>(
217        mut_ref: Self::Mut<'_, I>,
218        f: impl FnOnce(&mut I) -> Option<&mut U>,
219    ) -> Option<Self::Mut<'_, U>> {
220        mut_ref.try_map(|inner| RefMut::filter_map(inner, f).ok())
221    }
222
223    fn data_ptr(&self) -> *const () {
224        self.data.as_ptr() as *const ()
225    }
226
227    fn recycle(pointer: GenerationalPointer<Self>) {
228        let mut borrow_mut = pointer.storage.data.borrow_mut();
229
230        // First check if the generation is still valid
231        if !borrow_mut.valid(&pointer.location) {
232            return;
233        }
234
235        borrow_mut.increment_generation();
236        // Then decrement the reference count or drop the value if it's the last reference
237        match &mut borrow_mut.data {
238            // If this is the original reference, drop the value
239            RefCellStorageEntryData::Data(_) => borrow_mut.data = RefCellStorageEntryData::Empty,
240            // If this is a rc, just ignore the drop
241            RefCellStorageEntryData::Rc(_) => {}
242            // If this is a reference, decrement the reference count
243            RefCellStorageEntryData::Reference(reference) => {
244                let reference = *reference;
245                drop(borrow_mut);
246                drop_ref(reference);
247            }
248            RefCellStorageEntryData::Empty => {}
249        }
250
251        UNSYNC_RUNTIME.with(|runtime| runtime.borrow_mut().push(pointer.storage));
252    }
253}
254
255fn drop_ref(pointer: GenerationalPointer<UnsyncStorage>) {
256    let mut borrow_mut = pointer.storage.data.borrow_mut();
257
258    // First check if the generation is still valid
259    if !borrow_mut.valid(&pointer.location) {
260        return;
261    }
262
263    if let RefCellStorageEntryData::Rc(entry) = &mut borrow_mut.data {
264        // Decrement the reference count
265        if entry.drop_ref() {
266            // If the reference count is now zero, drop the value
267            borrow_mut.data = RefCellStorageEntryData::Empty;
268            UNSYNC_RUNTIME.with(|runtime| runtime.borrow_mut().push(pointer.storage));
269        }
270    } else {
271        unreachable!("References should always point to a data entry directly",);
272    }
273}
274
275impl<T: 'static> Storage<T> for UnsyncStorage {
276    #[track_caller]
277    fn try_read(
278        pointer: GenerationalPointer<Self>,
279    ) -> Result<Self::Ref<'static, T>, error::BorrowError> {
280        let (read, pointer) = Self::read(pointer)?;
281
282        let ref_ = Ref::filter_map(read, |any| {
283            // Then try to downcast
284            any.downcast_ref()
285        });
286        match ref_ {
287            Ok(guard) => Ok(GenerationalRef::new(
288                guard,
289                pointer.storage.borrow_info.borrow_guard(),
290            )),
291            Err(_) => Err(error::BorrowError::Dropped(
292                error::ValueDroppedError::new_for_location(pointer.location),
293            )),
294        }
295    }
296
297    #[track_caller]
298    fn try_write(
299        pointer: GenerationalPointer<Self>,
300    ) -> Result<Self::Mut<'static, T>, error::BorrowMutError> {
301        let (write, pointer) = Self::write(pointer)?;
302
303        let ref_mut = RefMut::filter_map(write, |any| {
304            // Then try to downcast
305            any.downcast_mut()
306        });
307        match ref_mut {
308            Ok(guard) => Ok(GenerationalRefMut::new(
309                guard,
310                pointer.storage.borrow_info.borrow_mut_guard(),
311            )),
312            Err(_) => Err(error::BorrowMutError::Dropped(
313                error::ValueDroppedError::new_for_location(pointer.location),
314            )),
315        }
316    }
317
318    fn new(value: T, caller: &'static std::panic::Location<'static>) -> GenerationalPointer<Self> {
319        Self::create_new(RefCellStorageEntryData::Data(Box::new(value)), caller)
320    }
321
322    fn new_rc(
323        value: T,
324        caller: &'static std::panic::Location<'static>,
325    ) -> GenerationalPointer<Self> {
326        // Create the data that the rc points to
327        let data = Self::create_new(
328            RefCellStorageEntryData::Rc(RcStorageEntry::new(Box::new(value))),
329            caller,
330        );
331        Self::create_new(RefCellStorageEntryData::Reference(data), caller)
332    }
333
334    fn new_reference(
335        pointer: GenerationalPointer<Self>,
336    ) -> BorrowResult<GenerationalPointer<Self>> {
337        // Chase the reference to get the final location
338        let (pointer, value) = Self::get_split_ref(pointer)?;
339        if let RefCellStorageEntryData::Rc(data) = &value.data {
340            data.add_ref();
341        } else {
342            unreachable!()
343        }
344        Ok(Self::create_new(
345            RefCellStorageEntryData::Reference(pointer),
346            pointer
347                .location
348                .created_at()
349                .unwrap_or(std::panic::Location::caller()),
350        ))
351    }
352
353    fn change_reference(
354        location: GenerationalPointer<Self>,
355        other: GenerationalPointer<Self>,
356    ) -> BorrowResult {
357        if location == other {
358            return Ok(());
359        }
360
361        let (other_final, other_write) = Self::get_split_ref(other)?;
362
363        let mut write = location.storage.data.borrow_mut();
364        // First check if the generation is still valid
365        if !write.valid(&location.location) {
366            return Err(BorrowError::Dropped(ValueDroppedError::new_for_location(
367                location.location,
368            )));
369        }
370
371        if let (RefCellStorageEntryData::Reference(reference), RefCellStorageEntryData::Rc(data)) =
372            (&mut write.data, &other_write.data)
373        {
374            if reference == &other_final {
375                return Ok(());
376            }
377            drop_ref(*reference);
378            *reference = other_final;
379            data.add_ref();
380        } else {
381            tracing::trace!(
382                "References should always point to a data entry directly found {:?} instead",
383                other_write.data
384            );
385            return Err(BorrowError::Dropped(ValueDroppedError::new_for_location(
386                other_final.location,
387            )));
388        }
389
390        Ok(())
391    }
392}