pub struct AimDbBuilder<R = NoRuntime> { /* private fields */ }Expand description
Database builder for producer-consumer pattern
Provides a fluent API for constructing databases with type-safe record registration.
Use .runtime() to set the runtime and transition to a typed builder.
Implementations§
Source§impl AimDbBuilder<NoRuntime>
impl AimDbBuilder<NoRuntime>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new database builder without a runtime
Call .runtime() to set the runtime adapter.
Sourcepub fn runtime<R>(self, rt: Arc<R>) -> AimDbBuilder<R>where
R: Spawn + 'static,
pub fn runtime<R>(self, rt: Arc<R>) -> AimDbBuilder<R>where
R: Spawn + 'static,
Sets the runtime adapter
This transitions the builder from untyped to typed with concrete runtime R.
§Type Safety Note
The connector_builders field is intentionally reset to Vec::new() during this
transition because connectors are parameterized by the runtime type:
- Before:
Vec<Box<dyn ConnectorBuilder<NoRuntime>>> - After:
Vec<Box<dyn ConnectorBuilder<R>>>
These types are incompatible and cannot be transferred. However, this is not a bug
because .with_connector() is only available AFTER calling .runtime() (it’s defined
in the impl<R> where R: Spawn block, not in impl AimDbBuilder<NoRuntime>).
This means the type system enforces the correct call order:
AimDbBuilder::new()
.runtime(runtime) // ← Must be called first
.with_connector(connector) // ← Now availableThe records and remote_config are preserved across the transition since they
are not parameterized by the runtime type.
Source§impl<R> AimDbBuilder<R>where
R: Spawn + 'static,
impl<R> AimDbBuilder<R>where
R: Spawn + 'static,
Sourcepub fn with_connector(self, builder: impl ConnectorBuilder<R> + 'static) -> Self
pub fn with_connector(self, builder: impl ConnectorBuilder<R> + 'static) -> Self
Registers a connector builder that will be invoked during build()
The connector builder will be called after the database is constructed, allowing it to collect routes and initialize the connector properly.
§Arguments
builder- A connector builder that implementsConnectorBuilder<R>
§Example
use aimdb_mqtt_connector::MqttConnector;
let db = AimDbBuilder::new()
.runtime(runtime)
.with_connector(MqttConnector::new("mqtt://broker.local:1883"))
.configure::<Temperature>(|reg| {
reg.link_from("mqtt://commands/temp")...
})
.build().await?;Sourcepub fn with_remote_access(self, config: AimxConfig) -> Self
pub fn with_remote_access(self, config: AimxConfig) -> Self
Enables remote access via AimX protocol (std only)
Configures the database to accept remote connections over a Unix domain socket, allowing external clients to introspect records, subscribe to updates, and (optionally) write data.
The remote access supervisor will be spawned automatically during build().
§Arguments
config- Remote access configuration (socket path, security policy, etc.)
§Example
use aimdb_core::remote::{AimxConfig, SecurityPolicy};
let config = AimxConfig::new("/tmp/aimdb.sock")
.with_security(SecurityPolicy::read_only());
let db = AimDbBuilder::new()
.runtime(runtime)
.with_remote_access(config)
.build()?;Sourcepub fn configure<T>(
&mut self,
key: impl RecordKey,
f: impl for<'a> FnOnce(&'a mut RecordRegistrar<'a, T, R>),
) -> &mut Self
pub fn configure<T>( &mut self, key: impl RecordKey, f: impl for<'a> FnOnce(&'a mut RecordRegistrar<'a, T, R>), ) -> &mut Self
Configures a record type manually with a unique key
The key uniquely identifies this record instance. Multiple records of the same type can exist with different keys (e.g., “sensor.temperature.room1” and “sensor.temperature.room2”).
§Arguments
key- A unique identifier for this record. Can be a string literal,StringKey, or any type implementingRecordKey(including user-defined enum keys).f- Configuration closure
§Example
// Using string literal
builder.configure::<Temperature>("sensor.temp.room1", |reg| { ... });
// Using compile-time safe enum key
builder.configure::<Temperature>(SensorKey::TempRoom1, |reg| { ... });Sourcepub fn register_record<T>(&mut self, cfg: &T::Config) -> &mut Selfwhere
T: RecordT<R>,
pub fn register_record<T>(&mut self, cfg: &T::Config) -> &mut Selfwhere
T: RecordT<R>,
Registers a self-registering record type
The record type must implement RecordT<R>.
Uses the type name as the default key. For custom keys, use configure() directly.
Sourcepub fn register_record_with_key<T>(
&mut self,
key: impl RecordKey,
cfg: &T::Config,
) -> &mut Selfwhere
T: RecordT<R>,
pub fn register_record_with_key<T>(
&mut self,
key: impl RecordKey,
cfg: &T::Config,
) -> &mut Selfwhere
T: RecordT<R>,
Registers a self-registering record type with a custom key
The record type must implement RecordT<R>.
Sourcepub async fn run(self) -> DbResult<()>
pub async fn run(self) -> DbResult<()>
Runs the database indefinitely (never returns)
This method builds the database, spawns all producer and consumer tasks, and then parks the current task indefinitely. This is the primary way to run AimDB services.
All logic runs in background tasks via producers, consumers, and connectors. The application continues until interrupted (e.g., Ctrl+C).
§Returns
DbResult<()> - Ok when database starts successfully, then parks forever
§Example
#[tokio::main]
async fn main() -> DbResult<()> {
AimDbBuilder::new()
.runtime(Arc::new(TokioAdapter::new()?))
.configure::<MyData>(|reg| {
reg.with_buffer(BufferCfg::SpmcRing { capacity: 100 })
.with_source(my_producer)
.with_tap(my_consumer);
})
.run().await // Runs forever
}Sourcepub async fn build(self) -> DbResult<AimDb<R>>
pub async fn build(self) -> DbResult<AimDb<R>>
Builds the database and returns the handle (async)
Use this when you need programmatic access to the database handle for
manual subscriptions or production. For typical services, use .run().await instead.
Automatic Task Spawning: This method spawns all producer services and
.tap() observer tasks that were registered during configuration.
Connector Setup: Connectors must be created manually before calling build():
use aimdb_mqtt_connector::{MqttConnector, router::RouterBuilder};
// Configure records with connector links
let builder = AimDbBuilder::new()
.runtime(runtime)
.configure::<Temp>("temp", |reg| {
reg.link_from("mqtt://commands/temp")
.with_buffer(BufferCfg::SingleLatest)
.with_serialization();
});
// Create MQTT connector with router
let router = RouterBuilder::new()
.route("commands/temp", /* deserializer */)
.build();
let connector = MqttConnector::new("mqtt://localhost:1883", router).await?;
// Register connector and build
let db = builder
.with_connector("mqtt", Arc::new(connector))
.build().await?;§Returns
DbResult<AimDb<R>> - The database instance