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 + 'static, 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
109impl<T: ?Sized + Debug, R: Deref<Target = T>> Debug for GenerationalRef<R> {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 self.inner.deref().fmt(f)
112 }
113}
114
115impl<T: ?Sized + Display, R: Deref<Target = T>> Display for GenerationalRef<R> {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 self.inner.deref().fmt(f)
118 }
119}
120
121impl<T: ?Sized + 'static, R: Deref<Target = T>> Deref for GenerationalRef<R> {
122 type Target = T;
123
124 fn deref(&self) -> &Self::Target {
125 self.inner.deref()
126 }
127}
128
129pub(crate) struct GenerationalRefBorrowGuard {
130 #[cfg(any(debug_assertions, feature = "debug_borrows"))]
131 pub(crate) borrowed_at: &'static std::panic::Location<'static>,
132 #[cfg(any(debug_assertions, feature = "debug_borrows"))]
133 pub(crate) borrowed_from: &'static crate::entry::MemoryLocationBorrowInfo,
134}
135
136#[cfg(any(debug_assertions, feature = "debug_borrows"))]
137impl Drop for GenerationalRefBorrowGuard {
138 fn drop(&mut self) {
139 self.borrowed_from.drop_borrow(self.borrowed_at);
140 }
141}
142
143/// A mutable reference to a value in a generational box. This reference acts similarly to [`std::cell::RefMut`], but has extra debug information
144/// to track when all references to the value are created and dropped.
145///
146/// [`GenerationalRefMut`] implements [`DerefMut`] which means you can call methods on the inner value just like you would on a mutable reference
147/// to the inner value. If you need to get the inner reference directly, you can call [`GenerationalRefMut::deref_mut`].
148///
149/// # Example
150/// ```rust
151/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
152/// let owner = UnsyncStorage::owner();
153/// let mut value = owner.insert(String::from("hello"));
154/// let mut mutable_reference = value.write();
155///
156/// // You call methods like `push_str` on the reference just like you would with the inner String
157/// mutable_reference.push_str("world");
158/// ```
159///
160/// ## Matching on GenerationalMut
161///
162/// You need to get the inner mutable reference with [`GenerationalRefMut::deref_mut`] before you match the inner value. If you try to match
163/// without calling [`GenerationalRefMut::deref_mut`], you will get an error like this:
164///
165/// ```compile_fail
166/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
167/// enum Colors {
168/// Red(u32),
169/// Green
170/// }
171/// let owner = UnsyncStorage::owner();
172/// let mut value = owner.insert(Colors::Red(0));
173/// let mut mutable_reference = value.write();
174///
175/// match mutable_reference {
176/// // Since we are matching on the `GenerationalRefMut` type instead of &mut Colors, we can't match on the enum directly
177/// Colors::Red(brightness) => *brightness += 1,
178/// Colors::Green => {}
179/// }
180/// ```
181///
182/// ```text
183/// error[E0308]: mismatched types
184/// --> packages/generational-box/tests/basic.rs:25:9
185/// |
186/// 9 | match mutable_reference {
187/// | ----------------- this expression has type `GenerationalRefMut<RefMut<'_, fn(u32) -> Colors {Colors::Red}>>`
188/// 10 | // Since we are matching on the `GenerationalRefMut` type instead of &mut Colors, we can't match on the enum directly
189/// 11 | Colors::Red(brightness) => *brightness += 1,
190/// | ^^^^^^^^^^^^^^^^^^^^^^^ expected `GenerationalRefMut<RefMut<'_, ...>>`, found `Colors`
191/// |
192/// = note: expected struct `GenerationalRefMut<RefMut<'_, fn(u32) -> Colors {Colors::Red}>>`
193/// found enum `Colors`
194/// ```
195///
196/// Instead, you need to call deref mut on the reference to get the inner value **before** you match on it:
197///
198/// ```rust
199/// use std::ops::DerefMut;
200/// # use generational_box::{AnyStorage, Owner, UnsyncStorage};
201/// enum Colors {
202/// Red(u32),
203/// Green
204/// }
205/// let owner = UnsyncStorage::owner();
206/// let mut value = owner.insert(Colors::Red(0));
207/// let mut mutable_reference = value.write();
208///
209/// // DerefMut converts the `GenerationalRefMut` into a `&mut Colors`
210/// match mutable_reference.deref_mut() {
211/// // Now we can match on the inner value
212/// Colors::Red(brightness) => *brightness += 1,
213/// Colors::Green => {}
214/// }
215/// ```
216pub struct GenerationalRefMut<W> {
217 pub(crate) inner: W,
218 pub(crate) borrow: GenerationalRefBorrowMutGuard,
219}
220
221impl<T: ?Sized + 'static, R: DerefMut<Target = T>> GenerationalRefMut<R> {
222 pub(crate) fn new(inner: R, borrow: GenerationalRefBorrowMutGuard) -> Self {
223 Self { inner, borrow }
224 }
225
226 /// Map the inner value to a new type
227 pub fn map<R2, F: FnOnce(R) -> R2>(self, f: F) -> GenerationalRefMut<R2> {
228 GenerationalRefMut {
229 inner: f(self.inner),
230 borrow: self.borrow,
231 }
232 }
233
234 /// Try to map the inner value to a new type
235 pub fn try_map<R2, F: FnOnce(R) -> Option<R2>>(self, f: F) -> Option<GenerationalRefMut<R2>> {
236 f(self.inner).map(|inner| GenerationalRefMut {
237 inner,
238 borrow: self.borrow,
239 })
240 }
241}
242
243impl<T: ?Sized, W: DerefMut<Target = T>> Deref for GenerationalRefMut<W> {
244 type Target = T;
245
246 fn deref(&self) -> &Self::Target {
247 self.inner.deref()
248 }
249}
250
251impl<T: ?Sized, W: DerefMut<Target = T>> DerefMut for GenerationalRefMut<W> {
252 fn deref_mut(&mut self) -> &mut Self::Target {
253 self.inner.deref_mut()
254 }
255}
256
257pub(crate) struct GenerationalRefBorrowMutGuard {
258 #[cfg(any(debug_assertions, feature = "debug_borrows"))]
259 /// The location where the borrow occurred.
260 pub(crate) borrowed_from: &'static crate::entry::MemoryLocationBorrowInfo,
261 #[cfg(any(debug_assertions, feature = "debug_borrows"))]
262 pub(crate) borrowed_mut_at: &'static std::panic::Location<'static>,
263}
264
265#[cfg(any(debug_assertions, feature = "debug_borrows"))]
266impl Drop for GenerationalRefBorrowMutGuard {
267 fn drop(&mut self) {
268 self.borrowed_from.drop_borrow_mut(self.borrowed_mut_at);
269 }
270}