aimdb-executor 0.1.0

Pure async executor trait definitions for AimDB - runtime-agnostic abstractions
Documentation
# aimdb-executor

Pure async executor trait definitions for AimDB - runtime-agnostic abstractions.

## Overview

`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:**
- **Runtime Agnostic**: No concrete runtime dependencies
- **Simple Trait Structure**: 4 focused traits covering all runtime needs
- **Platform Flexible**: Works across std and no_std environments
- **Zero Dependencies**: Pure trait definitions with minimal coupling

## Architecture

```
┌────────────────────────────────────────┐
│         aimdb-executor (traits)        │
│  - RuntimeAdapter                      │
│  - TimeOps                             │
│  - Logger                              │
│  - Spawn                               │
└────────────────────────────────────────┘
            △                △
            │                │
    ┌───────┴────┐      ┌────┴──────┐
    │  Tokio     │      │  Embassy  │
    │  Adapter   │      │  Adapter  │
    └────────────┘      └───────────┘
```

## Trait Overview

### 1. RuntimeAdapter

Platform identification and metadata:

```rust
pub trait RuntimeAdapter: Send + Sync + 'static {
    fn runtime_name() -> &'static str
    where
        Self: Sized;
}
```

**Usage:** Identify runtime at compile-time (associated function, not method).

### 2. TimeOps

Time operations for async contexts:

```rust
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.

### 3. Logger

Structured logging abstraction:

```rust
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).

### 4. Spawn

Task spawning with platform-specific tokens:

```rust
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.).

## Quick Start

### Implementing an Adapter

```rust
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()
            })
    }
}
```

## Error Types

Simple error enum for executor operations:

```rust
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>;
```

## Trait Variants

All traits are directly usable - **no trait_variant macros used**. All traits require `Send + Sync` bounds where appropriate.

## Usage in AimDB Core

The core database is generic over runtime traits:

```rust
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();
        // ...
    }
}
```

## Runtime Trait Bundle

A convenience trait that bundles all requirements:

```rust
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 {}
```

## Existing Implementations

Two official adapters are available:

### Tokio Adapter
```toml
[dependencies]
aimdb-tokio-adapter = "0.1"
```
- Standard library environments
- Uses `tokio::time`, `tokio::task`, `tracing`

### Embassy Adapter
```toml
[dependencies]
aimdb-embassy-adapter = "0.1"
```
- Embedded no_std environments
- Uses `embassy_time`, `embassy_executor`, `defmt`

## Design Philosophy

1. **Minimal Surface Area**: Only essential operations
2. **No Concrete Dependencies**: Pure trait definitions
3. **Platform Neutral**: Works across std and no_std
4. **Future Proof**: Easy to extend without breaking changes

## Features

```toml
[features]
std = []  # Enable standard library support
```

## Testing

```bash
# Run tests
cargo test -p aimdb-executor

# Check no_std compatibility
cargo check -p aimdb-executor --no-default-features
```

## Documentation

Generate API docs:
```bash
cargo doc -p aimdb-executor --open
```

## Examples

See adapter implementations:
- `aimdb-tokio-adapter/src/lib.rs` - Full Tokio implementation
- `aimdb-embassy-adapter/src/lib.rs` - Full Embassy implementation

## License

See [LICENSE](../LICENSE) file.