Skip to content

Commit c99051b

Browse files
committed
refactor: update dependencies and enhance buffer functionality with peek() method
1 parent 762ee76 commit c99051b

7 files changed

Lines changed: 145 additions & 21 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ test:
114114
cargo test --package aimdb-tokio-adapter --features "tokio-runtime,tracing,metrics"
115115
@printf "$(YELLOW) → Testing tokio adapter (with profiling)$(NC)\n"
116116
cargo test --package aimdb-tokio-adapter --features "tokio-runtime,tracing,profiling"
117+
@printf "$(YELLOW) → Testing embassy adapter (host, no executor: buffers, join-queue, doctests)$(NC)\n"
118+
cargo test --package aimdb-embassy-adapter --no-default-features --features "alloc,embassy-sync,embassy-time"
117119
@printf "$(YELLOW) → Testing sync wrapper$(NC)\n"
118120
cargo test --package aimdb-sync
119121
@printf "$(YELLOW) → Testing codegen library$(NC)\n"

aimdb-embassy-adapter/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ futures = "0.3"
7878
# Provides critical-section impl for host-side tests (embassy_sync channels need it)
7979
critical-section = { version = "1.1", features = ["std"] }
8080

81+
# Lets host tests register a trivial time driver (defines `_embassy_time_now`),
82+
# pulled in by embassy-time's `defmt-timestamp-uptime`. No tick feature here so
83+
# it unifies with the workspace's `tick-hz-32_768` (mock-driver/std would force
84+
# a conflicting tick rate).
85+
embassy-time-driver = { path = "../_external/embassy/embassy-time-driver" }
86+
8187
# For tracing tests
8288
tracing-test = "0.2"
8389

aimdb-embassy-adapter/src/buffer.rs

Lines changed: 123 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ use aimdb_core::buffer::{BufferCounters, BufferMetrics, BufferMetricsSnapshot};
6969
/// # Example
7070
/// ```no_run
7171
/// use aimdb_embassy_adapter::EmbassyBuffer;
72-
/// use aimdb_core::buffer::{BufferBackend, BufferCfg};
72+
/// use aimdb_core::buffer::{Buffer, BufferReader};
7373
///
7474
/// // Create an SPMC ring buffer with capacity 32, 4 subscribers, 2 publishers
7575
/// type MyBuffer = EmbassyBuffer<u32, 32, 4, 2, 4>;
76-
/// static BUFFER: MyBuffer = MyBuffer::new_spmc();
7776
///
7877
/// # async fn example() {
79-
/// let mut reader = BUFFER.subscribe();
80-
/// BUFFER.push(42);
78+
/// let buffer: MyBuffer = MyBuffer::new_spmc();
79+
/// let mut reader = buffer.subscribe();
80+
/// buffer.push(42);
8181
/// let value = reader.recv().await.unwrap();
8282
/// # }
8383
/// ```
@@ -240,6 +240,20 @@ impl<
240240
self
241241
}
242242

