pub struct AimDbBuilder { /* private fields */ }Expand description
Database builder for producer-consumer pattern
Provides a fluent API for constructing databases with type-safe record registration.
Set the runtime via .runtime(); a missing runtime is reported by build()
like any other configuration mistake.
Implementations§
Source§impl AimDbBuilder
impl AimDbBuilder
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(self, rt: Arc<impl RuntimeOps + 'static>) -> Self
pub fn runtime(self, rt: Arc<impl RuntimeOps + 'static>) -> Self
Sets the runtime adapter.
Accepts any adapter implementing the dyn-safe
RuntimeOps capability surface
(TokioAdapter, EmbassyAdapter, WasmAdapter); the builder stores it
as a value — no runtime type parameter.
Sourcepub fn extensions(&self) -> &Extensions
pub fn extensions(&self) -> &Extensions
Returns a shared reference to the extension storage.
External crates use this to retrieve state stored via extensions_mut().
Sourcepub fn extensions_mut(&mut self) -> &mut Extensions
pub fn extensions_mut(&mut self) -> &mut Extensions
Returns a mutable reference to the extension storage.
Use this inside AimDbBuilderPersistExt (or similar) to store typed state
that .persist() and AimDbQueryExt will later retrieve.
Sourcepub fn on_start<F, Fut>(&mut self, f: F) -> &mut Self
pub fn on_start<F, Fut>(&mut self, f: F) -> &mut Self
Registers a task to be spawned after build() completes.
The closure receives the RuntimeContext and
must return a future that runs for as long as needed (e.g. an infinite
cleanup loop). Tasks are spawned in registration order, after all
record tasks and connectors have been started.
Sourcepub fn with_connector(self, builder: impl ConnectorBuilder + 'static) -> Self
pub fn with_connector(self, builder: impl ConnectorBuilder + 'static) -> Self
Registers a connector builder, invoked during build.
This single entry point registers two kinds of connector — both
implement ConnectorBuilder and are
driven the same way:
- Data-plane links (MQTT / KNX / WebSocket): a record opts in with
link_to("<scheme>://<topic>")/link_from(...), and the connector mirrors that record to/from the external topic. The connector’sschemeis what those links match against. - Remote-access session connectors (UDS / serial / TCP): these expose
AimDB itself over a transport so peers can introspect/subscribe/write.
- The client half (e.g.
UdsClient) dials a peer and does uselink_to/link_fromunder its scheme — just like (1), the scheme is"uds"by default instead of"mqtt". - The server half (e.g.
UdsServer) accepts connections and takes no links — registering it is how a server stands up remote access (this replaces the oldwith_remote_access(config)).
- The client half (e.g.
§Examples
Illustrative (not compiled: the connector types live in downstream
crates aimdb-core cannot depend on):
// (1) data-plane link to an MQTT topic
let mut b = AimDbBuilder::new().runtime(rt)
.with_connector(MqttConnector::new("mqtt://broker.local:1883"));
b.configure::<Temperature>("commands.temp", |r| {
r.link_from("mqtt://commands/temp").with_deserializer(parse).finish();
});
b.build().await?;
// (2a) remote-access SERVER — no links, just expose this db over UDS
AimDbBuilder::new().runtime(rt)
.with_connector(UdsServer::from_config(remote_config))
.build().await?;
// (2b) remote-access CLIENT — mirror a record to a peer over UDS
let mut b = AimDbBuilder::new().runtime(rt)
.with_connector(UdsClient::new("/run/aimdb.sock"));
b.configure::<Temp>("temp", |r| { r.with_remote_access().link_to("uds://temp"); });
b.build().await?;Sourcepub fn configure<T>(
&mut self,
key: impl RecordKey,
f: impl FnOnce(&mut RecordRegistrar<'_, T>),
) -> &mut Self
pub fn configure<T>( &mut self, key: impl RecordKey, f: impl FnOnce(&mut RecordRegistrar<'_, T>), ) -> &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
Sourcepub async fn run(self) -> DbResult<()>
pub async fn run(self) -> DbResult<()>
Builds the database and drives every collected future to completion.
Convenience wrapper for the common case: call build(), then immediately
runner.run().await. The database handle is dropped on exit.
For programmatic access to the handle (manual subscriptions, holding the
AimDb for other uses), prefer build() directly.
§Returns
DbResult<()> — Ok once the database starts; the call then blocks until
every future the runner is driving has completed (typically forever).
Sourcepub async fn build(self) -> DbResult<(AimDb, AimDbRunner)>
pub async fn build(self) -> DbResult<(AimDb, AimDbRunner)>
Builds the database and returns a (handle, runner) pair.
build() collects every future the database needs to drive (producer
services, consumer taps, transforms with fan-in forwarders, connectors,
remote-access supervisor, on_start tasks) into the AimDbRunner
returned alongside the clone-able AimDb handle. No background
work runs until runner.run().await is awaited.
Use this when you need programmatic access to the handle for manual
subscriptions or production. For typical services, use .run().await
which calls build() and runner.run() for you.
Connector Setup: Connectors are constructed during build() from
the ConnectorBuilders previously registered via .with_connector().
Their driving futures are appended to the runner.
§Returns
DbResult<(AimDb, AimDbRunner)> — the handle (cloneable) and the
non-Clone runner that owns the collected futures.
§Errors
build() is the single surface for configuration mistakes: everything
recorded during configuration (conflicting .source()/.transform()/
.link_from(), missing serializers, unregistered schemes, …) plus the
build-time checks here (record validation, linked records without a
buffer, duplicate keys, dependency-graph cycles) is collected and
returned as one DbError::InvalidConfiguration carrying all
findings — one run surfaces every mistake.