From afe76d63011f9014c2268fc96b3f1dea72eff286 Mon Sep 17 00:00:00 2001 From: Quang Nguyen Date: Tue, 28 Jul 2026 17:06:13 +0700 Subject: [PATCH 01/15] Add std feature gate and no_std clip What's new: - tokio-related features are now optional; - Update `lib.rs` to gate `std` at module level for `consumer.rs`, `handle.rs`, and `producer.rs` as most units are depend on `std` dependencies at the moment. Will gate at finer level in the futures; - Add build with no default feature in Makefile --- Makefile | 2 ++ aimdb-sync/Cargo.toml | 6 +++--- aimdb-sync/src/consumer.rs | 13 ++++++++++--- aimdb-sync/src/handle.rs | 11 ++++++++--- aimdb-sync/src/lib.rs | 9 +++++++++ aimdb-sync/src/producer.rs | 7 ++++--- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 8d66dc6b..5cfffaf5 100644 --- a/Makefile +++ b/Makefile @@ -86,6 +86,8 @@ build: cargo build --package aimdb-tokio-adapter --features "tokio-runtime,tracing,observability" @printf "$(YELLOW) → Building sync wrapper$(NC)\n" cargo build --package aimdb-sync + @printf "$(YELLOW) → Building sync wrapper (no_std)$(NC)\n" + cargo build --package aimdb-sync --no-default-features @printf "$(YELLOW) → Building codegen library$(NC)\n" cargo build --package aimdb-codegen @printf "$(YELLOW) → Building CLI tools$(NC)\n" diff --git a/aimdb-sync/Cargo.toml b/aimdb-sync/Cargo.toml index a0c4dbec..882801b8 100644 --- a/aimdb-sync/Cargo.toml +++ b/aimdb-sync/Cargo.toml @@ -12,11 +12,11 @@ categories = ["database", "api-bindings"] [dependencies] # Core dependencies aimdb-core = { path = "../aimdb-core", version = "1.1.0" } -aimdb-tokio-adapter = { path = "../aimdb-tokio-adapter", version = "0.6.0" } +aimdb-tokio-adapter = { path = "../aimdb-tokio-adapter", version = "0.6.0", optional = true } tracing = { workspace = true, optional = true } # Tokio for channels and runtime -tokio = { version = "1.40", features = ["sync", "rt", "time", "macros"] } +tokio = { version = "1.40", features = ["sync", "rt", "time", "macros"], optional = true } # Error handling thiserror = { version = "2.0.16", default-features = false } @@ -38,7 +38,7 @@ serde_json = "1.0" [features] default = ["std"] -std = [] +std = ["tokio", "aimdb-tokio-adapter"] # Enable tracing for debugging tracing = ["dep:tracing", "aimdb-core/tracing"] diff --git a/aimdb-sync/src/consumer.rs b/aimdb-sync/src/consumer.rs index 5d779089..e4f393a3 100644 --- a/aimdb-sync/src/consumer.rs +++ b/aimdb-sync/src/consumer.rs @@ -1,10 +1,13 @@ //! Synchronous consumer for typed records. use crate::{SyncError, SyncResult}; -use std::fmt::Debug; +use alloc::sync::Arc; +use core::fmt::Debug; +use core::time::Duration; +#[cfg(feature = "std")] use std::sync::mpsc; -use std::sync::{Arc, Mutex}; -use std::time::Duration; +#[cfg(feature = "std")] +use std::sync::Mutex; /// Synchronous consumer for records of type `T`. /// @@ -121,6 +124,7 @@ where /// ```no_run /// use aimdb_core::AimDbBuilder; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; + /// #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use std::sync::Arc; /// use std::time::Duration; @@ -163,6 +167,7 @@ where /// ```no_run /// use aimdb_core::AimDbBuilder; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; + /// # #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use std::sync::Arc; /// @@ -211,6 +216,7 @@ where /// ```no_run /// use aimdb_core::AimDbBuilder; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; + /// # #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use std::sync::Arc; /// @@ -263,6 +269,7 @@ where /// ```no_run /// use aimdb_core::AimDbBuilder; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; + /// # #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use std::sync::Arc; /// use std::time::Duration; diff --git a/aimdb-sync/src/handle.rs b/aimdb-sync/src/handle.rs index 791df334..42c241d0 100644 --- a/aimdb-sync/src/handle.rs +++ b/aimdb-sync/src/handle.rs @@ -2,10 +2,12 @@ use crate::{SyncError, SyncResult}; use aimdb_core::{log_error, log_warn, AimDb, AimDbBuilder, DbError, DbResult}; -use std::fmt::Debug; -use std::sync::Arc; +use alloc::sync::Arc; +use core::fmt::Debug; +use core::time::Duration; +#[cfg(feature = "std")] use std::thread::{self, JoinHandle}; -use std::time::Duration; +#[cfg(feature = "std")] use tokio::sync::mpsc; /// Default channel capacity for sync producers and consumers. @@ -45,6 +47,7 @@ pub trait AimDbBuilderSyncExt { /// /// ```no_run /// use aimdb_core::AimDbBuilder; + /// # #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; /// use std::sync::Arc; @@ -121,6 +124,7 @@ impl AimDbSyncExt for AimDb { /// Call `detach()` explicitly to ensure clean shutdown. If the handle /// is dropped without calling `detach()`, a warning will be logged /// and an emergency shutdown will be attempted. +#[cfg(feature = "std")] pub struct AimDbHandle { /// Thread handle for the runtime thread thread_handle: Option>, @@ -139,6 +143,7 @@ pub struct AimDbHandle { #[derive(Debug, Clone, Copy)] struct ShutdownSignal; +#[cfg(feature = "std")] impl AimDbHandle { /// Create a new handle by spawning the runtime thread and building the database inside it. pub(crate) fn new_from_builder(builder: AimDbBuilder) -> SyncResult { diff --git a/aimdb-sync/src/lib.rs b/aimdb-sync/src/lib.rs index 20fd4508..43fc1972 100644 --- a/aimdb-sync/src/lib.rs +++ b/aimdb-sync/src/lib.rs @@ -45,8 +45,10 @@ //! //! ```no_run //! use aimdb_core::{AimDbBuilder, buffer::BufferCfg}; +//! # #[cfg(feature = "std")] //! use aimdb_tokio_adapter::{TokioAdapter, TokioRecordRegistrarExt}; //! use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; +//! # #[cfg(feature = "std")] //! use std::sync::Arc; //! //! #[derive(Debug, Clone)] @@ -245,16 +247,23 @@ #![warn(missing_docs)] #![warn(clippy::all)] #![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; +#[cfg(feature = "std")] mod consumer; mod error; +#[cfg(feature = "std")] mod handle; +#[cfg(feature = "std")] mod producer; +#[cfg(feature = "std")] pub use consumer::SyncConsumer; +#[cfg(feature = "std")] pub use handle::{AimDbBuilderSyncExt, AimDbHandle, AimDbSyncExt, DEFAULT_SYNC_CHANNEL_CAPACITY}; +#[cfg(feature = "std")] pub use producer::SyncProducer; pub use error::{SyncError, SyncResult}; diff --git a/aimdb-sync/src/producer.rs b/aimdb-sync/src/producer.rs index 08361bc7..4dd904c7 100644 --- a/aimdb-sync/src/producer.rs +++ b/aimdb-sync/src/producer.rs @@ -2,9 +2,10 @@ use crate::{SyncError, SyncResult}; use aimdb_core::DbResult; -use std::fmt::Debug; -use std::sync::Arc; -use std::time::Duration; +use alloc::sync::Arc; +use core::fmt::Debug; +use core::time::Duration; +#[cfg(feature = "std")] use tokio::sync::{mpsc, oneshot}; /// Synchronous producer for records of type `T`. From 2776ac400ec966662a0b53481b0d008c86c05a4e Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:04:22 +0700 Subject: [PATCH 02/15] Update aimdb-sync/Cargo.toml Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/Cargo.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/aimdb-sync/Cargo.toml b/aimdb-sync/Cargo.toml index 882801b8..88318a47 100644 --- a/aimdb-sync/Cargo.toml +++ b/aimdb-sync/Cargo.toml @@ -11,7 +11,13 @@ categories = ["database", "api-bindings"] [dependencies] # Core dependencies -aimdb-core = { path = "../aimdb-core", version = "1.1.0" } +# `default-features = false` is load-bearing: aimdb-core's default set is +# ["std", "alloc", "derive"], so inheriting it would pull anyhow/serde/remote +# into the `--no-default-features` build and silently un-no_std this crate. +# The `std` feature below forwards to `aimdb-core/std` for the std path. +aimdb-core = { path = "../aimdb-core", version = "1.1.0", default-features = false, features = [ + "alloc", +] } aimdb-tokio-adapter = { path = "../aimdb-tokio-adapter", version = "0.6.0", optional = true } tracing = { workspace = true, optional = true } From 4c7a0aeabf74f9369cbd711d2b514d3039b484ad Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:05:52 +0700 Subject: [PATCH 03/15] Update aimdb-sync/src/lib.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/aimdb-sync/src/lib.rs b/aimdb-sync/src/lib.rs index 43fc1972..c2cb77f0 100644 --- a/aimdb-sync/src/lib.rs +++ b/aimdb-sync/src/lib.rs @@ -45,10 +45,8 @@ //! //! ```no_run //! use aimdb_core::{AimDbBuilder, buffer::BufferCfg}; -//! # #[cfg(feature = "std")] //! use aimdb_tokio_adapter::{TokioAdapter, TokioRecordRegistrarExt}; //! use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; -//! # #[cfg(feature = "std")] //! use std::sync::Arc; //! //! #[derive(Debug, Clone)] From 14282fd9f5ce5ef9f6208badb7f69e64e22c6e37 Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:25:56 +0700 Subject: [PATCH 04/15] Update aimdb-sync/Cargo.toml Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aimdb-sync/Cargo.toml b/aimdb-sync/Cargo.toml index 88318a47..429416ee 100644 --- a/aimdb-sync/Cargo.toml +++ b/aimdb-sync/Cargo.toml @@ -44,7 +44,7 @@ serde_json = "1.0" [features] default = ["std"] -std = ["tokio", "aimdb-tokio-adapter"] +std = ["aimdb-core/std", "dep:tokio", "dep:aimdb-tokio-adapter"] # Enable tracing for debugging tracing = ["dep:tracing", "aimdb-core/tracing"] From 9a011b8118763e64363613e40d49827ee0bdd60b Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:29:39 +0700 Subject: [PATCH 05/15] Update aimdb-sync/src/consumer.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/src/consumer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/aimdb-sync/src/consumer.rs b/aimdb-sync/src/consumer.rs index e4f393a3..3b9ef33a 100644 --- a/aimdb-sync/src/consumer.rs +++ b/aimdb-sync/src/consumer.rs @@ -4,7 +4,6 @@ use crate::{SyncError, SyncResult}; use alloc::sync::Arc; use core::fmt::Debug; use core::time::Duration; -#[cfg(feature = "std")] use std::sync::mpsc; #[cfg(feature = "std")] use std::sync::Mutex; From 4e1d34a84ec9b91fb293030e94e4474c4b556483 Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:30:06 +0700 Subject: [PATCH 06/15] Update aimdb-sync/src/consumer.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/src/consumer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/aimdb-sync/src/consumer.rs b/aimdb-sync/src/consumer.rs index 3b9ef33a..1e6b57c7 100644 --- a/aimdb-sync/src/consumer.rs +++ b/aimdb-sync/src/consumer.rs @@ -5,7 +5,6 @@ use alloc::sync::Arc; use core::fmt::Debug; use core::time::Duration; use std::sync::mpsc; -#[cfg(feature = "std")] use std::sync::Mutex; /// Synchronous consumer for records of type `T`. From 07bb8fbe4c45a0ca5221c8837f56de6e7a02d752 Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:30:24 +0700 Subject: [PATCH 07/15] Update aimdb-sync/src/handle.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/src/handle.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/aimdb-sync/src/handle.rs b/aimdb-sync/src/handle.rs index 42c241d0..aa85ce47 100644 --- a/aimdb-sync/src/handle.rs +++ b/aimdb-sync/src/handle.rs @@ -47,7 +47,6 @@ pub trait AimDbBuilderSyncExt { /// /// ```no_run /// use aimdb_core::AimDbBuilder; - /// # #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; /// use std::sync::Arc; From 36161b761cc4511a915d8993761aa27a3b476cb5 Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:30:34 +0700 Subject: [PATCH 08/15] Update aimdb-sync/src/handle.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/src/handle.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/aimdb-sync/src/handle.rs b/aimdb-sync/src/handle.rs index aa85ce47..138bd6d4 100644 --- a/aimdb-sync/src/handle.rs +++ b/aimdb-sync/src/handle.rs @@ -123,7 +123,6 @@ impl AimDbSyncExt for AimDb { /// Call `detach()` explicitly to ensure clean shutdown. If the handle /// is dropped without calling `detach()`, a warning will be logged /// and an emergency shutdown will be attempted. -#[cfg(feature = "std")] pub struct AimDbHandle { /// Thread handle for the runtime thread thread_handle: Option>, From 22d66918d24df72d5888ab8c303976dfa6c66381 Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:30:50 +0700 Subject: [PATCH 09/15] Update aimdb-sync/src/producer.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/src/producer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/aimdb-sync/src/producer.rs b/aimdb-sync/src/producer.rs index 4dd904c7..08c148c1 100644 --- a/aimdb-sync/src/producer.rs +++ b/aimdb-sync/src/producer.rs @@ -5,7 +5,6 @@ use aimdb_core::DbResult; use alloc::sync::Arc; use core::fmt::Debug; use core::time::Duration; -#[cfg(feature = "std")] use tokio::sync::{mpsc, oneshot}; /// Synchronous producer for records of type `T`. From 22d3a418d08c83c8afbba45d3fba7b65bf3106c6 Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:31:06 +0700 Subject: [PATCH 10/15] Update aimdb-sync/src/handle.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- aimdb-sync/src/handle.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/aimdb-sync/src/handle.rs b/aimdb-sync/src/handle.rs index 138bd6d4..563fc0cd 100644 --- a/aimdb-sync/src/handle.rs +++ b/aimdb-sync/src/handle.rs @@ -141,7 +141,6 @@ pub struct AimDbHandle { #[derive(Debug, Clone, Copy)] struct ShutdownSignal; -#[cfg(feature = "std")] impl AimDbHandle { /// Create a new handle by spawning the runtime thread and building the database inside it. pub(crate) fn new_from_builder(builder: AimDbBuilder) -> SyncResult { From 9e0d99690ebf3c40e2a44e07db20fd5fa3bfdf01 Mon Sep 17 00:00:00 2001 From: Quang Nguyen <61941605+solus161@users.noreply.github.com> Date: Wed, 29 Jul 2026 08:40:01 +0700 Subject: [PATCH 11/15] Update Makefile Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> --- Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Makefile b/Makefile index 5cfffaf5..33bc4a8e 100644 --- a/Makefile +++ b/Makefile @@ -88,6 +88,16 @@ build: cargo build --package aimdb-sync @printf "$(YELLOW) → Building sync wrapper (no_std)$(NC)\n" cargo build --package aimdb-sync --no-default-features + @printf "$(YELLOW) → Asserting no tokio in sync wrapper (no_std)$(NC)\n" + @out=$$(cargo tree -p aimdb-sync --no-default-features -e features,no-dev 2>&1) || { \ + printf "$(RED)✗ cargo tree failed — refusing to pass vacuously:$(NC)\n"; \ + printf '%s\n' "$$out"; exit 1; \ + }; \ + if printf '%s\n' "$$out" | grep -qi tokio; then \ + printf "$(RED)✗ tokio leaked into the no_std build$(NC)\n"; \ + printf '%s\n' "$$out" | grep -i tokio; exit 1; \ + fi + @printf "$(BLUE)✓ no_std graph is tokio-free$(NC)\n" @printf "$(YELLOW) → Building codegen library$(NC)\n" cargo build --package aimdb-codegen @printf "$(YELLOW) → Building CLI tools$(NC)\n" From 71102d8ade6988f5745eac27abda17afa59780b5 Mon Sep 17 00:00:00 2001 From: Quang Nguyen Date: Wed, 29 Jul 2026 10:24:54 +0700 Subject: [PATCH 12/15] Update changes in no diff What's new: - Gate 'lib.rs` internal doctest with conditional `no_run` and `ignore` so `cargo test -p aimdb-sync --no-default-features --doc` does not fail - Several small reverted `std` guard as modules is now std-gated at `lib.rs` --- Makefile | 6 ++++++ aimdb-sync/src/consumer.rs | 5 ----- aimdb-sync/src/handle.rs | 3 --- aimdb-sync/src/lib.rs | 23 ++++++++++++++--------- aimdb-sync/src/producer.rs | 7 ------- aimdb-sync/tests/integration_test.rs | 4 +++- aimdb-sync/tests/settable_integration.rs | 2 +- 7 files changed, 24 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 33bc4a8e..8bcbbf02 100644 --- a/Makefile +++ b/Makefile @@ -169,6 +169,12 @@ test: cargo test --package aimdb-wasm-adapter --no-default-features --features observability --lib @printf "$(YELLOW) → Testing sync wrapper$(NC)\n" cargo test --package aimdb-sync + # --lib only: the crate-level doc examples document the std API (AimDbHandle / + # SyncProducer / SyncConsumer), which does not exist without `std`, so they + # cannot compile in this configuration. docs.rs builds the crate with + # all-features (aimdb-sync/Cargo.toml `[package.metadata.docs.rs]`). + @printf "$(YELLOW) → Testing sync wrapper (no_std)$(NC)\n" + cargo test --package aimdb-sync --no-default-features --lib @printf "$(YELLOW) → Testing codegen library$(NC)\n" cargo test --package aimdb-codegen @printf "$(YELLOW) → Testing CLI tools$(NC)\n" diff --git a/aimdb-sync/src/consumer.rs b/aimdb-sync/src/consumer.rs index 1e6b57c7..842c2e70 100644 --- a/aimdb-sync/src/consumer.rs +++ b/aimdb-sync/src/consumer.rs @@ -88,7 +88,6 @@ where /// /// # #[derive(Debug, Clone)] /// # struct MyData { value: i32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let handle = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter)) @@ -129,7 +128,6 @@ where /// /// # #[derive(Debug, Clone)] /// # struct MyData { value: i32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let handle = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter)) @@ -171,7 +169,6 @@ where /// /// # #[derive(Debug, Clone)] /// # struct MyData { value: i32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let handle = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter)) @@ -220,7 +217,6 @@ where /// /// # #[derive(Debug, Clone)] /// # struct MyData { value: i32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let handle = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter)) @@ -274,7 +270,6 @@ where /// /// # #[derive(Debug, Clone)] /// # struct MyData { value: i32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let handle = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter)) diff --git a/aimdb-sync/src/handle.rs b/aimdb-sync/src/handle.rs index 563fc0cd..f9963f27 100644 --- a/aimdb-sync/src/handle.rs +++ b/aimdb-sync/src/handle.rs @@ -5,9 +5,7 @@ use aimdb_core::{log_error, log_warn, AimDb, AimDbBuilder, DbError, DbResult}; use alloc::sync::Arc; use core::fmt::Debug; use core::time::Duration; -#[cfg(feature = "std")] use std::thread::{self, JoinHandle}; -#[cfg(feature = "std")] use tokio::sync::mpsc; /// Default channel capacity for sync producers and consumers. @@ -52,7 +50,6 @@ pub trait AimDbBuilderSyncExt { /// use std::sync::Arc; /// /// # #[derive(Debug, Clone)] struct MyData { value: f32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let mut builder = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter::new()?)); diff --git a/aimdb-sync/src/lib.rs b/aimdb-sync/src/lib.rs index c2cb77f0..82f00b1c 100644 --- a/aimdb-sync/src/lib.rs +++ b/aimdb-sync/src/lib.rs @@ -43,7 +43,8 @@ //! //! ## Quick Start //! -//! ```no_run +#![cfg_attr(feature = "std", doc = "```no_run")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] //! use aimdb_core::{AimDbBuilder, buffer::BufferCfg}; //! use aimdb_tokio_adapter::{TokioAdapter, TokioRecordRegistrarExt}; //! use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; @@ -53,8 +54,6 @@ //! struct Temperature { //! celsius: f32, //! } -//! // Guard againts the use of TokioAdapter in case of "std" -//! # #[cfg(feature = "std")] //! # fn main() -> SyncResult<()> { //! // Build and attach database (NO #[tokio::main] NEEDED!) //! let adapter = Arc::new(TokioAdapter::new()?); @@ -87,7 +86,8 @@ //! //! Both `SyncProducer` and `SyncConsumer` can be cloned and shared across threads: //! -//! ```no_run +#![cfg_attr(feature = "std", doc = "```no_run")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] //! use std::thread; //! # use aimdb_sync::{SyncConsumer, SyncProducer}; //! # #[derive(Debug, Clone)] struct Temperature { celsius: f32 } @@ -114,7 +114,8 @@ //! Note: Cloning a `SyncConsumer` shares the same channel, so only one thread //! will receive each value. For independent subscriptions, create multiple consumers: //! -//! ```no_run +#![cfg_attr(feature = "std", doc = "```no_run")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # use aimdb_sync::{AimDbHandle, SyncResult}; //! # #[derive(Debug, Clone)] struct Temperature { celsius: f32 } //! # fn demo(handle: &AimDbHandle) -> SyncResult<()> { @@ -131,7 +132,8 @@ //! By default, both producers and consumers use a channel capacity of 100. //! You can customize this per record type using the `_with_capacity` methods: //! -//! ```no_run +#![cfg_attr(feature = "std", doc = "```no_run")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # use aimdb_sync::{AimDbHandle, SyncResult}; //! # #[derive(Debug, Clone)] struct SensorData { value: f32 } //! # #[derive(Debug, Clone)] struct RareEvent { code: u8 } @@ -167,7 +169,8 @@ //! ### Solutions for SingleLatest Semantics //! //! 1. **Use `get_latest()`** - Drains the channel to get the most recent value: -//! ```no_run +#![cfg_attr(feature = "std", doc = "```no_run")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # use aimdb_sync::SyncResult; //! # #[derive(Debug, Clone)] struct Temperature { celsius: f32 } //! # fn demo(consumer: &aimdb_sync::SyncConsumer) -> SyncResult<()> { @@ -178,7 +181,8 @@ //! ``` //! //! 2. **Use capacity=1** - Minimize queueing: -//! ```no_run +#![cfg_attr(feature = "std", doc = "```no_run")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # #[derive(Debug, Clone)] struct Temperature { celsius: f32 } //! # fn demo(handle: &aimdb_sync::AimDbHandle) -> aimdb_sync::SyncResult<()> { //! let consumer = handle.consumer_with_capacity::("sensor.temp", 1)?; @@ -223,7 +227,8 @@ //! and return any errors that occur in the async context //! - `try_set()` sends immediately without waiting for the produce result (fire-and-forget) //! -//! ```no_run +#![cfg_attr(feature = "std", doc = "```no_run")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # use aimdb_sync::{DbError, SyncError, SyncProducer}; //! # use aimdb_core::{log_error}; //! # #[derive(Debug, Clone)] struct Temperature { celsius: f32 } diff --git a/aimdb-sync/src/producer.rs b/aimdb-sync/src/producer.rs index 08c148c1..033fc0b0 100644 --- a/aimdb-sync/src/producer.rs +++ b/aimdb-sync/src/producer.rs @@ -124,7 +124,6 @@ where /// /// # #[derive(Debug, Clone)] /// # struct MyData { value: i32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let handle = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter)) @@ -161,7 +160,6 @@ where /// /// # #[derive(Debug, Clone)] /// # struct MyData { value: i32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let handle = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter)) @@ -199,7 +197,6 @@ where /// /// # #[derive(Debug, Clone)] /// # struct MyData { value: i32 } - /// # #[cfg(feature = "std")] /// # fn main() -> SyncResult<()> { /// let handle = AimDbBuilder::new() /// .runtime(Arc::new(TokioAdapter)) @@ -243,8 +240,6 @@ where /// # Example /// /// ```no_run - /// # #[cfg(feature = "data-contracts")] - /// # #[cfg(feature = "std")] /// # use aimdb_sync::SyncResult; /// # fn main() -> SyncResult<()> { /// use aimdb_core::AimDbBuilder; @@ -272,8 +267,6 @@ where /// producer.set_value(22.5)?; // constructs Temperature::set(22.5, now_ms) and sends /// # Ok(()) /// # } - /// # #[cfg(not(feature = "data-contracts"))] - /// # fn main() {} /// ``` pub fn set_value(&self, value: T::Value) -> SyncResult<()> { self.set(T::set(value, unix_now_ms())) diff --git a/aimdb-sync/tests/integration_test.rs b/aimdb-sync/tests/integration_test.rs index 9a9136a9..52dee837 100644 --- a/aimdb-sync/tests/integration_test.rs +++ b/aimdb-sync/tests/integration_test.rs @@ -1,7 +1,9 @@ //! Integration tests for aimdb-sync //! //! These tests verify end-to-end functionality of the synchronous API wrapper. - +// The whole file exercises `attach()` / `SyncProducer` / `SyncConsumer`, none of +// which exist without `std`. +#![cfg(feature = "std")] use aimdb_core::{buffer::BufferCfg, AimDbBuilder, DbError}; use aimdb_sync::AimDbBuilderSyncExt; use aimdb_sync::SyncError; diff --git a/aimdb-sync/tests/settable_integration.rs b/aimdb-sync/tests/settable_integration.rs index 815885b1..eb15052f 100644 --- a/aimdb-sync/tests/settable_integration.rs +++ b/aimdb-sync/tests/settable_integration.rs @@ -2,7 +2,7 @@ //! construct via `Settable::set`, produce, and consume end-to-end through the //! real sync bridge. -#![cfg(feature = "data-contracts")] +#![cfg(all(feature = "std", feature = "data-contracts"))] use aimdb_core::{buffer::BufferCfg, AimDbBuilder}; use aimdb_data_contracts::{SchemaType, Settable}; From 37bbbbb8a6892dcbd131d46d97e7db81c54d4123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Wed, 29 Jul 2026 20:26:13 +0000 Subject: [PATCH 13/15] Complete the no_std review sweep for aimdb-sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-on to the review of #205, applied directly to avoid another round-trip. - consumer.rs: drop the last 4 inert `#[cfg(feature = "std")]` guards in doc examples. `mod consumer` is already std-gated at lib.rs:257, so they can never evaluate false. The one on `get_with_timeout` was also missing the `# ` hide prefix and rendered into the published docs. - consumer.rs: backtick `Arc` in a doc comment — it was the last `cargo doc` warning (unclosed HTML tag), pre-existing from before #204. - Makefile: add the no_std clippy arm and the thumbv7em-none-eabihf check, matching the per-crate convention. The cross-compile lane is the only one that catches std arriving through a dependency's default features; a host `--no-default-features` build passes regardless because the host has std, which is why CI was green while the no_std path was broken. - Makefile: drop `--lib` from the no_std test arm. The conditional ```ignore fence added in 71102d8 means the full command now passes, so the arm covers unit tests, integration tests and doctests. Co-Authored-By: Claude Opus 5 --- Makefile | 10 +++++----- aimdb-sync/src/consumer.rs | 6 +----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 8bcbbf02..ea913aab 100644 --- a/Makefile +++ b/Makefile @@ -169,12 +169,8 @@ test: cargo test --package aimdb-wasm-adapter --no-default-features --features observability --lib @printf "$(YELLOW) → Testing sync wrapper$(NC)\n" cargo test --package aimdb-sync - # --lib only: the crate-level doc examples document the std API (AimDbHandle / - # SyncProducer / SyncConsumer), which does not exist without `std`, so they - # cannot compile in this configuration. docs.rs builds the crate with - # all-features (aimdb-sync/Cargo.toml `[package.metadata.docs.rs]`). @printf "$(YELLOW) → Testing sync wrapper (no_std)$(NC)\n" - cargo test --package aimdb-sync --no-default-features --lib + cargo test --package aimdb-sync --no-default-features @printf "$(YELLOW) → Testing codegen library$(NC)\n" cargo test --package aimdb-codegen @printf "$(YELLOW) → Testing CLI tools$(NC)\n" @@ -258,6 +254,8 @@ clippy: cargo clippy --package aimdb-embassy-adapter --target thumbv7em-none-eabihf --features "embassy-runtime,embassy-net-support" -- -D warnings @printf "$(YELLOW) → Clippy on sync wrapper$(NC)\n" cargo clippy --package aimdb-sync --all-targets -- -D warnings + @printf "$(YELLOW) → Clippy on sync wrapper (no_std)$(NC)\n" + cargo clippy --package aimdb-sync --no-default-features --all-targets -- -D warnings @printf "$(YELLOW) → Clippy on client library$(NC)\n" cargo clippy --package aimdb-client --all-targets -- -D warnings @printf "$(YELLOW) → Clippy on client library (serial transport arm)$(NC)\n" @@ -410,6 +408,8 @@ test-embedded: cargo check --package aimdb-tcp-connector --target thumbv7em-none-eabihf --target-dir $(EMBEDDED_CHECK_TARGET_DIR) --no-default-features --features "embassy-runtime" @printf "$(YELLOW) → Checking aimdb-tcp-connector (Embassy TCP client + defmt) on thumbv7em-none-eabihf target$(NC)\n" cargo check --package aimdb-tcp-connector --target thumbv7em-none-eabihf --target-dir $(EMBEDDED_CHECK_TARGET_DIR) --no-default-features --features "embassy-runtime,defmt" + @printf "$(YELLOW) → Checking aimdb-sync (no_std) on thumbv7em-none-eabihf target$(NC)\n" + cargo check --package aimdb-sync --target thumbv7em-none-eabihf --target-dir $(EMBEDDED_CHECK_TARGET_DIR) --no-default-features ## Example projects examples: diff --git a/aimdb-sync/src/consumer.rs b/aimdb-sync/src/consumer.rs index 842c2e70..2b519da3 100644 --- a/aimdb-sync/src/consumer.rs +++ b/aimdb-sync/src/consumer.rs @@ -50,7 +50,7 @@ where T: Send + Sync + 'static + Debug + Clone, { /// Channel receiver for consumer data - /// Wrapped in Arc so it can be shared but only one thread receives at a time + /// Wrapped in `Arc` so it can be shared but only one thread receives at a time rx: Arc>>, } @@ -121,7 +121,6 @@ where /// ```no_run /// use aimdb_core::AimDbBuilder; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; - /// #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use std::sync::Arc; /// use std::time::Duration; @@ -163,7 +162,6 @@ where /// ```no_run /// use aimdb_core::AimDbBuilder; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; - /// # #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use std::sync::Arc; /// @@ -211,7 +209,6 @@ where /// ```no_run /// use aimdb_core::AimDbBuilder; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; - /// # #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use std::sync::Arc; /// @@ -263,7 +260,6 @@ where /// ```no_run /// use aimdb_core::AimDbBuilder; /// use aimdb_sync::{AimDbBuilderSyncExt, SyncResult}; - /// # #[cfg(feature = "std")] /// use aimdb_tokio_adapter::TokioAdapter; /// use std::sync::Arc; /// use std::time::Duration; From 1c769e0d585307eae5a9be215e29e3d1b0ba292c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Wed, 29 Jul 2026 20:31:37 +0000 Subject: [PATCH 14/15] Add data-contracts CI lanes for aimdb-sync `aimdb-sync/data-contracts` had no coverage in any make target, so tests/settable_integration.rs and the `set_value` doctest never compiled in CI. No consumer enables the feature either, so nothing reached it transitively. Adds a test arm and a clippy arm, matching the per-feature-combination convention aimdb-client uses. The test arm picks up 4 integration tests and a 26th doctest that were previously invisible. Co-Authored-By: Claude Opus 5 --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index ea913aab..c6e1cebc 100644 --- a/Makefile +++ b/Makefile @@ -171,6 +171,8 @@ test: cargo test --package aimdb-sync @printf "$(YELLOW) → Testing sync wrapper (no_std)$(NC)\n" cargo test --package aimdb-sync --no-default-features + @printf "$(YELLOW) → Testing sync wrapper (data-contracts: set_value family)$(NC)\n" + cargo test --package aimdb-sync --features data-contracts @printf "$(YELLOW) → Testing codegen library$(NC)\n" cargo test --package aimdb-codegen @printf "$(YELLOW) → Testing CLI tools$(NC)\n" @@ -256,6 +258,8 @@ clippy: cargo clippy --package aimdb-sync --all-targets -- -D warnings @printf "$(YELLOW) → Clippy on sync wrapper (no_std)$(NC)\n" cargo clippy --package aimdb-sync --no-default-features --all-targets -- -D warnings + @printf "$(YELLOW) → Clippy on sync wrapper (data-contracts)$(NC)\n" + cargo clippy --package aimdb-sync --features data-contracts --all-targets -- -D warnings @printf "$(YELLOW) → Clippy on client library$(NC)\n" cargo clippy --package aimdb-client --all-targets -- -D warnings @printf "$(YELLOW) → Clippy on client library (serial transport arm)$(NC)\n" From c0ff11bbc39d574979d9fd8bd044d00b56f774ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Wed, 29 Jul 2026 20:35:32 +0000 Subject: [PATCH 15/15] Gate WASM cancel machinery on wasm-runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `bindings` (lib.rs:39) is the only consumer of CancelToken/CancelHandle and is itself `#[cfg(feature = "wasm-runtime")]`, so the host test lanes (`--no-default-features`) compiled these items with no reachable caller and emitted 6 dead_code warnings. Gating them on the same feature as their consumer keeps the two in step. `Cell` was used only by CancelInner, so it moves behind the same gate to avoid trading dead_code for unused_imports; `RefCell` stays unconditional. Not dead code — the wasm32 path is unchanged and still compiles clean with -D warnings. Co-Authored-By: Claude Opus 5 --- aimdb-wasm-adapter/src/buffer.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/aimdb-wasm-adapter/src/buffer.rs b/aimdb-wasm-adapter/src/buffer.rs index bb96107f..1564afbb 100644 --- a/aimdb-wasm-adapter/src/buffer.rs +++ b/aimdb-wasm-adapter/src/buffer.rs @@ -19,7 +19,9 @@ use alloc::boxed::Box; use alloc::collections::VecDeque; use alloc::rc::Rc; use alloc::vec::Vec; -use core::cell::{Cell, RefCell}; +#[cfg(feature = "wasm-runtime")] +use core::cell::Cell; +use core::cell::RefCell; use core::task::{Context, Poll, Waker}; use aimdb_core::buffer::{Buffer, BufferCfg, BufferReader, DynBuffer}; @@ -389,6 +391,7 @@ fn wake_all(wakers: &mut Vec) { // ============================================================================ /// Shared state between [`CancelToken`] and [`CancelHandle`]. +#[cfg(feature = "wasm-runtime")] struct CancelInner { cancelled: Cell, waker: RefCell>, @@ -399,6 +402,7 @@ struct CancelInner { /// Polled in a `futures_util::future::select` alongside `reader.recv()`. /// When [`CancelHandle::cancel()`] fires, the stored waker is woken and /// `is_cancelled()` returns `true`, causing the select to resolve. +#[cfg(feature = "wasm-runtime")] pub(crate) struct CancelToken { inner: Rc, } @@ -407,17 +411,23 @@ pub(crate) struct CancelToken { /// /// Calling [`cancel()`](CancelHandle::cancel) sets the flag and wakes the /// subscription task so it exits immediately — even if `recv()` is blocked. +#[cfg(feature = "wasm-runtime")] pub(crate) struct CancelHandle { inner: Rc, } // SAFETY: wasm32 is single-threaded — no concurrent access possible +#[cfg(feature = "wasm-runtime")] unsafe impl Send for CancelToken {} +#[cfg(feature = "wasm-runtime")] unsafe impl Sync for CancelToken {} +#[cfg(feature = "wasm-runtime")] unsafe impl Send for CancelHandle {} +#[cfg(feature = "wasm-runtime")] unsafe impl Sync for CancelHandle {} /// Create a linked cancel token/handle pair. +#[cfg(feature = "wasm-runtime")] pub(crate) fn cancel_pair() -> (CancelToken, CancelHandle) { let inner = Rc::new(CancelInner { cancelled: Cell::new(false), @@ -431,6 +441,7 @@ pub(crate) fn cancel_pair() -> (CancelToken, CancelHandle) { ) } +#[cfg(feature = "wasm-runtime")] impl CancelToken { /// Returns `true` if [`CancelHandle::cancel()`] has been called. pub(crate) fn is_cancelled(&self) -> bool { @@ -443,6 +454,7 @@ impl CancelToken { } } +#[cfg(feature = "wasm-runtime")] impl CancelHandle { /// Signal cancellation and wake the subscription task. ///