| Crates.io | aimdb-executor |
| lib.rs | aimdb-executor |
| version | 0.1.0 |
| created_at | 2025-11-06 22:03:33.961577+00 |
| updated_at | 2025-11-06 22:03:33.961577+00 |
| description | Pure async executor trait definitions for AimDB - runtime-agnostic abstractions |
| homepage | https://aimdb.dev |
| repository | https://github.com/aimdb-dev/aimdb |
| max_upload_size | |
| id | 1920802 |
| size | 23,910 |
Pure async executor trait definitions for AimDB - runtime-agnostic abstractions.
aimdb-executor provides the trait abstractions that enable AimDB to work across different async runtime environments. This crate has zero dependencies and defines only traits, enabling dependency inversion where the core database depends on abstractions rather than concrete implementations.
Key Features:
┌────────────────────────────────────────┐
│ aimdb-executor (traits) │
│ - RuntimeAdapter │
│ - TimeOps │
│ - Logger │
│ - Spawn │
└────────────────────────────────────────┘
△ △
│ │
┌───────┴────┐ ┌────┴──────┐
│ Tokio │ │ Embassy │
│ Adapter │ │ Adapter │
└────────────┘ └───────────┘
Platform identification and metadata:
pub trait RuntimeAdapter: Send + Sync + 'static {
fn runtime_name() -> &'static str
where
Self: Sized;
}
Usage: Identify runtime at compile-time (associated function, not method).
Time operations for async contexts:
pub trait TimeOps: RuntimeAdapter {
type Instant: Clone + Send + Sync + core::fmt::Debug + 'static;
type Duration: Clone + Send + Sync + core::fmt::Debug + 'static;
fn now(&self) -> Self::Instant;
fn duration_since(&self, later: Self::Instant, earlier: Self::Instant)
-> Option<Self::Duration>;
fn millis(&self, ms: u64) -> Self::Duration;
fn secs(&self, secs: u64) -> Self::Duration;
fn micros(&self, micros: u64) -> Self::Duration;
fn sleep(&self, duration: Self::Duration) -> impl Future<Output = ()> + Send;
}
Usage: Generic time operations with platform-specific Instant/Duration types.
Structured logging abstraction:
pub trait Logger: RuntimeAdapter {
fn info(&self, message: &str);
fn debug(&self, message: &str);
fn warn(&self, message: &str);
fn error(&self, message: &str);
}
Usage: Logging that works across tracing (std) and defmt (embedded).
Task spawning with platform-specific tokens:
pub trait Spawn: RuntimeAdapter {
type SpawnToken: Send + 'static;
fn spawn<F>(&self, future: F) -> ExecutorResult<Self::SpawnToken>
where
F: Future<Output = ()> + Send + 'static;
}
Usage: Spawn async tasks with runtime-appropriate tokens (JoinHandle, SpawnToken, etc.).
use aimdb_executor::{RuntimeAdapter, TimeOps, Logger, Spawn, ExecutorResult};
use core::future::Future;
pub struct MyAdapter;
impl RuntimeAdapter for MyAdapter {
fn runtime_name() -> &'static str
where
Self: Sized,
{
"my-runtime"
}
}
impl TimeOps for MyAdapter {
type Instant = my_runtime::Instant;
type Duration = my_runtime::Duration;
fn now(&self) -> Self::Instant {
my_runtime::time::now()
}
fn duration_since(
&self,
later: Self::Instant,
earlier: Self::Instant,
) -> Option<Self::Duration> {
later.checked_duration_since(earlier)
}
fn millis(&self, ms: u64) -> Self::Duration {
my_runtime::Duration::from_millis(ms)
}
fn secs(&self, secs: u64) -> Self::Duration {
my_runtime::Duration::from_secs(secs)
}
fn micros(&self, micros: u64) -> Self::Duration {
my_runtime::Duration::from_micros(micros)
}
fn sleep(&self, duration: Self::Duration) -> impl Future<Output = ()> + Send {
my_runtime::time::sleep(duration)
}
}
impl Logger for MyAdapter {
fn info(&self, message: &str) {
my_runtime::log::info!("{}", message);
}
fn debug(&self, message: &str) {
my_runtime::log::debug!("{}", message);
}
fn warn(&self, message: &str) {
my_runtime::log::warn!("{}", message);
}
fn error(&self, message: &str) {
my_runtime::log::error!("{}", message);
}
}
impl Spawn for MyAdapter {
type SpawnToken = my_runtime::TaskHandle;
fn spawn<F>(&self, future: F) -> ExecutorResult<Self::SpawnToken>
where
F: Future<Output = ()> + Send + 'static,
{
my_runtime::spawn(future)
.map_err(|e| ExecutorError::SpawnFailed {
message: e.to_string()
})
}
}
Simple error enum for executor operations:
pub enum ExecutorError {
SpawnFailed { message: String }, // or &'static str in no_std
RuntimeUnavailable { message: String },
TaskJoinFailed { message: String },
}
pub type ExecutorResult<T> = Result<T, ExecutorError>;
All traits are directly usable - no trait_variant macros used. All traits require Send + Sync bounds where appropriate.
The core database is generic over runtime traits:
pub struct Database<A: RuntimeAdapter + TimeOps + Logger + Spawn> {
adapter: A,
// ... fields ...
}
impl<A> Database<A>
where
A: RuntimeAdapter + TimeOps + Logger + Spawn,
{
pub fn new(adapter: A) -> Self {
// Use adapter traits
adapter.info("Database initialized");
let now = adapter.now();
// ...
}
}
A convenience trait that bundles all requirements:
pub trait Runtime: RuntimeAdapter + TimeOps + Logger + Spawn {
fn runtime_info(&self) -> RuntimeInfo {
RuntimeInfo { name: Self::runtime_name() }
}
}
// Auto-implemented for any type with all four traits
impl<T> Runtime for T where T: RuntimeAdapter + TimeOps + Logger + Spawn {}
Two official adapters are available:
[dependencies]
aimdb-tokio-adapter = "0.1"
tokio::time, tokio::task, tracing[dependencies]
aimdb-embassy-adapter = "0.1"
embassy_time, embassy_executor, defmt[features]
std = [] # Enable standard library support
# Run tests
cargo test -p aimdb-executor
# Check no_std compatibility
cargo check -p aimdb-executor --no-default-features
Generate API docs:
cargo doc -p aimdb-executor --open
See adapter implementations:
aimdb-tokio-adapter/src/lib.rs - Full Tokio implementationaimdb-embassy-adapter/src/lib.rs - Full Embassy implementationSee LICENSE file.