Skip to content

Commit b4e8659

Browse files
ggmaldolxsaah
andauthored
#94 — Minimal example: hello-mailbox (#98)
* feat: add hello-mailbox example * Suggestions by the mantainer Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * Update Cargo.toml Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * Update examples/hello-mailbox/Cargo.toml Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * Update examples/hello-mailbox/Cargo.toml Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * Update examples/hello-mailbox/src/main.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * Update examples/hello-mailbox/src/main.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * Update examples/hello-mailbox/src/main.rs Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * Update examples/hello-mailbox/README.md Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * Update examples/hello-mailbox/README.md Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com> * chore: add hello-mailbox to Makefile fmt and examples targets --------- Co-authored-by: sounds.like.lx <147444674+lxsaah@users.noreply.github.com>
1 parent 5b22f7e commit b4e8659

6 files changed

Lines changed: 141 additions & 4 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ members = [
3131
"examples/weather-mesh-demo/weather-station-alpha",
3232
"examples/weather-mesh-demo/weather-station-beta",
3333
"examples/weather-mesh-demo/weather-station-gamma",
34+
"examples/hello-mailbox",
3435
]
3536
exclude = ["_external"]
3637
resolver = "2"

Makefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ test:
119119

120120
fmt:
121121
@printf "$(GREEN)Formatting code (workspace members only)...$(NC)\n"
122-
@for pkg in aimdb-executor aimdb-derive aimdb-data-contracts aimdb-core aimdb-client aimdb-embassy-adapter aimdb-tokio-adapter aimdb-wasm-adapter aimdb-sync aimdb-persistence aimdb-persistence-sqlite aimdb-mqtt-connector aimdb-knx-connector aimdb-ws-protocol aimdb-websocket-connector aimdb-codegen aimdb-cli aimdb-mcp sync-api-demo tokio-mqtt-connector-demo embassy-mqtt-connector-demo tokio-knx-connector-demo embassy-knx-connector-demo weather-mesh-common weather-hub weather-station-alpha weather-station-beta; do \
122+
@for pkg in aimdb-executor aimdb-derive aimdb-data-contracts aimdb-core aimdb-client aimdb-embassy-adapter aimdb-tokio-adapter aimdb-wasm-adapter aimdb-sync aimdb-persistence aimdb-persistence-sqlite aimdb-mqtt-connector aimdb-knx-connector aimdb-ws-protocol aimdb-websocket-connector aimdb-codegen aimdb-cli aimdb-mcp sync-api-demo tokio-mqtt-connector-demo embassy-mqtt-connector-demo tokio-knx-connector-demo embassy-knx-connector-demo weather-mesh-common weather-hub weather-station-alpha weather-station-beta hello-mailbox; do \
123123
printf "$(YELLOW) → Formatting $$pkg$(NC)\n"; \
124124
cargo fmt -p $$pkg 2>/dev/null || true; \
125125
done
@@ -128,7 +128,7 @@ fmt:
128128
fmt-check:
129129
@printf "$(GREEN)Checking code formatting (workspace members only)...$(NC)\n"
130130
@FAILED=0; \
131-
for pkg in aimdb-executor aimdb-derive aimdb-data-contracts aimdb-core aimdb-client aimdb-embassy-adapter aimdb-tokio-adapter aimdb-wasm-adapter aimdb-sync aimdb-persistence aimdb-persistence-sqlite aimdb-mqtt-connector aimdb-knx-connector aimdb-ws-protocol aimdb-websocket-connector aimdb-codegen aimdb-cli aimdb-mcp sync-api-demo tokio-mqtt-connector-demo embassy-mqtt-connector-demo tokio-knx-connector-demo embassy-knx-connector-demo weather-mesh-common weather-hub weather-station-alpha weather-station-beta; do \
131+
for pkg in aimdb-executor aimdb-derive aimdb-data-contracts aimdb-core aimdb-client aimdb-embassy-adapter aimdb-tokio-adapter aimdb-wasm-adapter aimdb-sync aimdb-persistence aimdb-persistence-sqlite aimdb-mqtt-connector aimdb-knx-connector aimdb-ws-protocol aimdb-websocket-connector aimdb-codegen aimdb-cli aimdb-mcp sync-api-demo tokio-mqtt-connector-demo embassy-mqtt-connector-demo tokio-knx-connector-demo embassy-knx-connector-demo weather-mesh-common weather-hub weather-station-alpha weather-station-beta hello-mailbox; do \
132132
printf "$(YELLOW) → Checking $$pkg$(NC)\n"; \
133133
if ! cargo fmt -p $$pkg -- --check 2>&1; then \
134134
printf "$(RED)❌ Formatting check failed for $$pkg$(NC)\n"; \
@@ -275,6 +275,8 @@ examples:
275275
cargo build --package weather-station-beta
276276
@printf "$(YELLOW) → Building weather-station-gamma (embedded, embassy runtime)$(NC)\n"
277277
cargo build --package weather-station-gamma --target thumbv7em-none-eabihf
278+
@printf "$(YELLOW) → Building hello-mailbox (sync)$(NC)\n"
279+
cargo build --package hello-mailbox
278280
@printf "$(GREEN)All examples built successfully!$(NC)\n"
279281