243+
fn peek(&self) -> Option<T> {
244+
match &*self.inner {
245+
// Watch stores the latest value natively; try_get() clones it
246+
// without consuming a receiver slot or advancing any cursor.
247+
EmbassyBufferInner::Watch(watch) => watch.try_get(),
248+
// Channel<_, T, 1>::try_peek() clones the pending slot without
249+
// removing it (the slot is drained once a consumer receives).
250+
// Mirrors the Tokio Mailbox arm.
251+
EmbassyBufferInner::Mailbox(channel) => channel.try_peek().ok(),
252+
// PubSub has no canonical latest — see design 031 §SPMC Ring.
253+
EmbassyBufferInner::SpmcRing(_) => None,
254+
}
255+
}
256+
243257
#[cfg(feature = "metrics")]
244258
fn metrics_snapshot(&self) -> Option<BufferMetricsSnapshot> {
245259
Some(<Self as BufferMetrics>::metrics(self))
@@ -546,6 +560,40 @@ impl<
546560
mod tests {
547561
use super::*;
548562

563+
// ── Host-test scaffolding ────────────────────────────────────────────
564+
// The crate links `defmt` (workspace dep) and embassy-time's
565+
// `defmt-timestamp-uptime`, but on the host neither a defmt logger nor a
566+
// time driver exists. Provide no-op stubs so the test binary links. Run via
567+
// the `test` Make target, or directly:
568+
// cargo test -p aimdb-embassy-adapter \
569+
// --no-default-features --features "alloc,embassy-sync,embassy-time"
570+
// (`embassy-runtime` would pull the cortex-m executor, which can't host-build.)
571+
#[defmt::global_logger]
572+
struct TestLogger;
573+
574+
unsafe impl defmt::Logger for TestLogger {
575+
fn acquire() {}
576+
unsafe fn flush() {}
577+
unsafe fn release() {}
578+
unsafe fn write(_bytes: &[u8]) {}
579+
}
580+
581+
#[defmt::panic_handler]
582+
fn defmt_panic() -> ! {
583+
core::panic!("defmt panic in host test")
584+
}
585+
586+
// Trivial time driver so `_embassy_time_now` resolves on the host. peek()
587+
// never reads the clock; the driver only needs to exist for linking.
588+
struct TestTimeDriver;
589+
impl embassy_time_driver::Driver for TestTimeDriver {
590+
fn now(&self) -> u64 {
591+
0
592+
}
593+
fn schedule_wake(&self, _at: u64, _waker: &core::task::Waker) {}
594+
}
595+
embassy_time_driver::time_driver_impl!(static TEST_TIME_DRIVER: TestTimeDriver = TestTimeDriver);
596+
549597
// Note: Embassy tests typically run on actual embedded targets or with embassy-executor
550598
// For now, these are basic compilation tests. Integration tests would need embassy-executor.
551599

@@ -571,4 +619,75 @@ mod tests {
571619
let cfg3 = BufferCfg::Mailbox;
572620
let _buf3: TestBuffer = Buffer::new(&cfg3);
573621
}
622+
623+
// ========================================================================
624+
// peek() Tests — non-destructive buffer-native reads (design 031)
625+
//
626+
// push()/peek() are synchronous and lock a CriticalSectionRawMutex; the
627+
// `critical-section` std impl in dev-dependencies provides the host-side
628+
// implementation, so these run without an embassy executor. Run with:
629+
// cargo test -p aimdb-embassy-adapter \
630+
// --no-default-features --features "alloc,embassy-sync,embassy-time"
631+
// ========================================================================
632+
633+
use aimdb_core::buffer::DynBuffer;
634+
635+
type PeekBuffer = EmbassyBuffer<i32, 8, 4, 2, 4>;
636+
637+
#[test]
638+
fn test_peek_single_latest_empty() {
639+
let buffer: PeekBuffer = PeekBuffer::new_watch();
640+
assert_eq!(DynBuffer::peek(&buffer), None);
641+
}
642+
643+
#[test]
644+
fn test_peek_single_latest_returns_latest() {
645+
let buffer: PeekBuffer = PeekBuffer::new_watch();
646+
DynBuffer::push(&buffer, 1);
647+
DynBuffer::push(&buffer, 2);
648+
DynBuffer::push(&buffer, 3);
649+
assert_eq!(DynBuffer::peek(&buffer), Some(3));
650+
}
651+
652+
#[test]
653+
fn test_peek_single_latest_is_non_destructive() {
654+
let buffer: PeekBuffer = PeekBuffer::new_watch();
655+
DynBuffer::push(&buffer, 42);
656+
// Multiple peeks return the same value.
657+
assert_eq!(DynBuffer::peek(&buffer), Some(42));
658+
assert_eq!(DynBuffer::peek(&buffer), Some(42));
659+
}
660+
661+
#[test]
662+
fn test_peek_mailbox_empty() {
663+
let buffer: PeekBuffer = PeekBuffer::new_mailbox();
664+
assert_eq!(DynBuffer::peek(&buffer), None);
665+
}
666+
667+
#[test]
668+
fn test_peek_mailbox_returns_pending() {
669+
let buffer: PeekBuffer = PeekBuffer::new_mailbox();
670+
DynBuffer::push(&buffer, 7);
671+
assert_eq!(DynBuffer::peek(&buffer), Some(7));
672+
// Peek is non-destructive: the slot is still occupied.
673+
assert_eq!(DynBuffer::peek(&buffer), Some(7));
674+
}
675+
676+
#[test]
677+
fn test_peek_mailbox_reflects_overwrite() {
678+
let buffer: PeekBuffer = PeekBuffer::new_mailbox();
679+
DynBuffer::push(&buffer, 1);
680+
DynBuffer::push(&buffer, 2);
681+
assert_eq!(DynBuffer::peek(&buffer), Some(2));
682+
}
683+
684+
#[test]
685+
fn test_peek_spmc_ring_returns_none() {
686+
// PubSub has no canonical latest — see design 031 §SPMC Ring.
687+
let buffer: PeekBuffer = PeekBuffer::new_spmc();
688+
assert_eq!(DynBuffer::peek(&buffer), None);
689+
DynBuffer::push(&buffer, 1);
690+
DynBuffer::push(&buffer, 2);
691+
assert_eq!(DynBuffer::peek(&buffer), None);
692+
}
574693
}

aimdb-embassy-adapter/src/join_queue.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -102,23 +102,18 @@ impl JoinFanInRuntime for EmbassyAdapter {
102102
// These tests cover: roundtrip ordering, bounded backpressure, and sender cloning.
103103
// Embassy channels do not close — there are no QueueClosed scenarios to test.
104104
//
105-
// NOTE: the tests themselves only depend on `embassy_sync::Channel` and
106-
// `futures::executor::block_on`, both of which are host-portable. The
107-
// `critical-section` dev-dep with `std` feature is provided so the
108-
// `CriticalSectionRawMutex` link target is satisfied on host.
109-
//
110-
// However, the tests live in a module gated on `feature = "embassy-runtime"`,
111-
// which transitively pulls in `embassy-executor`'s `platform-cortex-m` (ARM
112-
// assembly) and so does not compile under `cargo test` on x86_64. As a result
113-
// they are NOT exercised by `make check` / `make all` today — only by
114-
// `cargo check --target thumbv7em-none-eabihf --features embassy-runtime`,
115-
// which type-checks but does not execute them. Run them manually on an
116-
// Embassy-capable board or ARM simulator, or via a host-side harness that
117-
// builds the queue module without the executor.
105+
// They run on the host: the queue types depend only on `embassy_sync::Channel`
106+
// and `futures::executor::block_on` (the runtime-specific `JoinFanInRuntime`
107+
// impl above carries its own `embassy-runtime` gate), so this module is gated on
108+
// `embassy-sync` rather than `embassy-runtime` and never pulls embassy-executor's
109+
// cortex-m assembly into the host test build. `make test` exercises them via:
110+
// cargo test -p aimdb-embassy-adapter \
111+
// --no-default-features --features "alloc,embassy-sync,embassy-time"
112+
// (the `critical-section/std` dev-dep satisfies the `CriticalSectionRawMutex`
113+
// link target; defmt/time-driver stubs live in `buffer.rs`'s test module).
118114
#[cfg(test)]
119115
mod tests {
120116
use super::*;
121-
use aimdb_executor::{JoinQueue as _, JoinReceiver as _, JoinSender as _};
122117
use futures::executor::block_on;
123118

124119
fn make_channel() -> &'static EmbassyChan<u32> {

aimdb-embassy-adapter/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ extern crate alloc;
6666
#[cfg(all(not(feature = "std"), feature = "embassy-sync"))]
6767
pub mod buffer;
6868

69-
#[cfg(all(not(feature = "std"), feature = "embassy-runtime"))]
69+
#[cfg(all(not(feature = "std"), feature = "embassy-sync"))]
7070
pub mod join_queue;
7171

7272
#[cfg(not(feature = "std"))]

0 commit comments

Comments
 (0)