Skip to content

Commit 3d64818

Browse files
lxsaahclaude
andauthored
docs: purge never-compiled doc examples — compile, delete, or justify (#146) (#147)
* refactor(core)!: fuse inbound deserialize+produce at registration (036 W1 inbound) Replace the per-message Box<dyn Any> inbound path (DeserializerKind -> produce_any downcast) with a fused IngestFn built in InboundConnectorBuilder::finish() where T is known: deserialize + produce in one typed closure, no erasure crossing and no boxed future per message (Producer::produce is sync + infallible, design 029). - IngestFn / IngestFactoryFn replace DeserializerFn/ContextDeserializerFn/ DeserializerKind and ProducerTrait/ProducerFactoryFn (all deleted) - InboundConnectorLink carries the ingest factory (non-optional; finish() validates the deserializer before registering, unchanged error strings) - Router::route is now a sync fn taking &RuntimeContext (every production caller already passed Some(&ctx); the context-skip branch is unrepresentable with fused closures, its test removed) - collect_inbound_routes returns Vec<(String, IngestFn)> - pump_source / pump_client inbound / ws dispatch drop one .await - delete dead TypedRecord::create_producer_trait Registrar API (with_deserializer/_raw, link_from) is source-compatible; MQTT/KNX/WS builders pass routes opaquely and compile unchanged. Part of design 036 W1 (data-plane de-Any). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(core)!: fuse outbound subscribe+serialize+topic at registration (036 W1 outbound) Replace the per-message Box<dyn Any> outbound path (subscribe_any -> recv_any -> SerializerFn(&dyn Any) downcast, plus topic_any(&dyn Any)) with a fused SerializedSource built in OutboundConnectorBuilder::finish() where T is known: its readers yield destination + serialized payload directly (subscribe -> recv -> resolve topic -> serialize, all typed). - SerializedSource / SerializedReader / SerializedValue / SourceFactoryFn replace ConsumerTrait/AnyReader/SerializerKind/SerializerFn/ ContextSerializerFn/ConsumerFactoryFn and the erased TopicProviderAny/ TopicProviderWrapper/TopicProviderFn (all deleted; the typed TopicProvider<T> trait is now stored as-is) - OutboundRoute is { topic, source, config }; ConnectorLink carries the source factory (non-optional; finish() validates the serializer before registering, unchanged error strings; the "skip links without serializer" branch in collect_outbound_routes is gone) - RuntimeContext is threaded into SerializedReader::recv per call (026 context serializers), not captured; raw serializers skip the ctx clone - Buffer errors propagate unchanged (BufferLagged => pump continues, other => pump stops); serialize failures are logged and skipped inside the reader, observably identical to the old pump-side continue - pump_sink / pump_client outbound collapse to recv + publish What disappears per message: the Box<dyn Any> allocation, two downcasts, the topic_any erasure crossing, and the subscribe_any boxed future. The one remaining Box::pin per recv is the object-safe-async cost that already existed. Registrar API (with_serializer/_raw, with_topic_provider, link_to) is source-compatible; the KNX fake-gateway and session smoke tests pass unmodified. Part of design 036 W1 (data-plane de-Any). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(core)!: drop unrepresentable error surface; document join erasure (036 W1 wrap-up) - delete SerializeError::TypeMismatch — both constructors died with the W1 fusion (the downcasts are gone); DbError::TypeMismatch is unrelated and stays - delete dead ConnectorClient (held Arc<dyn Any>, zero users) and OutboundConnectorLink (zero users) - document on JoinTrigger why the join fan-in deliberately keeps its Box<dyn Any + Send> (the erasure is the multi-type join API) - CHANGELOG entries (global + aimdb-core + websocket-connector) - check in design docs 034/035/036 and amend the 036 W1 acceptance grep: DynBuffer::as_any and the session auth ext slots are setup-time hits the original literal grep missed Part of design 036 W1 (data-plane de-Any). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(tests): clean up use statements and formatting in tests * docs(design): mark 036 W1 implemented in PR #141 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(core)!: split AnyRecord into capability traits (036 W2) AnyRecord carried ~22 methods spanning four concerns; every remote-access or profiling change churned the core storage contract. Split by consumer: - AnyRecord (6 methods): storage/lifecycle only — validate, as_any(_mut), drain_config_errors, set_writable_erased, plus the cfg-gated json_access() accessor so the remote-access gate lives in one place. - RecordIntrospect (supertrait): graph/metadata introspection consumed by the builder's dependency-graph construction, route collection, and list_records. - JsonRecordAccess (cfg remote-access): latest_json / subscribe_json / set_from_json, reached via json_access(); the runtime .with_remote_access() checks stay inside the methods, so behavior is unchanged. Gate is `remote-access` (the 036 sketch said json-serialize). - RecordMetricsReset (supertrait): the cfg-gated no-op-default resets. Supertrait wiring keeps every dyn AnyRecord call site compiling unchanged; only the four JSON call sites switch to the accessor. Registry storage stays Vec<Box<dyn AnyRecord>>. Drops the dead outbound_connector_urls (cfg std) — zero callers in-tree and in aimdb-pro. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(design): mark 036 W2 implemented in PR #142 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(core): dedup StringKey::intern; document the leak contract (036 W5) intern() leaked a fresh allocation on every call, so re-interning the same key leaked again. A global dedup table (std Mutex / spin Mutex, same pattern as the TypedRecord field locks) now returns the existing 'static allocation for a known key, bounding the leak by the number of *distinct* dynamic keys — the actual lifetime contract of a record key. The contract is documented loudly on intern(), and the debug-build tripwire now counts distinct keys instead of calls. The &'static str / Copy design stays; an Arc<str> key variant remains rejected (forks RecordKey into two shapes — the 034 §3.1 mistake). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(tests): host_test_stubs! macro for the defmt logger triplication (036 W6) The 18-line no-op #[defmt::global_logger] + panic handler + host time driver block existed in three copies (embassy-adapter session_smoke, embassy-adapter buffer.rs tests, serial-connector embassy_smoke). Per 035 §2.4, an exported host_test_stubs! macro in aimdb-embassy-adapter now holds the single definition; each test binary expands it once, preserving the once-per-binary requirement of #[global_logger]/time_driver_impl!. The time driver uses the wake_by_ref variant (buffer.rs's superset behavior: zero-duration sleeps complete; the smokes never sleep). The serial-connector defmt/embassy-time-driver dev-deps stay — the expansion references them at the invocation site; the Cargo.toml comment now says so. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(design): mark 036 W5+W6 implemented in PR #143 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(design): 036 status round — W3 prep done, W4 deferred on W3 data, W7 skipped - W3: Nucleo firmware build verified (thumbv8m.main-none-eabihf); single run on a main build is the bar now that #140 is merged. Bench session is the remaining work and the gate for closing 035. - W4: deferred pending W3 scenario-1 AckTimeout evidence (decision 2026-06-12). Design pre-decided for the trigger: buffer the sent frame (option a) — GroupWrite already carries a 254-byte APDU buffer, so the semantic-content variant saves ~350 B total, no real RAM argument. - W7: skipped entirely (decision 2026-06-12); no audit will be run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(knx): ACK-retransmit knob — retransmit once, disconnect on second miss (036 W4) KNXnet/IP 3.8.4 says: repeat an unACKed TUNNELING_REQUEST once after the timeout, then tear the connection down on the second miss. The engine previously expired and warned only — hardware bench evidence (W3, 2026-06-12) showed ten button-press writes silently lost during a link outage's heartbeat-detection window (~65 s). TunnelConfig gains ack_retransmits (default 1 = spec behavior; 0 = the old expire-and-warn for the previous semantics). The pending-ACK slot buffers the sent frame (option (a) per the 036 W4 decision record: GroupWrite already carries a 254-byte APDU, so rebuilding from semantic content saves ~350 B total — not worth the rebuild path). On expiry with retries left the identical frame is re-sent (same sequence counter) and the timer re-armed; on final expiry AckTimeout is reported and the engine disconnects so queued commands flush after the re-handshake instead of vanishing into a dead tunnel. Eviction on map overflow stays warn-only (overflow is not confirmed loss). Behavior change at default config: a tunnel with a persistently unanswered write now reconnects within ~2× ack_timeout_ms instead of staying connected. Retransmit delay is ack_timeout_ms (3 s, the pre-engine constant); strict spec timing is one config knob away (ack_timeout_ms = 1_000). Tests: engine units (identical-frame retransmit, ack-after-retransmit, disconnect on second miss, legacy mode pinned at ack_retransmits=0) + fake-gateway test dropping the first ACK and asserting the byte-identical repeat and tunnel survival. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(design): mark 036 W4 implemented in PR #144; record W3 bench findings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(design): record W4 hardware validation (partial) and pre-release W3 scope Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: fix AimX v1/v2 rot, dead spec links, and removed-API references Doc-rot fixes from the post-036 debt scan; no wire or API behavior changes (the one wire-visible byte change — the client hello version — is corrected from a stale "1.0" to the "2.0" the server already announces; the server never validates it). - remote::PROTOCOL_VERSION corrected to "2.0", documented, and exported; the AimX dispatch Welcome and aimdb-client both use it now, so client and server can no longer drift. The dead, never-exported v1 untagged Message envelope and its helpers are deleted. - remote module docs: "AimX v1" + link to the nonexistent docs/design/remote-access/aimx-v1.md replaced with the v2 NDJSON tagged-frame description pointing at session::aimx and remote-access-via-connectors.md; stale .build()? example fixed to the (db, runner) = build().await? shape. - connector module docs: removed-`.link()` API replaced with the real configure/link_to pattern (the old example used a RecordConfig::builder API that never existed); ConnectorUrl no longer advertises Kafka/HTTP connector semantics for connectors that don't exist — documented as scheme-agnostic with real schemes (mqtt, knx, ws, uds, serial). - builder.rs AimDb example fixed: register_record returns &mut Self, so the old chained .build() could not compile. - aimdb-client README rewritten to match reality (AimxConnection, v2 wire, endpoint URLs incl. serial); crate doc + aimdb-cli doc updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: purge never-compiled doc examples — compile, delete, or justify (#146) Resolves the ignored-doctest debt from the post-036 scan with the revised policy (maintainer decision on #146): remove `rust,ignore` examples unless there is a good reason to keep one. Result: 108 ignored fences → 24, and every survivor carries an explicit "Illustrative (not compiled: …)" reason. - Converted to compiled doctests (`no_run`/`rust`) where the crate's deps allow it: the crate-level quick starts of aimdb-sync, aimdb-uds-connector, aimdb-websocket-connector, aimdb-mqtt-connector, aimdb-knx-connector, aimdb-persistence(+sqlite); core's producer/consumer module examples, TopicProvider, extensions, AimxConfig, RecordKey Hash-contract; the websocket AuthHandler and MQTT link-ext trait docs. ~30 examples now compile under `make test` (186 doctests passing suite-wide). - Conversion surfaced real rot, now fixed in the surviving examples: key-less `configure()`/`producer()`/`consumer()` calls (API takes a key), builder chains that can't compile (`&mut Self` → by-value `build()`), `with_buffer`/`finish()` on the wrong receiver, a deserializer returning `Box<T>` instead of `T`, sync's `AimDbSyncExt` example calling the async `build()` synchronously, and `DbError::RecordNotFound` vs `RecordKeyNotFound`. - Deleted ~50 method-level fragments that restated the signature (builder key-access helpers, registrar setters, connector constructors, internal SPI sketches) plus duplicates of the crate-level examples. - Kept 24 as `ignore`, each with a written reason: downstream-crate types core cannot depend on (adapter/connector wiring, `.buffer()` ext trait), proc-macro expansion targeting aimdb-core (circular dev-dependency), embedded/wasm-only code (Embassy peripherals, `#[wasm_bindgen]`), and macro grammar sketches with placeholder types. - Dev-deps: aimdb-uds-connector gains serde/serde_json for its quick start; aimdb-sync's example uses its existing aimdb-tokio-adapter dependency. Closes #146. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: remove deprecated settings.json file --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent f3becdc commit 3d64818

42 files changed

Lines changed: 399 additions & 661 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aimdb-core/src/buffer/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,21 @@
3838
//!
3939
//! # Example
4040
//!
41+
//! Illustrative (not compiled: `.buffer()` comes from your runtime adapter's
42+
//! registrar extension trait, which `aimdb-core` cannot depend on):
43+
//!
4144
//! ```rust,ignore
4245
//! use aimdb_core::buffer::BufferCfg;
4346
//!
4447
//! // High-frequency sensor data
4548
//! reg.buffer(BufferCfg::SpmcRing { capacity: 2048 })
46-
//! .source(|em, data| async { ... })
47-
//! .tap(|em, data| async { ... });
49+
//! .source(|ctx, producer| async move { /* … */ })
50+
//! .tap(|ctx, consumer| async move { /* … */ });
4851
//!
4952
//! // Configuration updates
5053
//! reg.buffer(BufferCfg::SingleLatest)
51-
//! .source(|em, cfg| async { ... })
52-
//! .tap(|em, cfg| async { ... });
54+
//! .source(|ctx, producer| async move { /* … */ })
55+
//! .tap(|ctx, consumer| async move { /* … */ });
5356
//! ```
5457
5558
// Module structure

aimdb-core/src/buffer/traits.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,6 @@ pub trait BufferReader<T: Clone + Send>: Send {
163163
/// # Requirements
164164
/// - Record must be configured with `.with_remote_access()`
165165
/// - Only available with the `remote-access` feature (requires serde_json)
166-
///
167-
/// # Example
168-
/// ```rust,ignore
169-
/// // Internal use in remote access handler
170-
/// let json_reader: Box<dyn JsonBufferReader> = record.subscribe_json()?;
171-
/// while let Ok(json_val) = json_reader.recv_json().await {
172-
/// // Forward JSON value to remote client...
173-
/// }
174-
/// ```
175166
#[cfg(feature = "remote-access")]
176167
pub trait JsonBufferReader: Send {
177168
/// Receive the next value as JSON (async)
@@ -225,21 +216,6 @@ pub struct BufferMetricsSnapshot {
225216
///
226217
/// Implemented by buffer types when the `metrics` feature is enabled.
227218
/// Provides counters for diagnosing producer-consumer imbalances.
228-
///
229-
/// # Example
230-
/// ```rust,ignore
231-
/// use aimdb_core::buffer::BufferMetrics;
232-
///
233-
/// // After enabling `metrics` feature
234-
/// let metrics = buffer.metrics();
235-
/// if metrics.produced_count > metrics.consumed_count + 1000 {
236-
/// println!("Warning: consumer is {} items behind",
237-
/// metrics.produced_count - metrics.consumed_count);
238-
/// }
239-
/// if metrics.dropped_count > 0 {
240-
/// println!("Warning: {} items dropped due to overflow", metrics.dropped_count);
241-
/// }
242-
/// ```
243219
#[cfg(feature = "metrics")]
244220
pub trait BufferMetrics {
245221
/// Get a snapshot of current buffer metrics

aimdb-core/src/builder.rs

Lines changed: 16 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -355,16 +355,6 @@ impl AimDbBuilder {
355355
/// must return a future that runs for as long as needed (e.g. an infinite
356356
/// cleanup loop). Tasks are spawned in registration order, after all
357357
/// record tasks and connectors have been started.
358-
///
359-
/// # Example
360-
/// ```rust,ignore
361-
/// builder.on_start(|ctx| async move {
362-
/// loop {
363-
/// do_cleanup().await;
364-
/// ctx.time().sleep_secs(3600).await;
365-
/// }
366-
/// });
367-
/// ```
368358
pub fn on_start<F, Fut>(&mut self, f: F) -> &mut Self
369359
where
370360
F: FnOnce(crate::RuntimeContext) -> Fut + Send + 'static,
@@ -396,23 +386,28 @@ impl AimDbBuilder {
396386
///
397387
/// # Examples
398388
///
389+
/// Illustrative (not compiled: the connector types live in downstream
390+
/// crates `aimdb-core` cannot depend on):
391+
///
399392
/// ```rust,ignore
400393
/// // (1) data-plane link to an MQTT topic
401-
/// AimDbBuilder::new().runtime(rt)
402-
/// .with_connector(MqttConnector::new("mqtt://broker.local:1883"))
403-
/// .configure::<Temperature>(|r| { r.link_from("mqtt://commands/temp"); })
404-
/// .build().await?;
394+
/// let mut b = AimDbBuilder::new().runtime(rt)
395+
/// .with_connector(MqttConnector::new("mqtt://broker.local:1883"));
396+
/// b.configure::<Temperature>("commands.temp", |r| {
397+
/// r.link_from("mqtt://commands/temp").with_deserializer_raw(parse).finish();
398+
/// });
399+
/// b.build().await?;
405400
///
406401
/// // (2a) remote-access SERVER — no links, just expose this db over UDS
407402
/// AimDbBuilder::new().runtime(rt)
408403
/// .with_connector(UdsServer::from_config(remote_config))
409404
/// .build().await?;
410405
///
411406
/// // (2b) remote-access CLIENT — mirror a record to a peer over UDS
412-
/// AimDbBuilder::new().runtime(rt)
413-
/// .with_connector(UdsClient::new("/run/aimdb.sock"))
414-
/// .configure::<Temp>(|r| { r.with_remote_access().link_to("uds://temp"); })
415-
/// .build().await?;
407+
/// let mut b = AimDbBuilder::new().runtime(rt)
408+
/// .with_connector(UdsClient::new("/run/aimdb.sock"));
409+
/// b.configure::<Temp>("temp", |r| { r.with_remote_access().link_to("uds://temp"); });
410+
/// b.build().await?;
416411
/// ```
417412
pub fn with_connector(
418413
mut self,
@@ -441,15 +436,6 @@ impl AimDbBuilder {
441436
/// * `key` - A unique identifier for this record. Can be a string literal, `StringKey`,
442437
/// or any type implementing `RecordKey` (including user-defined enum keys).
443438
/// * `f` - Configuration closure
444-
///
445-
/// # Example
446-
/// ```rust,ignore
447-
/// // Using string literal
448-
/// builder.configure::<Temperature>("sensor.temp.room1", |reg| { ... });
449-
///
450-
/// // Using compile-time safe enum key
451-
/// builder.configure::<Temperature>(SensorKey::TempRoom1, |reg| { ... });
452-
/// ```
453439
pub fn configure<T>(
454440
&mut self,
455441
key: impl RecordKey,
@@ -569,22 +555,6 @@ impl AimDbBuilder {
569555
/// # Returns
570556
/// `DbResult<()>` — Ok once the database starts; the call then blocks until
571557
/// every future the runner is driving has completed (typically forever).
572-
///
573-
/// # Example
574-
///
575-
/// ```rust,ignore
576-
/// #[tokio::main]
577-
/// async fn main() -> DbResult<()> {
578-
/// AimDbBuilder::new()
579-
/// .runtime(Arc::new(TokioAdapter::new()?))
580-
/// .configure::<MyData>(|reg| {
581-
/// reg.with_buffer(BufferCfg::SpmcRing { capacity: 100 })
582-
/// .with_source(my_producer)
583-
/// .with_tap(my_consumer);
584-
/// })
585-
/// .run().await // Runs forever
586-
/// }
587-
/// ```
588558
pub async fn run(self) -> DbResult<()> {
589559
log_info!("Building database and spawning background tasks...");
590560

@@ -626,19 +596,6 @@ impl AimDbBuilder {
626596
/// buffer, duplicate keys, dependency-graph cycles) is collected and
627597
/// returned as one [`DbError::InvalidConfiguration`] carrying **all**
628598
/// findings — one run surfaces every mistake.
629-
///
630-
/// # Example
631-
///
632-
/// ```rust,ignore
633-
/// let (db, runner) = AimDbBuilder::new()
634-
/// .runtime(runtime)
635-
/// .configure::<Temp>("temp", |reg| { /* … */ })
636-
/// .with_connector(mqtt_builder)
637-
/// .build().await?;
638-
///
639-
/// let handle = db.clone(); // clone freely before runner.run()
640-
/// runner.run().await; // drives everything to completion
641-
/// ```
642599
pub async fn build(mut self) -> DbResult<(AimDb, AimDbRunner)> {
643600
use crate::error::ConfigError;
644601

@@ -868,6 +825,9 @@ impl Default for AimDbBuilder {
868825
///
869826
/// # Examples
870827
///
828+
/// Illustrative (not compiled: the runtime adapter lives in a downstream
829+
/// crate `aimdb-core` cannot depend on):
830+
///
871831
/// ```rust,ignore
872832
/// use aimdb_tokio_adapter::TokioAdapter;
873833
///
@@ -952,12 +912,6 @@ impl AimDb {
952912
///
953913
/// External crates (e.g. `aimdb-persistence`) retrieve their typed state here
954914
/// to service query calls. The extensions are read-only on the live handle.
955-
///
956-
/// # Example
957-
/// ```rust,ignore
958-
/// use aimdb_persistence::PersistenceState;
959-
/// let state = db.extensions().get::<PersistenceState>().unwrap();
960-
/// ```
961915
pub fn extensions(&self) -> &Extensions {
962916
&self.inner.extensions
963917
}
@@ -989,13 +943,6 @@ impl AimDb {
989943
/// # Arguments
990944
/// * `key` - The record key (e.g., "sensor.temperature")
991945
/// * `value` - The value to produce
992-
///
993-
/// # Example
994-
///
995-
/// ```rust,ignore
996-
/// db.produce::<Temperature>("sensors.indoor", indoor_temp)?;
997-
/// db.produce::<Temperature>("sensors.outdoor", outdoor_temp)?;
998-
/// ```
999946
pub fn produce<T>(&self, key: impl AsRef<str>, value: T) -> DbResult<()>
1000947
where
1001948
T: Send + 'static + Debug + Clone,
@@ -1013,15 +960,6 @@ impl AimDb {
1013960
///
1014961
/// # Arguments
1015962
/// * `key` - The record key (e.g., "sensor.temperature")
1016-
///
1017-
/// # Example
1018-
///
1019-
/// ```rust,ignore
1020-
/// let mut reader = db.subscribe::<Temperature>("sensors.indoor")?;
1021-
/// while let Ok(temp) = reader.recv().await {
1022-
/// println!("Indoor: {:.1}°C", temp.celsius);
1023-
/// }
1024-
/// ```
1025963
pub fn subscribe<T>(
1026964
&self,
1027965
key: impl AsRef<str>,
@@ -1039,17 +977,6 @@ impl AimDb {
1039977
///
1040978
/// # Arguments
1041979
/// * `key` - The record key (e.g., "sensor.temperature")
1042-
///
1043-
/// # Example
1044-
///
1045-
/// ```rust,ignore
1046-
/// let indoor_producer = db.producer::<Temperature>("sensors.indoor");
1047-
/// let outdoor_producer = db.producer::<Temperature>("sensors.outdoor");
1048-
///
1049-
/// // Each producer writes to its own record
1050-
/// indoor_producer.produce(indoor_temp);
1051-
/// outdoor_producer.produce(outdoor_temp);
1052-
/// ```
1053980
pub fn producer<T>(
1054981
&self,
1055982
key: impl Into<alloc::string::String>,
@@ -1070,16 +997,6 @@ impl AimDb {
1070997
///
1071998
/// # Arguments
1072999
/// * `key` - The record key (e.g., "sensor.temperature")
1073-
///
1074-
/// # Example
1075-
///
1076-
/// ```rust,ignore
1077-
/// let indoor_consumer = db.consumer::<Temperature>("sensors.indoor");
1078-
/// let outdoor_consumer = db.consumer::<Temperature>("sensors.outdoor");
1079-
///
1080-
/// // Each consumer reads from its own record
1081-
/// let mut rx = indoor_consumer.subscribe();
1082-
/// ```
10831000
pub fn consumer<T>(
10841001
&self,
10851002
key: impl Into<alloc::string::String>,
@@ -1102,14 +1019,6 @@ impl AimDb {
11021019
/// Resolve a record key to its RecordId
11031020
///
11041021
/// Useful for checking if a record exists before operations.
1105-
///
1106-
/// # Example
1107-
///
1108-
/// ```rust,ignore
1109-
/// if let Some(id) = db.resolve_key("sensors.temperature") {
1110-
/// println!("Record exists with ID: {}", id);
1111-
/// }
1112-
/// ```
11131022
pub fn resolve_key(&self, key: &str) -> Option<crate::record_id::RecordId> {
11141023
self.inner.resolve_str(key)
11151024
}
@@ -1118,13 +1027,6 @@ impl AimDb {
11181027
///
11191028
/// Returns a slice of RecordIds for all records of type T.
11201029
/// Useful for introspection when multiple records of the same type exist.
1121-
///
1122-
/// # Example
1123-
///
1124-
/// ```rust,ignore
1125-
/// let temp_ids = db.records_of_type::<Temperature>();
1126-
/// println!("Found {} temperature records", temp_ids.len());
1127-
/// ```
11281030
pub fn records_of_type<T: 'static>(&self) -> &[crate::record_id::RecordId] {
11291031
self.inner.records_of_type::<T>()
11301032
}
@@ -1149,14 +1051,6 @@ impl AimDb {
11491051
///
11501052
/// Returns metadata for all registered records, useful for remote access introspection.
11511053
/// Available only when the `std` feature is enabled.
1152-
///
1153-
/// # Example
1154-
/// ```rust,ignore
1155-
/// let records = db.list_records();
1156-
/// for record in records {
1157-
/// println!("Record: {} ({})", record.name, record.type_id);
1158-
/// }
1159-
/// ```
11601054
#[cfg(feature = "remote-access")]
11611055
pub fn list_records(&self) -> Vec<crate::remote::RecordMetadata> {
11621056
self.inner.list_records()
@@ -1210,11 +1104,6 @@ impl AimDb {
12101104
///
12111105
/// # Returns
12121106
/// `Ok(())` on success, error if record not found, has producers, or deserialization fails
1213-
///
1214-
/// # Example (internal use)
1215-
/// ```rust,ignore
1216-
/// db.set_record_from_json("AppConfig", json!({"debug": true}))?;
1217-
/// ```
12181107
#[cfg(feature = "remote-access")]
12191108
pub fn set_record_from_json(
12201109
&self,
@@ -1238,14 +1127,6 @@ impl AimDb {
12381127
///
12391128
/// The topic is resolved dynamically if a `TopicResolverFn` is configured,
12401129
/// otherwise the static topic from the URL is used.
1241-
///
1242-
/// # Example
1243-
/// ```rust,ignore
1244-
/// // In MqttConnector after db.build()
1245-
/// let routes = db.collect_inbound_routes("mqtt");
1246-
/// let router = RouterBuilder::from_routes(routes).build();
1247-
/// connector.set_router(router).await?;
1248-
/// ```
12491130
pub fn collect_inbound_routes(
12501131
&self,
12511132
scheme: &str,

aimdb-core/src/connector.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@
1313
//!
1414
//! # Example
1515
//!
16-
//! ```rust,ignore
17-
//! use aimdb_core::BufferCfg;
18-
//!
16+
//! ```no_run
17+
//! # use aimdb_core::AimDbBuilder;
18+
//! # #[derive(Clone, Debug)] struct WeatherAlert { level: u8 }
19+
//! # fn wire(builder: &mut AimDbBuilder) {
1920
//! builder.configure::<WeatherAlert>("weather.alert", |reg| {
20-
//! reg.buffer(BufferCfg::SingleLatest)
21-
//! .link_to("mqtt://alerts/weather")
22-
//! .with_serializer_raw(|alert: &WeatherAlert| Ok(alert.to_json_vec()))
21+
//! // .buffer(BufferCfg::SingleLatest) — via your runtime adapter's ext trait
22+
//! reg.link_to("mqtt://alerts/weather")
23+
//! .with_serializer_raw(|alert: &WeatherAlert| Ok(vec![alert.level]))
2324
//! .finish();
2425
//! });
26+
//! # }
2527
//! ```
2628
2729
use core::fmt::{self, Debug};
@@ -158,8 +160,9 @@ pub type SourceFactoryFn = Arc<dyn Fn(&AimDb) -> Box<dyn SerializedSource> + Sen
158160
///
159161
/// # Example
160162
///
161-
/// ```rust,ignore
163+
/// ```rust
162164
/// use aimdb_core::connector::TopicProvider;
165+
/// # #[derive(Clone, Debug)] struct Temperature { sensor_id: u32 }
163166
///
164167
/// struct SensorTopicProvider;
165168
///
@@ -614,6 +617,9 @@ fn parse_connector_url(url: &str) -> DbResult<ConnectorUrl> {
614617
///
615618
/// # Example
616619
///
620+
/// Illustrative sketch of a connector author's `build()` (not compiled: the
621+
/// client types are fictional — see `aimdb-mqtt-connector` for a real one):
622+
///
617623
/// ```rust,ignore
618624
/// pub struct MqttConnectorBuilder {
619625
/// broker_url: String,

0 commit comments

Comments
 (0)