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