280282
## Security & Quality commands
@@ -414,7 +416,7 @@ check: fmt-check clippy test test-embedded test-wasm deny
414416
@printf "$(BLUE)✓ Embedded target compatibility verified$(NC)\n"
415417
@printf "$(BLUE)✓ WASM target compatibility verified$(NC)\n"
416418
@printf "$(BLUE)✓ Dependencies verified (deny)$(NC)\n"
417-
419+
418420
## WASM commands
419421
wasm:
420422
@printf "$(GREEN)Building WASM adapter with wasm-pack...$(NC)\n"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ docker compose up
117117
| --- | --- | --- |
118118
| **SPMC Ring** | Bounded stream with independent consumers | Sensor telemetry, event logs |
119119
| **SingleLatest** | Only the current value matters | Feature flags, config, UI state |
120-
| **Mailbox** | Latest instruction wins | Device commands, actuation, RPC |
120+
| [**Mailbox**](https://github.com/aimdb-dev/aimdb/tree/main/examples/hello-mailbox) | Latest instruction wins | Device commands, actuation, RPC |
121121

122122
- **Capabilities are unlocked by traits.** Implement `Streamable` to cross WASM/WebSocket/CLI boundaries, `Migratable` for typed schema evolution, `Observable` for monitoring, `Linkable` for wire-format connectors. Without the trait, the type system says no.
123123
- **Connectors that ship today:** MQTT, KNX, WebSocket. Writing your own is one trait impl.

examples/hello-mailbox/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "hello-mailbox"
3+
version.workspace = true
4+
edition.workspace = true
5+
license.workspace = true
6+
description = "AimDB minimal example demonstrating Mailbox buffer (latest-wins) semantics"
7+
publish = false
8+
9+
[dependencies]
10+
aimdb-core = { path = "../../aimdb-core", features = ["std"] }
11+
aimdb-tokio-adapter = { path = "../../aimdb-tokio-adapter", features = ["tokio-runtime"] }
12+
aimdb-sync = { path = "../../aimdb-sync" }
13+
tokio = { workspace = true, features = ["full"] }

examples/hello-mailbox/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# hello-mailbox: Mailbox buffer demo
2+
The Mailbox buffer keeps only the last message written. It's like a real mailbox where only the most recent letter is visible.
3+
4+
## When to use
5+
This Mailbox buffer demo is useful in a variety of scenarios where you want to retain only the last message, for example:
6+
- When you have a robotic arm that needs to execute a sequence of commands, and you only want to execute the last command, or even if the robot gets too much commands in a short period of time.
7+
8+
## How it works
9+
The Mailbox buffer demo works by simulating a mailbox buffer that retains only the last message.
10+
it runs 2 rounds:
11+
- the first round sends 3 Colors and the MailBox only gets the last message.
12+
- the second round sends 2 Colors and the MailBox only gets the last message.
13+
14+
## How to run
15+
From the workspace root, run:
16+
```
17+
cargo run -p hello-mailbox
18+
```
19+
**Expected output**
20+
```
21+
=== hello-mailbox: Mailbox buffer demo ===
22+
23+
Round 1
24+
1. Firing three rapid commands BEFORE consumer exists: Red → Green → Blue
25+
2. Consumer created AFTER the burst — reads once:
26+
✓ Got: Blue ← only the latest survived
27+
(Red and Green were overwritten before anyone could read them)
28+
29+
Round 2
30+
1. Firing two rapid commands BEFORE consumer exists: Red → Green
31+
2. Consumer created AFTER the burst — reads once:
32+
✓ Got: Green ← only the latest survived (Green)
33+
3. Shutting down...
34+
✓ Done.
35+
```

examples/hello-mailbox/src/main.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use aimdb_core::{buffer::BufferCfg, AimDbBuilder};
2+
use aimdb_sync::AimDbBuilderSyncExt;
3+
use aimdb_tokio_adapter::{TokioAdapter, TokioRecordRegistrarExt};
4+
use std::sync::Arc;
5+
use std::thread;
6+
use std::time::Duration;
7+
8+
// Enum of colors for the LED
9+
#[derive(Debug, Clone, PartialEq, Eq)]
10+
enum Color {
11+
Red,
12+
Green,
13+
Blue,
14+
}
15+
16+
// Struct representing the LED state
17+
#[derive(Debug, Clone, PartialEq, Eq)]
18+
struct Led {
19+
color: Color,
20+
}
21+
22+
// Main function
23+
fn main() -> Result<(), Box<dyn std::error::Error>> {
24+
println!("=== hello-mailbox: Mailbox buffer demo ===\n");
25+
26+
// configuration
27+
let adapter = Arc::new(TokioAdapter);
28+
let mut builder = AimDbBuilder::new().runtime(adapter);
29+
30+
builder.configure::<Led>("actuator.led", |reg| {
31+
reg.buffer(BufferCfg::Mailbox);
32+
});
33+
34+
let handle = builder.attach()?;
35+
let producer = handle.producer::<Led>("actuator.led")?;
36+
37+
{
38+
// Produce quickly BEFORE creating the consumer
39+
println!(" Round 1 ");
40+
println!("1. Firing three rapid commands BEFORE consumer exists: Red → Green → Blue");
41+
producer.set(Led { color: Color::Red })?;
42+
producer.set(Led {
43+
color: Color::Green,
44+
})?;
45+
producer.set(Led { color: Color::Blue })?;
46+
thread::sleep(Duration::from_millis(100));
47+
48+
// Now we create the consumer — it will only see the last value in the Mailbox
49+
println!("2. Consumer created AFTER the burst — reads once:");
50+
let consumer = handle.consumer::<Led>("actuator.led")?;
51+
thread::sleep(Duration::from_millis(100));
52+
53+
match consumer.try_get() {
54+
Ok(msg) => println!(" ✓ Got: {:?} ← only the latest survived", msg.color),
55+
Err(_) => println!(" (mailbox was already empty)"),
56+
}
57+
58+
println!(" (Red and Green were overwritten before anyone could read them)\n");
59+
}
60+
61+
println!(" Round 2 ");
62+
println!("1. Firing two rapid commands BEFORE consumer exists: Red → Green");
63+
// Create the color burst again
64+
producer.set(Led { color: Color::Red })?;
65+
producer.set(Led {
66+
color: Color::Green,
67+
})?;
68+
thread::sleep(Duration::from_millis(100));
69+
70+
println!("2. Consumer created AFTER the burst — reads once:");
71+
let consumer2 = handle.consumer::<Led>("actuator.led")?;
72+
thread::sleep(Duration::from_millis(100));
73+
74+
match consumer2.try_get() {
75+
Ok(msg) => println!(
76+
" ✓ Got: {:?} ← only the latest survived (Green)",
77+
msg.color
78+
),
79+
Err(_) => println!(" (mailbox was already empty)"),
80+
}
81+
82+
println!("3. Shutting down...");
83+
handle.detach()?;
84+
println!(" ✓ Done.");
85+
Ok(())
86+
}

0 commit comments

Comments
 (0)