switchy_async 0.2.0

Switchy Async runtime package
Documentation

MoosicBox Async

Async runtime abstraction and utilities for MoosicBox applications.

Overview

The MoosicBox Async package provides:

  • Runtime Abstraction: Generic async runtime interface
  • Multi-Backend: Support for Tokio and simulation runtimes
  • Builder Pattern: Flexible runtime configuration
  • Feature-Gated: Modular async functionality
  • Thread Management: Thread ID tracking and management

Features

Runtime Abstraction

  • GenericRuntime: Common interface for all async runtimes
  • Runtime Builder: Configurable runtime construction
  • Backend Selection: Choose between Tokio and simulation runtimes
  • Future Support: Standard Future trait integration

Backend Support

  • Tokio: Production async runtime
  • Simulator: Deterministic simulation runtime for testing
  • Feature-Gated: Enable only needed backends

Async Utilities

  • Thread ID: Unique thread identification
  • Task Management: Task spawning and joining
  • IO Operations: Async I/O primitives (feature-gated)
  • Synchronization: Async synchronization primitives (feature-gated)
  • Timers: Async timing utilities (feature-gated)

Installation

Add this to your Cargo.toml:

[dependencies]
switchy_async = "0.1.4"

With Tokio backend features:

[dependencies]
switchy_async = { version = "0.1.4", default-features = false, features = ["tokio", "rt-multi-thread", "io", "sync", "time", "macros"] }

For testing with simulation:

[dependencies]
switchy_async = { version = "0.1.4", default-features = false, features = ["simulator", "macros"] }

Usage

Runtime Creation

use switchy_async::{Builder, GenericRuntime};

// Create runtime with default settings (current-thread)
let runtime = Builder::new().build()?;

// Use generic runtime interface
runtime.block_on(async {
    println!("Hello from async runtime!");
});

// Wait for runtime to complete
runtime.wait()?;

// With multi-threaded runtime (requires rt-multi-thread feature)
#[cfg(feature = "rt-multi-thread")]
{
    let runtime = Builder::new()
        .max_blocking_threads(Some(4))
        .build()?;
    runtime.block_on(async {
        println!("Hello from multi-threaded runtime!");
    });
    runtime.wait()?;
}

Backend-Specific Usage

// Tokio backend (when tokio feature enabled)
#[cfg(all(feature = "tokio", feature = "time", not(feature = "simulator")))]
use switchy_async::{Builder, task, time};

#[cfg(all(feature = "tokio", feature = "time", not(feature = "simulator")))]
{
    let runtime = Builder::new().build()?;

    // Spawn tasks
    runtime.block_on(async {
        let handle = task::spawn(async {
            time::sleep(time::Duration::from_millis(100)).await;
            "Task completed"
        });

        let result = handle.await.expect("task should complete");
        println!("{}", result);
    });

    runtime.wait()?;
}

// Additional modules available with features
#[cfg(feature = "io")]
use switchy_async::io;  // Async I/O traits and utilities

#[cfg(feature = "sync")]
use switchy_async::sync;  // Synchronization primitives

#[cfg(feature = "util")]
use switchy_async::util;  // Additional utilities

Simulation Backend

// Simulation backend (when simulator feature enabled)
#[cfg(feature = "simulator")]
use switchy_async::simulator;

#[cfg(feature = "simulator")]
{
    let runtime = Builder::new().build()?;

    runtime.block_on(async {
        // Deterministic async execution for testing
        println!("Simulation runtime");
    });
}

Thread Management

use switchy_async::thread_id;

// Get unique thread ID
let id = thread_id();
println!("Current thread ID: {}", id);

Macros and Utilities

// Async macros (requires macros feature)
#[cfg(feature = "macros")]
use switchy_async::{select, join, try_join};

#[cfg(feature = "macros")]
{
    // Use select! macro
    select! {
        result1 = async_operation_1() => {
            println!("Operation 1 completed: {:?}", result1);
        }
        result2 = async_operation_2() => {
            println!("Operation 2 completed: {:?}", result2);
        }
    }

    // Use join! macro
    let (result1, result2) = join!(
        async_operation_1(),
        async_operation_2()
    );

    // Use try_join! macro for Results
    let (result1, result2) = try_join!(
        fallible_async_operation_1(),
        fallible_async_operation_2()
    )?;
}

// Yield injection for simulation testing (requires macros feature)
#[cfg(feature = "macros")]
use switchy_async::{inject_yields, inject_yields_mod};

#[cfg(feature = "macros")]
#[inject_yields]
async fn my_async_function() {
    // Function body with automatic yield injection for deterministic testing
}

// Runtime entry-point macros
#[cfg(feature = "macros")]
#[switchy_async::main]
async fn main() {
    println!("Runs with the selected switchy_async backend");
}

#[cfg(feature = "macros")]
#[switchy_async::test]
async fn my_test() {
    assert_eq!(2 + 2, 4);
}

Error Handling

use switchy_async::Error;

// Runtime errors
match runtime.wait() {
    Ok(()) => println!("Runtime completed successfully"),
    Err(Error::IO(io_err)) => println!("I/O error: {}", io_err),
    Err(Error::Join(join_err)) => println!("Join error: {}", join_err),
}

// Task join errors (when using task handles)
use switchy_async::task::JoinError;

let handle = runtime.spawn(async { /* ... */ });
match handle.await {
    Ok(result) => println!("Task completed: {:?}", result),
    Err(e) => println!("Task failed: {}", e),
}

Feature Flags

Backend Selection

  • tokio: Enable Tokio async runtime
  • simulator: Enable simulation runtime for testing

Runtime Features

  • rt-multi-thread: Multi-threaded runtime support
  • fs: File system operations
  • io: Async I/O operations
  • net: Networking support
  • process: Process management
  • sync: Synchronization primitives (includes channels)
  • time: Timing utilities
  • util: Additional utilities
  • macros: Async macros (select!, join!, try_join!, etc.)

Macro Features

  • macros: Enable async macros and yield injection utilities

Runtime Comparison

Tokio Runtime

  • Production: Optimized for production use
  • Performance: High-performance async execution
  • Ecosystem: Full Tokio ecosystem support
  • Threading: Multi-threaded execution

Simulation Runtime

  • Testing: Deterministic execution for tests
  • Reproducible: Consistent behavior across runs
  • Debugging: Easier debugging and tracing
  • Controlled: Precise control over execution order

Dependencies

Core dependencies:

  • thiserror: Error handling
  • pin-project-lite: Pin projection utilities
  • scoped-tls: Scoped thread-local storage
  • log: Logging facade

Feature-gated dependencies:

  • futures: Core Future trait and utilities (enabled with backend features)
  • tokio: Tokio async runtime (optional, enabled with tokio feature)
  • tokio-util: Additional Tokio utilities (optional, enabled with tokio or util features)
  • flume: MPSC/MPMC channel implementation (optional, enabled with sync feature)
  • switchy_async_macros: Macro utilities (optional, enabled with macros feature)
  • switchy_random: Random number generation for simulator (optional, enabled with simulator feature)
  • switchy_time: Time utilities for simulator (optional, enabled with simulator feature)

Integration

This package is designed for:

  • Application Runtime: Main async runtime for applications
  • Testing: Deterministic async testing with simulation
  • Library Development: Runtime-agnostic async libraries
  • Performance: High-performance async applications
  • Cross-Platform: Consistent async behavior across platforms