aimdb-core
Core database engine for AimDB - async in-memory storage with data synchronization.
Overview
aimdb-core provides the foundational database engine for AimDB, designed for data synchronization across MCU → edge → cloud environments with low-latency synchronization.
Key Features:
- Type-Safe Records:
TypeId-based routing eliminates string keys and enables compile-time safety - Runtime Agnostic: Works with any async runtime (Tokio, Embassy) via adapter pattern
- Producer-Consumer Model: Built-in typed message passing with multiple buffer strategies
- Pluggable Buffers: SPMC Ring, SingleLatest, and Mailbox for different data flow patterns
- No-std Compatible: Core functionality works without standard library
Architecture
┌─────────────────────────────────────────────────┐
│ Database<A: RuntimeAdapter> │
│ - Unified API for all operations │
│ - Type-safe record management │
│ - Builder pattern configuration │
└─────────────────────────────────────────────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Producers Consumers Connectors
(Async) (Async) (MQTT/Kafka)
Quick Start
Add to your Cargo.toml:
[]
= "0.4"
= "0.4" # or aimdb-embassy-adapter
Basic Usage
use ;
use BufferCfg;
use TokioAdapter;
use Arc;
async
For complete working examples with producers, consumers, and connectors, see:
examples/tokio-mqtt-connector-demo- Full producer/consumer with MQTT publishingexamples/sync-api-demo- Synchronous API usageexamples/remote-access-demo- Remote introspection server
Buffer Types
Choose the right buffer strategy for your use case:
SPMC Ring Buffer
Use for: High-frequency data streams with bounded memory
use BufferCfg;
reg.buffer
- Bounded backlog for multiple consumers
- Fast producers can outrun slow consumers
- Oldest messages dropped on overflow
SingleLatest
Use for: State synchronization, configuration updates
reg.buffer
- Only stores newest value
- Intermediate updates collapsed
- History doesn't matter
Mailbox
Use for: Commands and one-shot events
reg.buffer
- Single-slot with overwrite
- Latest command wins
- At-least-once delivery
Producer-Consumer Patterns
Source (Producer)
Async function that generates and sends data:
async
// Register in builder
reg.buffer
.source;
Tap (Consumer)
Async function that receives and processes data:
async
// Register in builder
reg.tap;
For complete examples, see examples/tokio-mqtt-connector-demo.
Type Safety
Records are identified by TypeId, not strings:
use TypeId;
let type_id = ;
// TypeId automatically used for record lookup
Benefits:
- Compile-time type checking
- No string parsing overhead
- Impossible to mix types
Runtime Adapters
Core depends on abstract traits from aimdb-executor:
- TokioAdapter: Standard library environments
- EmbassyAdapter: Embedded no_std environments
Adapters provide:
- Task spawning (
Spawn) - Time operations (
TimeOps) - Logging (
Logger) - Platform identification (
RuntimeAdapter)
Features
[]
= [] # Standard library support
= ["dep:tracing"] # Structured logging
= [] # Performance metrics
= ["dep:defmt"] # Embedded logging
Error Handling
All operations return DbResult<T> with DbError enum:
use ;
pub async
Common errors:
RecordNotFound: Requested type not registeredProducerFailed/ConsumerFailed: Task execution errorsBufferError: Buffer operations failedConnectorError: External connector issues
Connectors
Integrate with external systems like MQTT, Kafka, or custom protocols:
use MqttConnector;
use Arc;
let mqtt = new;
let mut builder = new
.runtime
.with_connector;
builder.;
let db = builder.build?;
See examples/tokio-mqtt-connector-demo for complete connector integration.
Testing
# Run tests (std)
# Run tests (no_std embedded)
Performance
Design targets:
- < 50ms end-to-end latency
- Lock-free buffer operations
- Zero-copy where possible
- Minimal allocations in hot paths
Documentation
Generate API docs:
License
See LICENSE file.