generational_box/
references.rs

1use std::{
2    fmt::{Debug, Display},
3    ops::{Deref, DerefMut},
4};
5
6/// A reference to a value in a generational box. This reference acts similarly to [`std::cell::Ref`], but has extra debug information
7/// to track when all references to the value are created and dropped.
8///
9/// [`GenerationalRef`] implements [`Deref`] which means you can call methods on the inner value just like you would on a reference to the
10/// inner value. If you need to get the inner reference directly, you can call [`GenerationalRef::deref`].
11///
12/// # Example
13/// ```rust
14/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
15/// let owner = UnsyncStorage::owner();
16/// let value = owner.insert(String::from("hello"));
17/// let reference = value.read();
18///
19/// // You call methods like `as_str` on the reference just like you would with the inner String
20/// assert_eq!(reference.as_str(), "hello");
21/// ```
22///
23/// ## Matching on GenerationalRef
24///
25/// You need to get the inner reference with [`GenerationalRef::deref`] before you match the inner value. If you try to match without
26/// calling [`GenerationalRef::deref`], you will get an error like this:
27///
28/// ```compile_fail
29/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
30/// enum Colors {
31///     Red,
32///     Green
33/// }
34/// let owner = UnsyncStorage::owner();
35/// let value = owner.insert(Colors::Red);
36/// let reference = value.read();
37///
38/// match reference {
39///     // Since we are matching on the `GenerationalRef` type instead of &Colors, we can't match on the enum directly
40///     Colors::Red => {}
41///     Colors::Green => {}
42/// }
43/// ```
44///
45/// ```text
46/// error[E0308]: mismatched types
47///   --> packages/generational-box/tests/basic.rs:25:9
48///   |
49/// 2 |         Red,
50///   |         --- unit variant defined here
51/// ...
52/// 3 |     match reference {
53///   |           --------- this expression has type `GenerationalRef<Ref<'_, Colors>>`
54/// 4 |         // Since we are matching on the `GenerationalRef` type instead of &Colors, we can't match on the enum directly
55/// 5 |         Colors::Red => {}
56///   |         ^^^^^^^^^^^ expected `GenerationalRef<Ref<'_, Colors>>`, found `Colors`
57///   |
58///   = note: expected struct `GenerationalRef<Ref<'_, Colors>>`
59///                found enum `Colors`
60/// ```
61///
62/// Instead, you need to deref the reference to get the inner value **before** you match on it:
63///
64/// ```rust
65/// use std::ops::Deref;
66/// # use generational_box::{AnyStorage, Owner, UnsyncStorage};
67/// enum Colors {
68///     Red,
69///     Green
70/// }
71/// let owner = UnsyncStorage::owner();
72/// let value = owner.insert(Colors::Red);
73/// let reference = value.read();
74///
75/// // Deref converts the `GenerationalRef` into a `&Colors`
76/// match reference.deref() {
77///     // Now we can match on the inner value
78///     Colors::Red => {}
79///     Colors::Green => {}
80/// }
81/// ```
82pub struct GenerationalRef<R> {
83    pub(crate) inner: R,
84    guard: GenerationalRefBorrowGuard,
85}
86
87impl<T: ?Sized, R: Deref<Target = T>> GenerationalRef<R> {
88    pub(crate) fn new(inner: R, guard: GenerationalRefBorrowGuard) -> Self {
89        Self { inner, guard }
90    }
91
92    /// Map the inner value to a new type
93    pub fn map<R2, F: FnOnce(R) -> R2>(self, f: F) -> GenerationalRef<R2> {
94        GenerationalRef {
95            inner: f(self.inner),
96            guard: self.guard,
97        }
98    }
99
100    /// Try to map the inner value to a new type
101    pub fn try_map<R2, F: FnOnce(R) -> Option<R2>>(self, f: F) -> Option<GenerationalRef<R2>> {
102        f(self.inner).map(|inner| GenerationalRef {
103            inner,
104            guard: self.guard,
105        })
106    }
107
108    /// Clone the inner value. This requires that the inner value implements [`Clone`].
109    pub fn cloned(&self) -> T
110    where
111        T: Clone,
112    {
113        self.inner.deref().clone()
114    }
115}
116
117impl<T: ?Sized + Debug, R: Deref<Target = T>> Debug for GenerationalRef<R> {
118    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119        self.inner.deref().fmt(f)
120    }
121}
122
123impl<T: ?Sized + Display, R: Deref<Target = T>> Display for GenerationalRef<R> {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        self.inner.deref().fmt(f)
126    }
127}
128
129impl<T: ?Sized, R: Deref<Target = T>> Deref for GenerationalRef<R> {
130    type Target = T;
131
132    fn deref(&self) -> &Self::Target {
133        self.inner.deref()
134    }
135}
136
137pub(crate) struct GenerationalRefBorrowGuard {
138    #[cfg(any(debug_assertions, feature = "debug_borrows"))]
139    pub(crate) borrowed_at: &'static std::panic::Location<'static>,
140    #[cfg(any(debug_assertions, feature = "debug_borrows"))]
141    pub(crate) borrowed_from: &'static crate::entry::MemoryLocationBorrowInfo,
142}
143
144#[cfg(any(debug_assertions, feature = "debug_borrows"))]
145impl Drop for GenerationalRefBorrowGuard {
146    fn drop(&mut self) {
147        self.borrowed_from.drop_borrow(self.borrowed_at);
148    }
149}
150
151/// A mutable reference to a value in a generational box. This reference acts similarly to [`std::cell::RefMut`], but has extra debug information
152/// to track when all references to the value are created and dropped.
153///
154/// [`GenerationalRefMut`] implements [`DerefMut`] which means you can call methods on the inner value just like you would on a mutable reference
155/// to the inner value. If you need to get the inner reference directly, you can call [`GenerationalRefMut::deref_mut`].
156///
157/// # Example
158/// ```rust
159/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
160/// let owner = UnsyncStorage::owner();
161/// let mut value = owner.insert(String::from("hello"));
162/// let mut mutable_reference = value.write();
163///
164/// // You call methods like `push_str` on the reference just like you would with the inner String
165/// mutable_reference.push_str("world");
166/// ```
167///
168/// ## Matching on GenerationalMut
169///
170/// You need to get the inner mutable reference with [`GenerationalRefMut::deref_mut`] before you match the inner value. If you try to match
171/// without calling [`GenerationalRefMut::deref_mut`], you will get an error like this:
172///
173/// ```compile_fail
174/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
175/// enum Colors {
176///     Red(u32),
177///     Green
178/// }
179/// let owner = UnsyncStorage::owner();
180/// let mut value = owner.insert(Colors::Red(0));
181/// let mut mutable_reference = value.write();
182///
183/// match mutable_reference {
184///     // Since we are matching on the `GenerationalRefMut` type instead of &mut Colors, we can't match on the enum directly
185///     Colors::Red(brightness) => *brightness += 1,
186///     Colors::Green => {}
187/// }
188/// ```
189///
190/// ```text
191/// error[E0308]: mismatched types
192///   --> packages/generational-box/tests/basic.rs:25:9
193///    |
194/// 9  |     match mutable_reference {
195///    |           ----------------- this expression has type `GenerationalRefMut<RefMut<'_, fn(u32) -> Colors {Colors::Red}>>`
196/// 10 |         // Since we are matching on the `GenerationalRefMut` type instead of &mut Colors, we can't match on the enum directly
197/// 11 |         Colors::Red(brightness) => *brightness += 1,
198///    |         ^^^^^^^^^^^^^^^^^^^^^^^ expected `GenerationalRefMut<RefMut<'_, ...>>`, found `Colors`
199///    |
200///    = note: expected struct `GenerationalRefMut<RefMut<'_, fn(u32) -> Colors {Colors::Red}>>`
201///                found enum `Colors`
202/// ```
203///
204/// Instead, you need to call deref mut on the reference to get the inner value **before** you match on it:
205///
206/// ```rust
207/// use std::ops::DerefMut;
208/// # use generational_box::{AnyStorage, Owner, UnsyncStorage};
209/// enum Colors {
210///     Red(u32),
211///     Green
212/// }
213/// let owner = UnsyncStorage::owner();
214/// let mut value = owner.insert(Colors::Red(0));
215/// let mut mutable_reference = value.write();
216///
217/// // DerefMut converts the `GenerationalRefMut` into a `&mut Colors`
218/// match mutable_reference.deref_mut() {
219///     // Now we can match on the inner value
220///     Colors::Red(brightness) => *brightness += 1,
221///     Colors::Green => {}
222/// }
223/// ```
224pub struct GenerationalRefMut<W> {
225    pub(crate) inner: W,
226    pub(crate) borrow: GenerationalRefBorrowMutGuard,
227}
228
229impl<T: ?Sized, R: DerefMut<Target = T>> GenerationalRefMut<R> {
230    pub(crate) fn new(inner: R, borrow: GenerationalRefBorrowMutGuard) -> Self {
231        Self { inner, borrow }
232    }
233
234    /// Map the inner value to a new type
235    pub fn map<R2, F: FnOnce(R) -> R2>(self, f: F) -> GenerationalRefMut<R2> {
236        GenerationalRefMut {
237            inner: f(self.inner),
238            borrow: self.borrow,
239        }
240    }
241
242    /// Try to map the inner value to a new type
243    pub fn try_map<R2, F: FnOnce(R) -> Option<R2>>(self, f: F) -> Option<GenerationalRefMut<R2>> {
244        f(self.inner).map(|inner| GenerationalRefMut {
245            inner,
246            borrow: self.borrow,
247        })
248    }
249}
250
251impl<T: ?Sized, W: DerefMut<Target = T>> Deref for GenerationalRefMut<W> {
252    type Target = T;
253
254    fn deref(&self) -> &Self::Target {
255        self.inner.deref()
256    }
257}
258
259impl<T: ?Sized, W: DerefMut<Target = T>> DerefMut for GenerationalRefMut<W> {
260    fn deref_mut(&mut self) -> &mut Self::Target {
261        self.inner.deref_mut()
262    }
263}
264
265pub(crate) struct GenerationalRefBorrowMutGuard {
266    #[cfg(any(debug_assertions, feature = "debug_borrows"))]
267    /// The location where the borrow occurred.
268    pub(crate) borrowed_from: &'static crate::entry::MemoryLocationBorrowInfo,
269    #[cfg(any(debug_assertions, feature = "debug_borrows"))]
270    pub(crate) borrowed_mut_at: &'static std::panic::Location<'static>,
271}
272
273#[cfg(any(debug_assertions, feature = "debug_borrows"))]
274impl Drop for GenerationalRefBorrowMutGuard {
275    fn drop(&mut self) {
276        self.borrowed_from.drop_borrow_mut(self.borrowed_mut_at);
277    }
278}