1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4use parking_lot::Mutex;
5use std::{
6 fmt::Debug,
7 marker::PhantomData,
8 num::NonZeroU64,
9 ops::{Deref, DerefMut},
10 sync::Arc,
11};
12
13pub use error::*;
14pub use references::*;
15pub use sync::SyncStorage;
16pub use unsync::UnsyncStorage;
17
18mod entry;
19mod error;
20mod references;
21mod sync;
22mod unsync;
23
24#[derive(Clone, Copy, PartialEq, Eq, Hash)]
26pub struct GenerationalBoxId {
27 data_ptr: *const (),
28 generation: NonZeroU64,
29}
30
31unsafe impl Send for GenerationalBoxId {}
33unsafe impl Sync for GenerationalBoxId {}
34
35impl Debug for GenerationalBoxId {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 f.write_fmt(format_args!("{:?}@{:?}", self.data_ptr, self.generation))?;
38 Ok(())
39 }
40}
41
42pub struct GenerationalBox<T, S: 'static = UnsyncStorage> {
44 raw: GenerationalPointer<S>,
45 _marker: PhantomData<T>,
46}
47
48impl<T, S: AnyStorage> Debug for GenerationalBox<T, S> {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 self.raw.fmt(f)
51 }
52}
53
54impl<T, S: Storage<T>> GenerationalBox<T, S> {
55 #[track_caller]
58 pub fn leak(value: T, location: &'static std::panic::Location<'static>) -> Self {
59 let location = S::new(value, location);
60 Self {
61 raw: location,
62 _marker: PhantomData,
63 }
64 }
65
66 #[track_caller]
69 pub fn leak_rc(value: T, location: &'static std::panic::Location<'static>) -> Self {
70 let location = S::new_rc(value, location);
71 Self {
72 raw: location,
73 _marker: PhantomData,
74 }
75 }
76
77 pub fn raw_ptr(&self) -> *const () {
79 self.raw.storage.data_ptr()
80 }
81
82 pub fn id(&self) -> GenerationalBoxId {
84 self.raw.id()
85 }
86
87 #[track_caller]
89 pub fn try_read(&self) -> Result<S::Ref<'static, T>, BorrowError> {
90 self.raw.try_read()
91 }
92
93 #[track_caller]
95 pub fn read(&self) -> S::Ref<'static, T> {
96 self.try_read().unwrap()
97 }
98
99 #[track_caller]
101 pub fn try_write(&self) -> Result<S::Mut<'static, T>, BorrowMutError> {
102 self.raw.try_write()
103 }
104
105 #[track_caller]
107 pub fn write(&self) -> S::Mut<'static, T> {
108 self.try_write().unwrap()
109 }
110
111 #[track_caller]
113 pub fn set(&self, value: T)
114 where
115 T: 'static,
116 {
117 *self.write() = value;
118 }
119
120 pub fn manually_drop(&self)
122 where
123 T: 'static,
124 {
125 self.raw.recycle();
126 }
127
128 #[track_caller]
130 pub fn leak_reference(&self) -> BorrowResult<GenerationalBox<T, S>> {
131 Ok(Self {
132 raw: S::new_reference(self.raw)?,
133 _marker: std::marker::PhantomData,
134 })
135 }
136
137 pub fn point_to(&self, other: GenerationalBox<T, S>) -> BorrowResult {
139 S::change_reference(self.raw, other.raw)
140 }
141}
142
143impl<T, S> GenerationalBox<T, S> {
144 pub fn ptr_eq(&self, other: &Self) -> bool
146 where
147 S: AnyStorage,
148 {
149 self.raw == other.raw
150 }
151
152 pub fn created_at(&self) -> Option<&'static std::panic::Location<'static>> {
154 self.raw.location.created_at()
155 }
156}
157
158impl<T, S> Copy for GenerationalBox<T, S> {}
159
160impl<T, S> Clone for GenerationalBox<T, S> {
161 fn clone(&self) -> Self {
162 *self
163 }
164}
165
166pub trait Storage<Data = ()>: AnyStorage {
168 fn try_read(pointer: GenerationalPointer<Self>) -> BorrowResult<Self::Ref<'static, Data>>;
170
171 fn try_write(pointer: GenerationalPointer<Self>) -> BorrowMutResult<Self::Mut<'static, Data>>;
173
174 fn new(
176 value: Data,
177 caller: &'static std::panic::Location<'static>,
178 ) -> GenerationalPointer<Self>;
179
180 fn new_rc(
182 value: Data,
183 caller: &'static std::panic::Location<'static>,
184 ) -> GenerationalPointer<Self>;
185
186 fn new_reference(inner: GenerationalPointer<Self>) -> BorrowResult<GenerationalPointer<Self>>;
190
191 fn change_reference(
195 pointer: GenerationalPointer<Self>,
196 rc_pointer: GenerationalPointer<Self>,
197 ) -> BorrowResult;
198}
199
200pub trait AnyStorage: Default {
202 type Ref<'a, T: ?Sized + 'a>: Deref<Target = T>;
204 type Mut<'a, T: ?Sized + 'a>: DerefMut<Target = T>;
206
207 fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'a>(
211 ref_: Self::Ref<'a, T>,
212 ) -> Self::Ref<'b, T>;
213
214 fn downcast_lifetime_mut<'a: 'b, 'b, T: ?Sized + 'a>(
218 mut_: Self::Mut<'a, T>,
219 ) -> Self::Mut<'b, T>;
220
221 fn try_map_mut<T: ?Sized, U: ?Sized>(
223 mut_ref: Self::Mut<'_, T>,
224 f: impl FnOnce(&mut T) -> Option<&mut U>,
225 ) -> Option<Self::Mut<'_, U>>;
226
227 fn map_mut<T: ?Sized, U: ?Sized>(
229 mut_ref: Self::Mut<'_, T>,
230 f: impl FnOnce(&mut T) -> &mut U,
231 ) -> Self::Mut<'_, U> {
232 Self::try_map_mut(mut_ref, |v| Some(f(v))).unwrap()
233 }
234
235 fn try_map<T: ?Sized, U: ?Sized>(
237 ref_: Self::Ref<'_, T>,
238 f: impl FnOnce(&T) -> Option<&U>,
239 ) -> Option<Self::Ref<'_, U>>;
240
241 fn map<T: ?Sized, U: ?Sized>(
243 ref_: Self::Ref<'_, T>,
244 f: impl FnOnce(&T) -> &U,
245 ) -> Self::Ref<'_, U> {
246 Self::try_map(ref_, |v| Some(f(v))).unwrap()
247 }
248
249 fn data_ptr(&self) -> *const ();
251
252 fn recycle(location: GenerationalPointer<Self>);
254
255 fn owner() -> Owner<Self>
257 where
258 Self: 'static,
259 {
260 Owner(Arc::new(Mutex::new(OwnerInner {
261 owned: Default::default(),
262 })))
263 }
264}
265
266#[derive(Debug, Clone, Copy)]
267pub(crate) struct GenerationalLocation {
268 generation: NonZeroU64,
270 #[cfg(any(debug_assertions, feature = "debug_ownership"))]
271 created_at: &'static std::panic::Location<'static>,
272}
273
274impl GenerationalLocation {
275 pub(crate) fn created_at(&self) -> Option<&'static std::panic::Location<'static>> {
276 #[cfg(debug_assertions)]
277 {
278 Some(self.created_at)
279 }
280 #[cfg(not(debug_assertions))]
281 {
282 None
283 }
284 }
285}
286
287pub struct GenerationalPointer<S: 'static = UnsyncStorage> {
289 storage: &'static S,
291 location: GenerationalLocation,
293}
294
295impl<S: AnyStorage + 'static> PartialEq for GenerationalPointer<S> {
296 fn eq(&self, other: &Self) -> bool {
297 self.storage.data_ptr() == other.storage.data_ptr()
298 && self.location.generation == other.location.generation
299 }
300}
301
302impl<S: AnyStorage + 'static> Debug for GenerationalPointer<S> {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 f.write_fmt(format_args!(
305 "{:?}@{:?}",
306 self.storage.data_ptr(),
307 self.location.generation
308 ))
309 }
310}
311
312impl<S: 'static> Clone for GenerationalPointer<S> {
313 fn clone(&self) -> Self {
314 *self
315 }
316}
317
318impl<S: 'static> Copy for GenerationalPointer<S> {}
319
320impl<S> GenerationalPointer<S> {
321 #[track_caller]
322 fn try_read<T>(self) -> Result<S::Ref<'static, T>, BorrowError>
323 where
324 S: Storage<T>,
325 {
326 S::try_read(self)
327 }
328
329 #[track_caller]
330 fn try_write<T>(self) -> Result<S::Mut<'static, T>, BorrowMutError>
331 where
332 S: Storage<T>,
333 {
334 S::try_write(self)
335 }
336
337 fn recycle(self)
338 where
339 S: AnyStorage,
340 {
341 S::recycle(self);
342 }
343
344 fn id(&self) -> GenerationalBoxId
345 where
346 S: AnyStorage,
347 {
348 GenerationalBoxId {
349 data_ptr: self.storage.data_ptr(),
350 generation: self.location.generation,
351 }
352 }
353}
354
355struct OwnerInner<S: AnyStorage + 'static> {
356 owned: Vec<GenerationalPointer<S>>,
357}
358
359impl<S: AnyStorage> Drop for OwnerInner<S> {
360 fn drop(&mut self) {
361 for location in self.owned.drain(..) {
362 location.recycle();
363 }
364 }
365}
366
367pub struct Owner<S: AnyStorage + 'static = UnsyncStorage>(Arc<Mutex<OwnerInner<S>>>);
369
370impl<S: AnyStorage> Default for Owner<S> {
371 fn default() -> Self {
372 S::owner()
373 }
374}
375
376impl<S: AnyStorage> Clone for Owner<S> {
377 fn clone(&self) -> Self {
378 Self(self.0.clone())
379 }
380}
381
382impl<S: AnyStorage> Owner<S> {
383 #[track_caller]
385 pub fn insert<T>(&self, value: T) -> GenerationalBox<T, S>
386 where
387 S: Storage<T>,
388 {
389 self.insert_with_caller(value, std::panic::Location::caller())
390 }
391
392 #[track_caller]
394 pub fn insert_rc<T>(&self, value: T) -> GenerationalBox<T, S>
395 where
396 S: Storage<T>,
397 {
398 self.insert_rc_with_caller(value, std::panic::Location::caller())
399 }
400
401 pub fn insert_rc_with_caller<T>(
403 &self,
404 value: T,
405 caller: &'static std::panic::Location<'static>,
406 ) -> GenerationalBox<T, S>
407 where
408 S: Storage<T>,
409 {
410 let location = S::new_rc(value, caller);
411 self.0.lock().owned.push(location);
412 GenerationalBox {
413 raw: location,
414 _marker: std::marker::PhantomData,
415 }
416 }
417
418 pub fn insert_with_caller<T>(
420 &self,
421 value: T,
422 caller: &'static std::panic::Location<'static>,
423 ) -> GenerationalBox<T, S>
424 where
425 S: Storage<T>,
426 {
427 let location = S::new(value, caller);
428 self.0.lock().owned.push(location);
429 GenerationalBox {
430 raw: location,
431 _marker: PhantomData,
432 }
433 }
434
435 #[track_caller]
439 pub fn insert_reference<T>(
440 &self,
441 other: GenerationalBox<T, S>,
442 ) -> BorrowResult<GenerationalBox<T, S>>
443 where
444 S: Storage<T>,
445 {
446 let location = other.leak_reference()?;
447 self.0.lock().owned.push(location.raw);
448 Ok(location)
449 }
450}