aimdb_core/extensions.rs
1//! Generic extension storage for [`AimDbBuilder`] and [`AimDb`].
2//!
3//! External crates store typed state here during builder configuration
4//! and retrieve it during record setup or at query time. This is the
5//! hook mechanism used by `aimdb-persistence` — and any other crate that
6//! needs to attach data to the builder or the live database without
7//! modifying `aimdb-core`.
8//!
9//! # Example
10//! ```rust,ignore
11//! // Storing a value (e.g. from an external "with_persistence" builder ext):
12//! builder.extensions_mut().insert(MyState { ... });
13//!
14//! // Retrieving it from a RecordRegistrar closure:
15//! let state = reg.extensions().get::<MyState>().expect("MyState not configured");
16//!
17//! // Retrieving it from a live AimDb handle (query time):
18//! let state = db.extensions().get::<MyState>().expect("MyState not configured");
19//! ```
20
21extern crate alloc;
22
23use alloc::boxed::Box;
24use core::any::{Any, TypeId};
25use hashbrown::HashMap;
26
27/// Generic extension storage for [`AimDbBuilder`][crate::AimDbBuilder] and
28/// [`AimDb`][crate::AimDb].
29///
30/// Keyed by [`TypeId`] so each stored type occupies exactly one slot.
31/// Values must be `Send + Sync + 'static` to be safe across thread and task
32/// boundaries used throughout AimDB's async executor model.
33pub struct Extensions {
34 map: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
35}
36
37impl Default for Extensions {
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43impl Extensions {
44 /// Creates an empty extension map.
45 pub fn new() -> Self {
46 Self {
47 map: HashMap::new(),
48 }
49 }
50
51 /// Inserts a value. Replaces any previously stored value of the same type.
52 pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) {
53 self.map.insert(TypeId::of::<T>(), Box::new(val));
54 }
55
56 /// Returns a reference to the value of type `T`, or `None` if not stored.
57 pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
58 self.map
59 .get(&TypeId::of::<T>())
60 .and_then(|b| b.downcast_ref())
61 }
62}