Skip to main content

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}