Expand description
Agnostic-Lite
agnostic-lite is an agnostic abstraction layer for any async runtime.
In order to make it trivial for others to build implementations of any async runtime, this crate provides an abstraction layer implementation.
In addition, the abstraction layer itself is no_std and alloc-free, so the traits can be used in environments where alloc is not available. It also has no unsafe code. Concrete runtime backends have their own requirements: tokio, smol, and wasm require std, while the embassy backend is no_std but requires alloc.
§Introduction
agnostic-lite is a lightweight, no_std-compatible, allocation-free abstraction layer for async runtimes. It provides the essential async primitives you need to write runtime-agnostic code that works in any environment - from standard applications to embedded systems.
§Key Features
no_stdCompatible: Works without the standard library- Allocation-Free: No heap allocations required
- No Unsafe Code:
#![forbid(unsafe_code)]ensures memory safety - Modular Traits: Small, focused traits instead of one monolithic Runtime trait
- Zero-Cost: Compiles to runtime-specific code
- WASM Support: Works in WebAssembly environments
§Core Traits
agnostic-lite provides focused traits for specific async operations:
AsyncSpawner: Spawn tasks globallyAsyncLocalSpawner: Spawn thread-local tasksAsyncSleep: Sleep for a durationAsyncInterval: Create periodic intervalsAsyncTimeout: Apply timeouts to operationsLocalRuntimeLite: The thread-pinned runtime core — construction,block_on, local/blocking spawning, and the!Send-tolerant time familyRuntimeLite: TheSendextension ofLocalRuntimeLite— multithread spawning and theSendtime family (bounds on it reach every core item too)Yielder: Yield control back to the runtime
§Supported Runtimes
- tokio - Enable with
features = ["tokio"](requiresstd) - smol - Enable with
features = ["smol"](requiresstd) - wasm-bindgen-futures - Enable with
features = ["wasm"](requiresstd) - embassy - Enable with
features = ["embassy"]; theno_stdruntime for embedded targets (requiresalloc)
§Why agnostic-lite?
Choose agnostic-lite over agnostic when:
- ✅ You need
no_stdsupport for embedded systems - ✅ You want minimal dependencies and compile times
- ✅ You only need basic async primitives (spawning, time)
- ✅ You’re building a library and want minimal footprint
- ✅ You need guaranteed memory safety (no unsafe code)
Choose agnostic when:
- You need networking, DNS, or process management
- You’re building standard applications with
std - You want a batteries-included experience
§Installation
[dependencies]
agnostic-lite = "0.7"§Runtime Selection
Choose one runtime feature:
# With tokio
agnostic-lite = { version = "0.7", features = ["tokio"] }
# With smol
agnostic-lite = { version = "0.7", features = ["smol"] }
# With WASM
agnostic-lite = { version = "0.7", features = ["wasm"] }§no_std Usage
The tokio, smol, and wasm runtimes all pull in std. For a real no_std runtime, use the
embassy backend, which targets embassy-executor and only requires alloc:
# no_std (with alloc), for embedded targets running on embassy-executor
agnostic-lite = { version = "0.7", default-features = false, features = ["embassy"] }The embassy backend has caveats (a one-time spawner init, a bounded task pool, a busy-polling
block_on, and panicking spawn_blocking/local spawning) — see the embassy module docs.
§Feature Flags
§Core Features
std(default): Standard library supportalloc: Allocation support (without std)time: Time-related traits and types
§Runtime Features (choose one)
tokio: Tokio runtime implementations (requiresstd)async-io: async-io backend (used by smol, requiresstd)smol: Smol runtime implementations (requiresstd)wasm: WebAssembly support via wasm-bindgen-futures (requiresstd)embassy:no_stdruntime for embedded targets via embassy-executor (requiresalloc)
§Trait Reference
The signatures below are simplified sketches for orientation; see docs.rs for the authoritative definitions.
§AsyncSpawner
pub trait AsyncSpawner: Yielder + Copy + Send + Sync + 'static {
type JoinHandle<O>: JoinHandle<O> + Send + Sync + 'static
where
O: Send + 'static;
fn spawn<F>(future: F) -> Self::JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static;
}§AsyncLocalSpawner
pub trait AsyncLocalSpawner: Yielder + Copy + 'static {
type JoinHandle<O>: LocalJoinHandle<O> + 'static
where
O: 'static;
fn spawn_local<F>(future: F) -> Self::JoinHandle<F::Output>
where
F: Future + 'static,
F::Output: 'static;
}§AsyncSleep
pub trait AsyncSleep: Future<Output = Self::Instant> + Send {
type Instant: Instant;
fn reset(self: Pin<&mut Self>, deadline: Self::Instant);
}§AsyncInterval
pub trait AsyncInterval: Stream<Item = Self::Instant> + Send + Unpin {
type Instant: Instant;
fn reset(&mut self, interval: Duration);
fn reset_at(&mut self, instant: Self::Instant);
fn poll_tick(&mut self, cx: &mut Context<'_>) -> Poll<Self::Instant>;
}§AsyncTimeout
pub trait AsyncTimeout<F>: Future<Output = Result<F::Output, Elapsed>> + Send
where
F: Future + Send,
{
type Instant: Instant;
fn timeout(timeout: Duration, fut: F) -> Self;
fn timeout_at(deadline: Self::Instant, fut: F) -> Self;
}§LocalRuntimeLite and RuntimeLite
Since 0.7 the runtime abstraction is two traits. LocalRuntimeLite is the
thread-pinned core — everything a consumer needs to host futures on the
current thread — and RuntimeLite is its Send extension. A thread-pinned
host (a LocalSet-shaped executor, or any runtime whose timers are
deliberately !Send) can implement the core alone; tokio/smol/wasm/embassy
implement both. Completion-based (proactor) runtimes such as compio are
deliberately out of scope: their I/O model warrants a native driver
integration of its own, not this reactor-shaped abstraction wrapped around
it. This is a trimmed sketch:
pub trait LocalRuntimeLite: Sized + Unpin + Copy + Send + Sync + 'static {
type LocalSpawner: AsyncLocalSpawner;
type BlockingSpawner: AsyncBlockingSpawner;
// with the `time` feature: Instant, LocalSleep, LocalInterval, LocalTimeout, LocalDelay
fn new() -> Self;
fn block_on<F: Future>(f: F) -> F::Output;
// ... plus spawn_local / spawn_blocking / sleep_local / timeout_local and more
}
pub trait RuntimeLite: LocalRuntimeLite {
type Spawner: AsyncSpawner;
// with the `time` feature: AfterSpawner, Sleep, Interval, Timeout, Delay
fn spawn<F>(future: F) -> <Self::Spawner as AsyncSpawner>::JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static;
// ... plus sleep / timeout / interval / spawn_after and more
}Generic R: RuntimeLite bounds reach every core item through the supertrait
unchanged. Concrete-type calls of moved members (SmolRuntime::block_on(..))
need LocalRuntimeLite in scope, and UFCS calls must name the owning trait.
§Conditional Compilation Helpers
agnostic-lite provides macros for conditional compilation:
use agnostic_lite::{cfg_tokio, cfg_smol};
cfg_tokio! {
// This code only compiles when tokio feature is enabled
use tokio::task;
}
cfg_smol! {
// This code only compiles when smol feature is enabled
use smol::Task;
}§Performance
agnostic-lite has zero runtime overhead. All trait methods are inlined and compile to the same code as using the runtime directly:
- No allocations: Works without heap allocations
- No dynamic dispatch: All trait calls are statically resolved
- Zero-cost abstractions: Compiles to identical assembly as direct runtime usage
§License
agnostic-lite is under the terms of both the MIT license and the
Apache License (Version 2.0).
See LICENSE-APACHE, LICENSE-MIT for details.
Copyright (c) 2025 Al Liu.
Modules§
- async_
io async-io - Time related traits concrete implementations for runtime based on
async-io, e.g.smol. - embassy
embassy - Concrete runtime implementations based on the
embassy-executorruntime. - smol
smol - Concrete runtime implementations based on
smolruntime. - tests
timeand (testortest) - Unit test for the
RuntimeLite - time
time - Time related traits
- tokio
tokio - Concrete runtime implementations based on
tokioruntime. - wasm
wasm - Concrete runtime implementations based on
wasm-bindgen-futures.
Macros§
- cfg_
linux - Macro to conditionally compile items for
linuxsystem - cfg_
smol - Macro to conditionally compile items for
smolfeature - cfg_
tokio - Macro to conditionally compile items for
tokiofeature - cfg_
unix - Macro to conditionally compile items for
unixsystem - cfg_
windows - Macro to conditionally compile items for
windowssystem
Enums§
- After
Handle Error time - Error of
AfterHandle’s output
Traits§
- After
Handle time - The handle returned by the
AsyncAfterSpawnerwhen a after future is spawned. - Async
After Spawner time - A spawner trait for spawning futures. Go’s
time.AfterFuncequivalent. - Async
Blocking Spawner - A spawner trait for spawning blocking.
- Async
Local Spawner - A spawner trait for spawning futures.
- Async
Spawner - A spawner trait for spawning futures.
- Join
Handle - Joinhanlde trait
- Local
Join Handle - Joinhanlde trait
- Local
Runtime Lite - The thread-pinned half of a runtime: construction,
block_on, local and blocking spawning, and the!Send-tolerant time family. - Runtime
Lite - Runtime trait: the
Sendextension ofLocalRuntimeLite. - Yielder
- Yielder hints the runtime to execution back