arid/
lib.rs

1//! An ergonomic object-model for Rust.
2//!
3//! Behold, a doubly-linked-list! No `RefCell`s are required despite the data-structure being full
4//! of reference cycles.
5//!
6//! ```
7//! use arid::{Object as _, Handle as _, object, Strong, W};
8//!
9//! #[derive(Debug)]
10//! pub struct List {
11//!     head: Option<Strong<NodeHandle>>,
12//!     tail: Option<NodeHandle>,
13//! }
14//!
15//! #[derive(Debug)]
16//! pub struct Node {
17//!     list: Option<ListHandle>,
18//!     value: u32,
19//!     prev: Option<NodeHandle>,
20//!     next: Option<Strong<NodeHandle>>,
21//! }
22//!
23//! object!(pub List, pub Node);
24//!
25//! impl ListHandle {
26//!     pub fn new(w: W) -> Strong<Self> {
27//!         List { head: None, tail: None }.spawn(w)
28//!     }
29//!
30//!     pub fn add_after(self, prev: Option<NodeHandle>, node: NodeHandle, w: W) {
31//!         // Validate operation.
32//!         assert!(node.r(w).list.is_none());
33//!         assert!(prev.is_none_or(|prev| prev.r(w).list == Some(self)));
34//!
35//!         node.m(w).list = Some(self);
36//!
37//!         // Establish links with the previous node.
38//!         node.m(w).prev = prev;  // prev <- node
39//!
40//!         // prev -> node
41//!         let node_strong = node.as_strong(w);
42//!         let next = if let Some(prev) = prev {
43//!             prev.m(w).next.replace(node_strong)
44//!         } else {
45//!             self.m(w).head = Some(node_strong);
46//!             None
47//!         };
48//!
49//!         // Establish links with the next node.
50//!         // node <- next
51//!         if let Some(next) = next.as_ref() {
52//!             next.m(w).prev = Some(node);
53//!         } else {
54//!             self.m(w).tail = Some(node);
55//!         }
56//!
57//!         node.m(w).next = next;  // node -> next
58//!     }
59//! }
60//! ```
61//!
62//! # Motivation
63//!
64//! The core idea behind `arid` is to tie all object borrows to some parent [`World`] instance. That
65//! is, we make each smart-pointer accessible by methods such as these...
66//!
67//! ```
68//! # struct World;
69//! # struct MyObjectHandle;
70//! # struct MyObject;
71//! impl MyObjectHandle {
72//!     /// Borrow the smart-pointer's value immutably.
73//!     fn r<'w>(self, world: &'w World) -> &'w MyObject {
74//! # /*
75//!         ...
76//! # */ todo!()
77//!     }
78//!
79//!     /// Borrow the smart-pointer's value mutably.
80//!     fn m<'w>(self, world: &'w mut World) -> &'w mut MyObject {
81//! # /*
82//!         ...
83//! # */ todo!()
84//!     }
85//! }
86//! ```
87//!
88//! One major implication of this model is that no borrows have to be validated at runtime,
89//! eliminating an entire class of runtime bugs and reducing runtime overhead slightly. This is
90//! especially valuable since runtime borrow checker violations can happen at a distance, may
91//! not always be exercised under all circumstances, and can be introduced invisibly depending on
92//! the timing of [`Ref`](std::cell::Ref) guard drops.
93//!
94//! The other major implication of this model, however, is that *only one object can be borrowed at
95//! a time!* The "magic" of `arid`, then, is the way it hides this restriction in practice. We do
96//! this in three main ways:
97//!
98//! 1. First, we make smart pointers (a.k.a handles) [`Copy`]able.
99//!
100//!    This removes one incentive for users to create long-term borrows from a dereferenced object
101//!    since handles can be implicitly copied out of the dereferenced object without needing an
102//!    explicit `.clone()`. By making more borrow sites short-lived, we avoid a large number of
103//!    borrow checker violations which may otherwise crop up from our strict "single borrow at a
104//!    time" restriction.
105//!
106//! 2. Second, we allow smart pointers to be receivers on `impl` blocks.
107//!
108//!    This allows users to interweave multiple mutable borrows within a single method body while
109//!    still keeping a subject-verb-style calling syntax for object methods.
110//!
111//! 3. Third, we set a convention to always pass the `world` at the end of each argument list.
112//!
113//!    This is quite important since arguments are evaluated in the order they appear in a function
114//!    call. If, instead, we passed the `world` in the first argument of a call expression, the
115//!    subsequent argument expressions would have to contend with a concurrent borrow in that first
116//!    argument.
117//!
118//! These three decisions placate the borrow checker for most usage patterns, making the system
119//! quite ergonomic compared to its more traditional alternatives.
120//!
121//! # Basic Usage
122//!
123//! All object instances in the `arid` object model are owned by exactly one [`World`]. It can be
124//! instantiated anywhere with...
125//!
126//! ```
127//! use arid::World;
128//!
129//! let mut w = World::new();
130//! let w = &mut w;
131//! ```
132//!
133//! By convention, we try to ensure that the `world` for any given function body is named `w` and
134//! corresponds to an (im)mutable borrow of the world.
135//!
136//! We can then define the object types which live inside a world using the [`object!`] macro like
137//! so...
138//!
139//! ```
140//! use arid::object;
141//!
142//! #[derive(Debug)]
143//! pub struct MyObject {
144//!     count: u32,
145//! }
146//!
147//! object!(pub MyObject);
148//! ```
149//!
150//! The `object!` macro takes the name of a structure within the current scope (e.g. `MyObject`) and
151//! does a couple things...
152//!
153//! - It implements the [`Object`] trait for the target type `MyObject`.
154//! - It defines a newtype for handles of that object and calls the newtype `<StructName>Handle`
155//!   (in our case, `MyObjectHandle`). The visibility of this newtype is taken from the macro
156//!   invocation and must match the visibility of the value structure.
157//! - It implements the [`Handle`] trait for that handle newtype structure.
158//!
159//! The requirements for defining an object are minimal: it must be [`Sized`], live for `'static`,
160//! and implement [`Debug`](std::fmt::Debug).
161//!
162//! The `Object` trait exposes an [`Object::spawn`] method to allocate an object instance into a
163//! given `World`. We can use it like so...
164//!
165//! ```
166//! # use arid::World;
167//! #
168//! # let mut w = World::new();
169//! # let w = &mut w;
170//! #
171//! # use arid::object;
172//! #
173//! # #[derive(Debug)]
174//! # pub struct MyObject {
175//! #     count: u32,
176//! # }
177//! #
178//! # object!(pub MyObject);
179//! #
180//! use arid::Object as _;
181//!
182//! let my_counter = MyObject { count: 1 }.spawn(w);
183//! ```
184//!
185//! We can then access the handle's value immutably using the [`Handle::r`] method and mutably using
186//! the [`Handle::m`] method.
187//!
188//! ```
189//! # use arid::World;
190//! #
191//! # let mut w = World::new();
192//! # let w = &mut w;
193//! #
194//! # use arid::object;
195//! #
196//! # #[derive(Debug)]
197//! # pub struct MyObject {
198//! #     count: u32,
199//! # }
200//! #
201//! # object!(pub MyObject);
202//! #
203//! # use arid::Object as _;
204//! #
205//! # let my_counter = MyObject { count: 1 }.spawn(w);
206//! use arid::Handle as _;
207//!
208//! my_counter.m(w).count += 1;
209//! assert_eq!(my_counter.r(w).count, 2);
210//! ```
211//!
212//! Since each object's corresponding handle newtype is declared in the crate which invoked the
213//! `object!` macro, we are allowed to implement inherent methods and traits directly onto the
214//! handle.
215//!
216//! ```
217//! # use arid::World;
218//! #
219//! # let mut w = World::new();
220//! # let w = &mut w;
221//! #
222//! # use arid::object;
223//! #
224//! # #[derive(Debug)]
225//! # pub struct MyObject {
226//! #     count: u32,
227//! # }
228//! #
229//! # object!(pub MyObject);
230//! #
231//! # use arid::Object as _;
232//! #
233//! # let my_counter = MyObject { count: 1 }.spawn(w);
234//! # use arid::Handle as _;
235//! #
236//! # my_counter.m(w).count += 1;
237//! # assert_eq!(my_counter.r(w).count, 2);
238//! use arid::{W, Wr};
239//!
240//! impl MyObjectHandle {
241//!     pub fn increment(self, w: W) {
242//!         self.m(w).count += 1;
243//!     }
244//!
245//!     pub fn is_less_than(self, other: u32, w: Wr) -> bool {
246//!         self.r(w).count < other
247//!     }
248//! }
249//!
250//! assert!(my_counter.is_less_than(3, w));
251//! my_counter.increment(w);
252//! assert!(!my_counter.is_less_than(3, w));
253//! ```
254//!
255//! Note that [`W`] is just an alias to a `&mut World` and [`Wr`] is just an alias to a `&World`.
256//! Rust allows you to elide the lifetime of these type aliases in most cases. Rust implicitly
257//! reborrows references when they're passed directly to a function, which allows us to avoid
258//! explicit `&mut *w` and `&*w` reborrowing syntax.
259//!
260//! <div class="warning">
261//!
262//! Also note that, by convention, ***the `world` parameter always goes last*** to help the borrow
263//! checker understand more valid code.
264//!
265//! <details><summary><strong style="cursor: pointer">Justification</strong></summary>
266//!
267//! This convention is valuable because Rust always evaluates function call arguments in their
268//! syntactic order. If the world were to be passed first, the function's borrow of that world would
269//! happen before all subsequent arguments were evaluated, preventing those arguments from borrowing
270//! the world mutably.
271//!
272//! This code disrespects the conventions and gets a borrow checker error:
273//!
274//! ```compile_fail
275//! # use arid::World;
276//! #
277//! # let mut w = World::new();
278//! # let w = &mut w;
279//! #
280//! # use arid::object;
281//! #
282//! # #[derive(Debug)]
283//! # pub struct MyObject {
284//! #     count: u32,
285//! # }
286//! #
287//! # object!(pub MyObject);
288//! #
289//! # use arid::Object as _;
290//! #
291//! # let my_counter = MyObject { count: 1 }.spawn(w);
292//! # use arid::Handle as _;
293//! #
294//! # my_counter.m(w).count += 1;
295//! # assert_eq!(my_counter.r(w).count, 2);
296//! # use arid::{W, Wr};
297//! impl MyObjectHandle {
298//!     pub fn increment_by(self, w: W, delta: u32) {
299//!         self.m(w).count += delta;
300//!     }
301//! }
302//!
303//! // Double the count!
304//! my_counter.increment_by(w, my_counter.m(w).count);
305//! ```
306//!
307//! ```text
308//! error[E0499]: cannot borrow `*w` as mutable more than once at a time
309//!   --> convention.rs:33:41
310//!    |
311//! 33 | my_counter.increment_by(w, my_counter.m(w).count);
312//!    |            ------------ -               ^ second mutable borrow occurs here
313//!    |            |            |
314//!    |            |            first mutable borrow occurs here
315//!    |            first borrow later used by call
316//!    |
317//! help: try adding a local storing this argument...
318//!   --> convention.rs:33:28
319//!    |
320//! 33 | my_counter.increment_by(w, my_counter.m(w).count);
321//!    |                            ^^^^^^^^^^^^^^^
322//! help: ...and then using that local as the argument to this call
323//!   --> convention.rs:33:1
324//!    |
325//! 33 | my_counter.increment_by(w, my_counter.m(w).count);
326//!    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
327//! ```
328//!
329//! If we reordered the arguments, the error would go away!
330//!
331//! ```
332//! # use arid::World;
333//! #
334//! # let mut w = World::new();
335//! # let w = &mut w;
336//! #
337//! # use arid::object;
338//! #
339//! # #[derive(Debug)]
340//! # pub struct MyObject {
341//! #     count: u32,
342//! # }
343//! #
344//! # object!(pub MyObject);
345//! #
346//! # use arid::Object as _;
347//! #
348//! # let my_counter = MyObject { count: 1 }.spawn(w);
349//! # use arid::Handle as _;
350//! #
351//! # my_counter.m(w).count += 1;
352//! # assert_eq!(my_counter.r(w).count, 2);
353//! # use arid::{W, Wr};
354//! impl MyObjectHandle {
355//!     pub fn increment_by(self, delta: u32, w: W) {
356//!         self.m(w).count += delta;
357//!     }
358//! }
359//!
360//! // Double the count!
361//! my_counter.increment_by(my_counter.m(w).count, w);
362//! ```
363//!
364//! </details>
365//! </div>
366//!
367//! To pretty-print a handle's value using [`Debug`](std::fmt::Debug), you must first wrap the
368//! target handle in a [`WorldDebug`] wrapper type using the [`Handle::debug`] method. This wrapper
369//! calls into the handle's regular `Debug::fmt` method but passes the [`World`] through
370//! thread-local storage so the printed value may be accessed.
371//!
372//! The debug-printing logic for all `Handle`s ensures that cyclic formatting is handled properly.
373//! For example, printing the following structure will not cause the program to stack-overflow:
374//!
375//! ```
376//! # use arid::World;
377//! #
378//! # let mut w = World::new();
379//! # let w = &mut w;
380//! use arid::{Handle as _, Object as _, object};
381//!
382//! #[derive(Debug)]
383//! pub struct Cycle {
384//!     other: Option<CycleHandle>,
385//! }
386//!
387//! object!(pub Cycle);
388//!
389//! let foo = Cycle { other: None }.spawn(w);
390//! let bar = Cycle { other: None }.spawn(w);
391//!
392//! foo.m(w).other = Some(*bar);
393//! bar.m(w).other = Some(*foo);
394//!
395//! dbg!(foo.debug(w));
396//! ```
397//!
398//! ```text
399//! [debug.rs:16:5] foo.debug(w) = debug::main::Cycle[0, v1]: Cycle {
400//!     other: Some(
401//!         debug::main::Cycle[1, v1]: Cycle {
402//!             other: Some(
403//!                 debug::main::Cycle[0, v1],
404//!             ),
405//!         },
406//!     ),
407//! }
408//! ```
409//!
410//! # Lifecycle
411//!
412//! Objects in `arid` are reference-counted although their semantics are a bit special:
413//!
414//! - The [`Handle`] newtypes generated by the `object!` macro are weak references but are assumed
415//!   to be valid. As such, you can call `.r()` and `.w()` on them directly. These types are
416//!   `Copy`able.
417//! - [`Strong`] wrappers around handles are, as their name suggest, strong references. These
418//!   objects [`Deref`](std::ops::Deref) to their underlying weak `Handle` newtype. These types are
419//!   *not* `Copy`able but are `Clone`able.
420//! - [`MayDangle`] are wrappers around handle newtypes which force the user to explicitly check for
421//!   dangling values using [`MayDangle::get`] or [`MayDangle::unwrap`] before dereferencing the
422//!   value. These types are `Copy`able.
423//!
424//! The [`Object::spawn`] method returns a `Strong` directly and handle newtypes can be upgraded
425//! into `Strong` references using the [`Handle::as_strong`] method.
426//!
427//! Objects are not destroyed immediately upon their reference count reaching zero. Instead, all
428//! deletions are queued until the [`World::flush`] method is called. This means that objects
429//! without any remaining strong references to them may be "resurrected" using the
430//! `Handle::as_strong` method like so:
431//!
432//! ```
433//! # use arid::World;
434//! #
435//! # let mut w = World::new();
436//! # let w = &mut w;
437//! #
438//! # use arid::object;
439//! #
440//! # #[derive(Debug)]
441//! # pub struct MyObject {
442//! #     count: u32,
443//! # }
444//! #
445//! # object!(pub MyObject);
446//! use arid::{Handle as _, Object as _, Strong};
447//!
448//! let my_counter_strong: Strong<MyObjectHandle> = MyObject { count: 1 }.spawn(w);
449//! let my_counter_weak: MyObjectHandle = *my_counter_strong;
450//!
451//! // We still have a strong reference to our counter so nothing gets deleted.
452//! w.flush();
453//! assert!(my_counter_weak.is_alive(w));
454//!
455//! // We dropped the last remaining strong reference but re-created it with `as_strong`
456//! // before the next flush so the object is still alive.
457//! drop(my_counter_strong);
458//! assert!(my_counter_weak.is_alive(w));
459//! let my_counter_strong = my_counter_weak.as_strong(w);
460//! w.flush();
461//! assert!(my_counter_weak.is_alive(w));
462//!
463//! // Finally, we can drop the value!
464//! drop(my_counter_strong);
465//! assert!(my_counter_weak.is_alive(w));
466//! w.flush();
467//! assert!(!my_counter_weak.is_alive(w));
468//! ```
469//!
470//! You can define a custom destructor for a given object type by implementing the [`Destructor`]
471//! trait on its handle. This method is called during the call to `World::flush` immediately before
472//! the value is properly destroyed.
473//!
474//! ```
475//! # use arid::World;
476//! #
477//! # let mut w = World::new();
478//! # let w = &mut w;
479//! use arid::{Destructor, Handle, Object, object, W};
480//!
481//! #[derive(Debug)]
482//! pub struct DtorObserver {
483//!     name: &'static str,
484//! }
485//!
486//! object!(pub DtorObserver);
487//!
488//! impl Destructor for DtorObserverHandle {
489//!     fn pre_destroy(self, w: W) {
490//!         println!("{} has been destroyed!", self.r(w).name);
491//!     }
492//! }
493//!
494//! let object = DtorObserver { name: "Max" }.spawn(w);
495//!
496//! drop(object);
497//! w.flush();  // "Max has been destroyed!"
498//! ```
499//!
500//! # Polymorphism
501//!
502//! Handle newtypes are not limited to harboring inherent `impl` blocks. Indeed, they can also
503//! accommodate `dyn`-compatible `trait` implementations, providing a powerful mechanism for
504//! polymorphism.
505//!
506//! We'll begin by defining a new trait and making it inherit the [`ErasedHandle`] trait implemented
507//! by all [`Handle`]s.
508//!
509//! ```
510//! use arid::{ErasedHandle, W, Wr};
511//!
512//! pub trait AbstractCounter: ErasedHandle {
513//!     fn increment(&self, w: W);
514//!
515//!     fn get_count(&self, w: Wr) -> usize;
516//! }
517//! ```
518//!
519//! We can then implement that trait on a handle newtype.
520//!
521//! ```
522//! # use arid::{ErasedHandle, W, Wr};
523//! #
524//! # pub trait AbstractCounter: ErasedHandle {
525//! #     fn increment(&self, w: W);
526//! #
527//! #     fn get_count(&self, w: Wr) -> usize;
528//! # }
529//! use std::time::Instant;
530//!
531//! use arid::{object, Handle as _};
532//!
533//! #[derive(Debug, Default)]
534//! pub struct SimpleCounter {
535//!     count: usize,
536//! }
537//!
538//! object!(pub SimpleCounter);
539//!
540//! impl AbstractCounter for SimpleCounterHandle {
541//!     fn increment(&self, w: W) {
542//!         self.m(w).count += 1;
543//!     }
544//!
545//!     fn get_count(&self, w: Wr) -> usize {
546//!         self.r(w).count
547//!     }
548//! }
549//!
550//! #[derive(Debug, Default)]
551//! pub struct ComplexCounter {
552//!     records: Vec<Instant>,
553//! }
554//!
555//! object!(pub ComplexCounter);
556//!
557//! impl AbstractCounter for ComplexCounterHandle {
558//!     fn increment(&self, w: W) {
559//!         self.m(w).records.push(Instant::now());
560//!     }
561//!
562//!     fn get_count(&self, w: Wr) -> usize {
563//!         self.r(w).records.len()
564//!     }
565//! }
566//! ```
567//!
568//! While it is perfectly valid to store these `dyn Trait`-objects in a `Box`, it is likely much
569//! more ergonomic and performant to store them in an [`Erased`] handle wrapper, which is `Copy`able
570//! and comes with some useful helper methods for down-casting types. You can instantiate an
571//! `Erased` wrapper using the [`erase!`] macro like so:
572//!
573//! ```
574//! # use arid::{ErasedHandle, W, Wr};
575//! #
576//! # pub trait AbstractCounter: ErasedHandle {
577//! #     fn increment(&self, w: W);
578//! #
579//! #     fn get_count(&self, w: Wr) -> usize;
580//! # }
581//! # use std::time::Instant;
582//! #
583//! # use arid::{object, Handle as _};
584//! #
585//! # #[derive(Debug, Default)]
586//! # pub struct SimpleCounter {
587//! #     count: usize,
588//! # }
589//! #
590//! # object!(pub SimpleCounter);
591//! #
592//! # impl AbstractCounter for SimpleCounterHandle {
593//! #     fn increment(&self, w: W) {
594//! #         self.m(w).count += 1;
595//! #     }
596//! #
597//! #     fn get_count(&self, w: Wr) -> usize {
598//! #         self.r(w).count
599//! #     }
600//! # }
601//! #
602//! # #[derive(Debug, Default)]
603//! # pub struct ComplexCounter {
604//! #     records: Vec<Instant>,
605//! # }
606//! #
607//! # object!(pub ComplexCounter);
608//! #
609//! # impl AbstractCounter for ComplexCounterHandle {
610//! #     fn increment(&self, w: W) {
611//! #         self.m(w).records.push(Instant::now());
612//! #     }
613//! #
614//! #     fn get_count(&self, w: Wr) -> usize {
615//! #         self.r(w).records.len()
616//! #     }
617//! # }
618//! #
619//! # use arid::World;
620//! # let mut w = World::new();
621//! # let w = &mut w;
622//! use arid::{erase, Object as _};
623//!
624//! let simple_counter = SimpleCounter::default().spawn(w);
625//! let complex_counter = ComplexCounter::default().spawn(w);
626//!
627//! let mut counter = erase!(as dyn AbstractCounter, *simple_counter);
628//!
629//! counter.increment(w);
630//! assert_eq!(counter.get_count(w), 1);
631//! dbg!(counter.debug(w));
632//! assert!(counter.try_downcast::<SimpleCounterHandle>().is_some());
633//!
634//! counter = erase!(as dyn AbstractCounter, *complex_counter);
635//! counter.increment(w);
636//! assert_eq!(counter.get_count(w), 1);
637//! dbg!(counter.debug(w));
638//! assert!(counter.try_downcast::<ComplexCounterHandle>().is_some());
639//! ```
640//!
641//! ```text
642//! [poly.rs:59:5] counter.debug(w) = poly::main::SimpleCounter[0, v1]: SimpleCounter {
643//!     count: 1,
644//! }
645//! [poly.rs:65:5] counter.debug(w) = poly::main::ComplexCounter[0, v1]: ComplexCounter {
646//!     records: [
647//!         Instant {
648//!             tv_sec: 85959,
649//!             tv_nsec: 910593500,
650//!         },
651//!     ],
652//! }
653//! ```
654//!
655//! [`Erased`] is a weak-but-assumed-valid handle to a value—sort of like a `Handle`. You can use
656//! [`StrongErased`] to create a strong reference to the value.
657//!
658//! # Custom Arenas
659//!
660//! To provide the user with copyable object handles, `arid` tracks its values in *generational
661//! arenas*, which can be thought of as very efficient dictionaries from the [`RawHandle`]s that
662//! [`Handle`]s wrap to the values to which they point. By default, we use the
663//! [`DefaultObjectArena`] arena but the user can provide a custom arena so long as it implements
664//! the [`ObjectArena`] trait. This could come in handy when trying to attach additional metadata to
665//! a variety of objects (e.g. widget parent and child relationships in a UI framework), when
666//! customizing those objects' deletion routine, or even when using an alternative data-structure to
667//! keep track of objects.
668//!
669//! This section will be reimplement the `DefaultObjectArena` structure in user-land but introduce
670//! additional metadata to it—in our case, a fancy new field named `frobs`! I expect this to be the
671//! most common way to define new arenas but this is only a pattern and, so long as you can properly
672//! implement the `ObjectArena` trait, you can do basically anything here.
673//!
674//! Let's start by defining creating a new-type structure to wrap a [`RawArena`]. Each slot actively
675//! allocated in the arena will have three fields: the actual value, its [`KeepAliveIndex`] so we
676//! can upgrade a given [`RawHandle`] to its corresponding [`KeepAlive`], and our custom metadata
677//! named `frobs`.
678//!
679//! The [`ObjectArena`] trait requires that our structure be [`Sized`], implement [`Default`], and
680//! live for `'static` so we'll derive those traits now.
681//!
682//! ```
683//! use arid::{RawArena, KeepAliveIndex, Object};
684//!
685//! #[derive(Debug)]
686//! pub struct MyArena<T: Object> {
687//!     arena: RawArena<Slot<T>>,
688//! }
689//!
690//! impl<T: Object> Default for MyArena<T> {
691//!     fn default() -> Self {
692//!         Self {
693//!             arena: RawArena::default(),
694//!         }
695//!     }
696//! }
697//!
698//! #[derive(Debug)]
699//! struct Slot<T: Object> {
700//!     value: T,
701//!     keep_alive: KeepAliveIndex,
702//!     frobs: u32,
703//! }
704//! ```
705//!
706//! Now, let us implement the [`ObjectArena`] trait on the `MyArena` type for objects we wish to
707//! support. We can fetch a given arena instance using the [`World::arena`] and [`World::arena_mut`]
708//! methods and the [`KeepAliveManager`] used to track [`KeepAlive`]s using [`World::manager`],
709//! [`World::manager_mut`], and [`World::arena_and_manager_mut`].
710//!
711//! Here's some boilerplate for a minimal arena with very little customization:
712//!
713//! ```
714//! # use arid::{RawArena, KeepAliveIndex, Object};
715//! #
716//! # #[derive(Debug)]
717//! # pub struct MyArena<T: Object> {
718//! #     arena: RawArena<Slot<T>>,
719//! # }
720//! #
721//! # impl<T: Object> Default for MyArena<T> {
722//! #     fn default() -> Self {
723//! #         Self {
724//! #             arena: RawArena::default(),
725//! #         }
726//! #     }
727//! # }
728//! #
729//! # #[derive(Debug)]
730//! # struct Slot<T: Object> {
731//! #     value: T,
732//! #     keep_alive: KeepAliveIndex,
733//! #     frobs: u32,
734//! # }
735//! use std::fmt;
736//!
737//! use arid::{Handle, ObjectArena, ObjectArenaSimpleSpawn, Strong, W, WorldKeepAliveUserdata, Wr};
738//!
739//! impl<T: Object<Arena = Self>> ObjectArenaSimpleSpawn for MyArena<T>
740//! where
741//!     T: Object<Arena = Self> + fmt::Debug,
742//! {
743//!     fn spawn(value: Self::Object, w: W) -> Strong<Self::Handle> {
744//!         let (arena, manager) = w.arena_and_manager_mut::<Self>();
745//!
746//!         // Add the value to the arena, obtaining a `RawHandle`.
747//!         let handle = arena.arena.insert(Slot {
748//!             value,
749//!             // We'll initialize this after we allocate the slot's `KeepAlive` using the
750//!             // `RawHandle` we allocate in the current step.
751//!             keep_alive: KeepAliveIndex::MAX,
752//!             frobs: 0,
753//!         });
754//!
755//!         // Create a `KeepAlive` to keep track of our slot.
756//!         let keep_alive = manager.allocate(WorldKeepAliveUserdata {
757//!             // The destructor is a function pointer that `World::flush` will call on objects
758//!             // whose `KeepAlive`s have all expired.
759//!             destructor: |handle, w| {
760//!                  let handle = Self::Handle::from_raw(handle);
761//!
762//!                  // The user is allowed to define custom destructors for their objects.
763//!                  // Don't forget to call them!
764//!                  Self::Handle::invoke_pre_destructor(handle, w);
765//!
766//!                  w.arena_mut::<Self>().arena.remove(handle.raw());
767//!             },
768//!             handle,
769//!         });
770//!
771//!         // Patch the temporary `keep_alive` in our slot with the new keep alive we just created.
772//!         arena.arena.get_mut(handle).unwrap().keep_alive = keep_alive.index();
773//!
774//!         // We now have a `RawHandle` and a `KeepAlive`, the two components required to create
775//!         // the `Strong` handle the caller expects!
776//!         Strong::new(Self::Handle::from_raw(handle), keep_alive)
777//!     }
778//! }
779//!
780//! impl<T> ObjectArena for MyArena<T>
781//! where
782//!     T: Object<Arena = Self> + fmt::Debug,
783//! {
784//!     type Object = T;
785//!     type Handle = T::Handle;
786//!
787//!     fn try_get(handle: Self::Handle, w: Wr<'_>) -> Option<&Self::Object> {
788//!         w.arena::<Self>().arena.get(handle.raw()).map(|v| &v.value)
789//!     }
790//!
791//!     fn try_get_mut(handle: Self::Handle, w: W<'_>) -> Option<&mut Self::Object> {
792//!         w.arena_mut::<Self>().arena.get_mut(handle.raw()).map(|v| &mut v.value)
793//!     }
794//!
795//!     fn as_strong_if_alive(handle: Self::Handle, w: W) -> Option<Strong<Self::Handle>> {
796//!         let (arena, manager) = w.arena_and_manager_mut::<Self>();
797//!
798//!         // Ensure the handle is still alive.
799//!         let slot = arena.arena.get(handle.raw())?;
800//!
801//!         // If it is, upgrade its `KeepAliveIndex` to a `KeepAlive` guard.
802//!         let keep_alive = manager.upgrade(slot.keep_alive);
803//!
804//!         Some(Strong::new(handle, keep_alive))
805//!     }
806//!
807//!     fn print_debug(f: &mut fmt::Formatter<'_>, handle: Self::Handle, w: Wr) -> fmt::Result {
808//!         if let Some(alive) = handle.try_r(w) {
809//!             alive.fmt(f)
810//!         } else {
811//!             f.write_str("<dangling>")
812//!         }
813//!     }
814//! }
815//! ```
816//!
817//! Finally, let's create extension traits to define new methods on objects within our new arena.
818//!
819//! ```
820//! # use arid::{RawArena, KeepAliveIndex, Object};
821//! #
822//! # #[derive(Debug)]
823//! # pub struct MyArena<T: Object> {
824//! #     arena: RawArena<Slot<T>>,
825//! # }
826//! #
827//! # impl<T: Object> Default for MyArena<T> {
828//! #     fn default() -> Self {
829//! #         Self {
830//! #             arena: RawArena::default(),
831//! #         }
832//! #     }
833//! # }
834//! #
835//! # #[derive(Debug)]
836//! # struct Slot<T: Object> {
837//! #     value: T,
838//! #     keep_alive: KeepAliveIndex,
839//! #     frobs: u32,
840//! # }
841//! # use std::fmt;
842//! #
843//! # use arid::{Handle, ObjectArena, ObjectArenaSimpleSpawn, Strong, W, WorldKeepAliveUserdata, Wr};
844//! #
845//! # impl<T: Object<Arena = Self>> ObjectArenaSimpleSpawn for MyArena<T>
846//! # where
847//! #     T: Object<Arena = Self> + fmt::Debug,
848//! # {
849//! #     fn spawn(value: Self::Object, w: W) -> Strong<Self::Handle> {
850//! #         let (arena, manager) = w.arena_and_manager_mut::<Self>();
851//! #
852//! #         // Add the value to the arena, obtaining a `RawHandle`.
853//! #         let handle = arena.arena.insert(Slot {
854//! #             value,
855//! #             // We'll initialize this after we allocate the slot's `KeepAlive` using the
856//! #             // `RawHandle` we allocate in the current step.
857//! #             keep_alive: KeepAliveIndex::MAX,
858//! #             frobs: 0,
859//! #         });
860//! #
861//! #         // Create a `KeepAlive` to keep track of our slot.
862//! #         let keep_alive = manager.allocate(WorldKeepAliveUserdata {
863//! #             // The destructor is a function pointer that `World::flush` will call on objects
864//! #             // whose `KeepAlive`s have all expired.
865//! #             destructor: |handle, w| {
866//! #                  let handle = Self::Handle::from_raw(handle);
867//! #
868//! #                  // The user is allowed to define custom destructors for their objects.
869//! #                  // Don't forget to call them!
870//! #                  Self::Handle::invoke_pre_destructor(handle, w);
871//! #
872//! #                  w.arena_mut::<Self>().arena.remove(handle.raw());
873//! #             },
874//! #             handle,
875//! #         });
876//! #
877//! #         // Patch the temporary `keep_alive` in our slot with the new keep alive we just created.
878//! #         arena.arena.get_mut(handle).unwrap().keep_alive = keep_alive.index();
879//! #
880//! #         // We now have a `RawHandle` and a `KeepAlive`, the two components required to create
881//! #         // the `Strong` handle the caller expects!
882//! #         Strong::new(Self::Handle::from_raw(handle), keep_alive)
883//! #     }
884//! # }
885//! #
886//! # impl<T> ObjectArena for MyArena<T>
887//! # where
888//! #     T: Object<Arena = Self> + fmt::Debug,
889//! # {
890//! #     type Object = T;
891//! #     type Handle = T::Handle;
892//! #
893//! #     fn try_get(handle: Self::Handle, w: Wr<'_>) -> Option<&Self::Object> {
894//! #         w.arena::<Self>().arena.get(handle.raw()).map(|v| &v.value)
895//! #     }
896//! #
897//! #     fn try_get_mut(handle: Self::Handle, w: W<'_>) -> Option<&mut Self::Object> {
898//! #         w.arena_mut::<Self>().arena.get_mut(handle.raw()).map(|v| &mut v.value)
899//! #     }
900//! #
901//! #     fn as_strong_if_alive(handle: Self::Handle, w: W) -> Option<Strong<Self::Handle>> {
902//! #         let (arena, manager) = w.arena_and_manager_mut::<Self>();
903//! #
904//! #         // Ensure the handle is still alive.
905//! #         let slot = arena.arena.get(handle.raw())?;
906//! #
907//! #         // If it is, upgrade its `KeepAliveIndex` to a `KeepAlive` guard.
908//! #         let keep_alive = manager.upgrade(slot.keep_alive);
909//! #
910//! #         Some(Strong::new(handle, keep_alive))
911//! #     }
912//! #
913//! #     fn print_debug(f: &mut fmt::Formatter<'_>, handle: Self::Handle, w: Wr) -> fmt::Result {
914//! #         if let Some(alive) = handle.try_r(w) {
915//! #             alive.fmt(f)
916//! #         } else {
917//! #             f.write_str("<dangling>")
918//! #         }
919//! #     }
920//! # }
921//! pub trait MyObject: Object<Arena = MyArena<Self>> + fmt::Debug {}
922//!
923//! impl<T: Object<Arena = MyArena<Self>> + fmt::Debug> MyObject for T {}
924//!
925//! pub trait MyHandle: Handle<Object: MyObject> {
926//!     fn frob(self, w: W);
927//!
928//!     fn get_frobs(self, w: Wr) -> u32;
929//! }
930//!
931//! impl<T: Handle<Object: MyObject>> MyHandle for T {
932//!     fn frob(self, w: W) {
933//!         w.arena_mut::<MyArena<T::Object>>()
934//!             .arena
935//!             .get_mut(self.raw())
936//!             .expect("value is not alive")
937//!             .frobs += 1;
938//!     }
939//!
940//!     fn get_frobs(self, w: Wr) -> u32 {
941//!         w.arena::<MyArena<T::Object>>()
942//!             .arena
943//!             .get(self.raw())
944//!             .expect("value is not alive")
945//!             .frobs
946//!     }
947//! }
948//! ```
949//!
950//! And with that, we have a working arena; now, we just need to use it! To define an object within
951//! the arena, we can use a second form of the [`object!`] macro to specify a custom arena in which
952//! the object should be stored:
953//!
954//! ```
955//! # use arid::{RawArena, KeepAliveIndex, Object};
956//! #
957//! # #[derive(Debug)]
958//! # pub struct MyArena<T: Object> {
959//! #     arena: RawArena<Slot<T>>,
960//! # }
961//! #
962//! # impl<T: Object> Default for MyArena<T> {
963//! #     fn default() -> Self {
964//! #         Self {
965//! #             arena: RawArena::default(),
966//! #         }
967//! #     }
968//! # }
969//! #
970//! # #[derive(Debug)]
971//! # struct Slot<T: Object> {
972//! #     value: T,
973//! #     keep_alive: KeepAliveIndex,
974//! #     frobs: u32,
975//! # }
976//! # use std::fmt;
977//! #
978//! # use arid::{Handle, ObjectArena, ObjectArenaSimpleSpawn, Strong, W, WorldKeepAliveUserdata, Wr};
979//! #
980//! # impl<T: Object<Arena = Self>> ObjectArenaSimpleSpawn for MyArena<T>
981//! # where
982//! #     T: Object<Arena = Self> + fmt::Debug,
983//! # {
984//! #     fn spawn(value: Self::Object, w: W) -> Strong<Self::Handle> {
985//! #         let (arena, manager) = w.arena_and_manager_mut::<Self>();
986//! #
987//! #         // Add the value to the arena, obtaining a `RawHandle`.
988//! #         let handle = arena.arena.insert(Slot {
989//! #             value,
990//! #             // We'll initialize this after we allocate the slot's `KeepAlive` using the
991//! #             // `RawHandle` we allocate in the current step.
992//! #             keep_alive: KeepAliveIndex::MAX,
993//! #             frobs: 0,
994//! #         });
995//! #
996//! #         // Create a `KeepAlive` to keep track of our slot.
997//! #         let keep_alive = manager.allocate(WorldKeepAliveUserdata {
998//! #             // The destructor is a function pointer that `World::flush` will call on objects
999//! #             // whose `KeepAlive`s have all expired.
1000//! #             destructor: |handle, w| {
1001//! #                  let handle = Self::Handle::from_raw(handle);
1002//! #
1003//! #                  // The user is allowed to define custom destructors for their objects.
1004//! #                  // Don't forget to call them!
1005//! #                  Self::Handle::invoke_pre_destructor(handle, w);
1006//! #
1007//! #                  w.arena_mut::<Self>().arena.remove(handle.raw());
1008//! #             },
1009//! #             handle,
1010//! #         });
1011//! #
1012//! #         // Patch the temporary `keep_alive` in our slot with the new keep alive we just created.
1013//! #         arena.arena.get_mut(handle).unwrap().keep_alive = keep_alive.index();
1014//! #
1015//! #         // We now have a `RawHandle` and a `KeepAlive`, the two components required to create
1016//! #         // the `Strong` handle the caller expects!
1017//! #         Strong::new(Self::Handle::from_raw(handle), keep_alive)
1018//! #     }
1019//! # }
1020//! #
1021//! # impl<T> ObjectArena for MyArena<T>
1022//! # where
1023//! #     T: Object<Arena = Self> + fmt::Debug,
1024//! # {
1025//! #     type Object = T;
1026//! #     type Handle = T::Handle;
1027//! #
1028//! #     fn try_get(handle: Self::Handle, w: Wr<'_>) -> Option<&Self::Object> {
1029//! #         w.arena::<Self>().arena.get(handle.raw()).map(|v| &v.value)
1030//! #     }
1031//! #
1032//! #     fn try_get_mut(handle: Self::Handle, w: W<'_>) -> Option<&mut Self::Object> {
1033//! #         w.arena_mut::<Self>().arena.get_mut(handle.raw()).map(|v| &mut v.value)
1034//! #     }
1035//! #
1036//! #     fn as_strong_if_alive(handle: Self::Handle, w: W) -> Option<Strong<Self::Handle>> {
1037//! #         let (arena, manager) = w.arena_and_manager_mut::<Self>();
1038//! #
1039//! #         // Ensure the handle is still alive.
1040//! #         let slot = arena.arena.get(handle.raw())?;
1041//! #
1042//! #         // If it is, upgrade its `KeepAliveIndex` to a `KeepAlive` guard.
1043//! #         let keep_alive = manager.upgrade(slot.keep_alive);
1044//! #
1045//! #         Some(Strong::new(handle, keep_alive))
1046//! #     }
1047//! #
1048//! #     fn print_debug(f: &mut fmt::Formatter<'_>, handle: Self::Handle, w: Wr) -> fmt::Result {
1049//! #         if let Some(alive) = handle.try_r(w) {
1050//! #             alive.fmt(f)
1051//! #         } else {
1052//! #             f.write_str("<dangling>")
1053//! #         }
1054//! #     }
1055//! # }
1056//! # pub trait MyObject: Object<Arena = MyArena<Self>> + fmt::Debug {}
1057//! #
1058//! # impl<T: Object<Arena = MyArena<Self>> + fmt::Debug> MyObject for T {}
1059//! #
1060//! # pub trait MyHandle: Handle<Object: MyObject> {
1061//! #     fn frob(self, w: W);
1062//! #
1063//! #     fn get_frobs(self, w: Wr) -> u32;
1064//! # }
1065//! #
1066//! # impl<T: Handle<Object: MyObject>> MyHandle for T {
1067//! #     fn frob(self, w: W) {
1068//! #         w.arena_mut::<MyArena<T::Object>>()
1069//! #             .arena
1070//! #             .get_mut(self.raw())
1071//! #             .expect("value is not alive")
1072//! #             .frobs += 1;
1073//! #     }
1074//! #
1075//! #     fn get_frobs(self, w: Wr) -> u32 {
1076//! #         w.arena::<MyArena<T::Object>>()
1077//! #             .arena
1078//! #             .get(self.raw())
1079//! #             .expect("value is not alive")
1080//! #             .frobs
1081//! #     }
1082//! # }
1083//! #
1084//! # use arid::World;
1085//! # let mut w = World::new();
1086//! # let w = &mut w;
1087//! use arid::{object, Object as _};
1088//!
1089//! #[derive(Debug)]
1090//! pub struct MyThing {
1091//!     name: &'static str,
1092//! }
1093//!
1094//! object!(pub MyThing[MyArena<Self>]);
1095//!
1096//! let my_thing = MyThing { name: "Ryleigh" }.spawn(w);
1097//!
1098//! my_thing.frob(w);
1099//! my_thing.m(w).name = "Riley";
1100//! assert_eq!(my_thing.get_frobs(w), 1);
1101//! ```
1102//!
1103//! Happy hacking!
1104//!
1105//! # Limitations and Future Work
1106//!
1107//! `arid`'s largest limitation is its lack of support for generic [`Object`] definitions. This
1108//! limitation originates from our use of [`late_struct`] to build up our [`World`]s: each object
1109//! declaration defines a new field in our world and these late-bound field definitions cannot be
1110//! generic.
1111//!
1112//! Our use of `late_struct` also means that the size of each world is proportional to the number of
1113//! objects defined in the binary but the constant factor on this size is, intentionally, fairly
1114//! small (currently, 32 bytes per arena type).
1115//!
1116//! The use of arenas to implement this object model is also somewhat unfortunate. Arenas transform
1117//! the (small) cost of incrementing and decrementing reference counts into the (equally small) cost
1118//! of checking object generations before accessing a handle. This is a somewhat suspicious tradeoff
1119//! since I'd expect dereferences to happen more often than reference copies but that's just a
1120//! hunch.
1121//!
1122//! Really, arenas are just a work-around to give us `Copy`able handles for ergonomic purposes.
1123//! Hopefully, this need for arenas will be obviated by the [ergonomic ref-counting] team's efforts.
1124//! Likewise, the handle newtype system is really just a work-around for the lack of [arbitrary
1125//! `Self` types](https://github.com/rust-lang/rust/issues/44874).
1126//!
1127//! [ergonomic ref-counting]: https://rust-lang.github.io/rust-project-goals/2024h2/ergonomic-rc.html
1128//!
1129
1130#![deny(missing_docs)]
1131
1132mod arena;
1133pub use self::arena::*;
1134
1135mod keep_alive;
1136pub use self::keep_alive::*;
1137
1138mod handle;
1139pub use self::handle::*;
1140
1141mod world;
1142pub use self::world::*;
1143
1144mod wrappers;
1145pub use self::wrappers::*;