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 ptr_eq(&self, other: &Self) -> bool {
122 self.raw == other.raw
123 }
124
125 pub fn manually_drop(&self)
127 where
128 T: 'static,
129 {
130 self.raw.recycle();
131 }
132
133 pub fn created_at(&self) -> Option<&'static std::panic::Location<'static>> {
135 self.raw.location.created_at()
136 }
137
138 #[track_caller]
140 pub fn leak_reference(&self) -> BorrowResult<GenerationalBox<T, S>> {
141 Ok(Self {
142 raw: S::new_reference(self.raw)?,
143 _marker: std::marker::PhantomData,
144 })
145 }
146
147 pub fn point_to(&self, other: GenerationalBox<T, S>) -> BorrowResult {
149 S::change_reference(self.raw, other.raw)
150 }
151}
152
153impl<T, S> Copy for GenerationalBox<T, S> {}
154
155impl<T, S> Clone for GenerationalBox<T, S> {
156 fn clone(&self) -> Self {
157 *self
158 }
159}
160
161pub trait Storage<Data = ()>: AnyStorage + 'static {
163 fn try_read(pointer: GenerationalPointer<Self>) -> BorrowResult<Self::Ref<'static, Data>>;
165
166 fn try_write(pointer: GenerationalPointer<Self>) -> BorrowMutResult<Self::Mut<'static, Data>>;
168
169 fn new(
171 value: Data,
172 caller: &'static std::panic::Location<'static>,
173 ) -> GenerationalPointer<Self>;
174
175 fn new_rc(
177 value: Data,
178 caller: &'static std::panic::Location<'static>,
179 ) -> GenerationalPointer<Self>;
180
181 fn new_reference(inner: GenerationalPointer<Self>) -> BorrowResult<GenerationalPointer<Self>>;
185
186 fn change_reference(
190 pointer: GenerationalPointer<Self>,
191 rc_pointer: GenerationalPointer<Self>,
192 ) -> BorrowResult;
193}
194
195pub trait AnyStorage: Default + 'static {
197 type Ref<'a, T: ?Sized + 'static>: Deref<Target = T>;
199 type Mut<'a, T: ?Sized + 'static>: DerefMut<Target = T>;
201
202 fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'static>(
206 ref_: Self::Ref<'a, T>,
207 ) -> Self::Ref<'b, T>;
208
209 fn downcast_lifetime_mut<'a: 'b, 'b, T: ?Sized + 'static>(
213 mut_: Self::Mut<'a, T>,
214 ) -> Self::Mut<'b, T>;
215
216 fn try_map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
218 mut_ref: Self::Mut<'_, T>,
219 f: impl FnOnce(&mut T) -> Option<&mut U>,
220 ) -> Option<Self::Mut<'_, U>>;
221
222 fn map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
224 mut_ref: Self::Mut<'_, T>,
225 f: impl FnOnce(&mut T) -> &mut U,
226 ) -> Self::Mut<'_, U> {
227 Self::try_map_mut(mut_ref, |v| Some(f(v))).unwrap()
228 }
229
230 fn try_map<T: ?Sized, U: ?Sized + 'static>(
232 ref_: Self::Ref<'_, T>,
233 f: impl FnOnce(&T) -> Option<&U>,
234 ) -> Option<Self::Ref<'_, U>>;
235
236 fn map<T: ?Sized, U: ?Sized + 'static>(
238 ref_: Self::Ref<'_, T>,
239 f: impl FnOnce(&T) -> &U,
240 ) -> Self::Ref<'_, U> {
241 Self::try_map(ref_, |v| Some(f(v))).unwrap()
242 }
243
244 fn data_ptr(&self) -> *const ();
246
247 fn recycle(location: GenerationalPointer<Self>);
249
250 fn owner() -> Owner<Self> {
252 Owner(Arc::new(Mutex::new(OwnerInner {
253 owned: Default::default(),
254 })))
255 }
256}
257
258#[derive(Debug, Clone, Copy)]
259pub(crate) struct GenerationalLocation {
260 generation: NonZeroU64,
262 #[cfg(any(debug_assertions, feature = "debug_ownership"))]
263 created_at: &'static std::panic::Location<'static>,
264}
265
266impl GenerationalLocation {
267 pub(crate) fn created_at(&self) -> Option<&'static std::panic::Location<'static>> {
268 #[cfg(debug_assertions)]
269 {
270 Some(self.created_at)
271 }
272 #[cfg(not(debug_assertions))]
273 {
274 None
275 }
276 }
277}
278
279pub struct GenerationalPointer<S: 'static = UnsyncStorage> {
281 storage: &'static S,
283 location: GenerationalLocation,
285}
286
287impl<S: AnyStorage + 'static> PartialEq for GenerationalPointer<S> {
288 fn eq(&self, other: &Self) -> bool {
289 self.storage.data_ptr() == other.storage.data_ptr()
290 && self.location.generation == other.location.generation
291 }
292}
293
294impl<S: AnyStorage + 'static> Debug for GenerationalPointer<S> {
295 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296 f.write_fmt(format_args!(
297 "{:?}@{:?}",
298 self.storage.data_ptr(),
299 self.location.generation
300 ))
301 }
302}
303
304impl<S: 'static> Clone for GenerationalPointer<S> {
305 fn clone(&self) -> Self {
306 *self
307 }
308}
309
310impl<S: 'static> Copy for GenerationalPointer<S> {}
311
312impl<S> GenerationalPointer<S> {
313 #[track_caller]
314 fn try_read<T>(self) -> Result<S::Ref<'static, T>, BorrowError>
315 where
316 S: Storage<T>,
317 {
318 S::try_read(self)
319 }
320
321 #[track_caller]
322 fn try_write<T>(self) -> Result<S::Mut<'static, T>, BorrowMutError>
323 where
324 S: Storage<T>,
325 {
326 S::try_write(self)
327 }
328
329 fn recycle(self)
330 where
331 S: AnyStorage,
332 {
333 S::recycle(self);
334 }
335
336 fn id(&self) -> GenerationalBoxId
337 where
338 S: AnyStorage,
339 {
340 GenerationalBoxId {
341 data_ptr: self.storage.data_ptr(),
342 generation: self.location.generation,
343 }
344 }
345}
346
347struct OwnerInner<S: AnyStorage + 'static> {
348 owned: Vec<GenerationalPointer<S>>,
349}
350
351impl<S: AnyStorage> Drop for OwnerInner<S> {
352 fn drop(&mut self) {
353 for location in self.owned.drain(..) {
354 location.recycle();
355 }
356 }
357}
358
359pub struct Owner<S: AnyStorage + 'static = UnsyncStorage>(Arc<Mutex<OwnerInner<S>>>);
361
362impl<S: AnyStorage> Default for Owner<S> {
363 fn default() -> Self {
364 S::owner()
365 }
366}
367
368impl<S: AnyStorage> Clone for Owner<S> {
369 fn clone(&self) -> Self {
370 Self(self.0.clone())
371 }
372}
373
374impl<S: AnyStorage> Owner<S> {
375 #[track_caller]
377 pub fn insert<T: 'static>(&self, value: T) -> GenerationalBox<T, S>
378 where
379 S: Storage<T>,
380 {
381 self.insert_with_caller(value, std::panic::Location::caller())
382 }
383
384 #[track_caller]
386 pub fn insert_rc<T: 'static>(&self, value: T) -> GenerationalBox<T, S>
387 where
388 S: Storage<T>,
389 {
390 self.insert_rc_with_caller(value, std::panic::Location::caller())
391 }
392
393 pub fn insert_rc_with_caller<T: 'static>(
395 &self,
396 value: T,
397 caller: &'static std::panic::Location<'static>,
398 ) -> GenerationalBox<T, S>
399 where
400 S: Storage<T>,
401 {
402 let location = S::new_rc(value, caller);
403 self.0.lock().owned.push(location);
404 GenerationalBox {
405 raw: location,
406 _marker: std::marker::PhantomData,
407 }
408 }
409
410 pub fn insert_with_caller<T: 'static>(
412 &self,
413 value: T,
414 caller: &'static std::panic::Location<'static>,
415 ) -> GenerationalBox<T, S>
416 where
417 S: Storage<T>,
418 {
419 let location = S::new(value, caller);
420 self.0.lock().owned.push(location);
421 GenerationalBox {
422 raw: location,
423 _marker: PhantomData,
424 }
425 }
426
427 #[track_caller]
431 pub fn insert_reference<T: 'static>(
432 &self,
433 other: GenerationalBox<T, S>,
434 ) -> BorrowResult<GenerationalBox<T, S>>
435 where
436 S: Storage<T>,
437 {
438 let location = other.leak_reference()?;
439 self.0.lock().owned.push(location.raw);
440 Ok(location)
441 }
442}