aetherflow 0.1.0

A high-performance, thread-per-core actor runtime for Rust. Messages move with zero-copy ownership, mailboxes are lock-free, and isolation is proven at compile time — so the hot path has no locks, no GC, and no atomic refcounts. Flow at the speed of hardware.
Documentation
  • Coverage
  • 73.81%
    31 out of 42 items documented1 out of 10 items with examples
  • Size
  • Source code size: 114.34 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.04 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 4s Average build duration of successful builds.
  • all releases: 4s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • org-408/aetherflow
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • mash180sx

AetherFlow

Flow at the speed of hardware.

A high-performance actor runtime for Rust — thread-per-core, lock-free, zero-copy. The type system proves isolation at compile time, which unlocks optimizations other runtimes can't safely make.

CI crates.io docs.rs license

Docs · Why AetherFlow? · Benchmarks


AetherFlow is not a Tokio replacement. It's a different lineage: an actor runtime designed from the CPU up — cores, caches, and message ownership are first-class, not afterthoughts.

You write plain typed Rust. When you send a message, its ownership is moved into the runtime — using it afterward doesn't compile (E0382). This is Pony's iso idea recovered in Rust as a moved T: Send, so the runtime routes the message without locks, without GC, and with no per-message Arc/refcount — guarantees, not benchmarks. (Ownership of the message value is transferred; Rust's Send still lets you put explicitly-shared state like Arc<Mutex<_>> inside a message if you choose — see Known limitations.)

  • 🛡️ Isolation, proven at compile time — data-race freedom is a type error, not a runtime convention. Use-after-send doesn't compile (E0382).
  • Thread-per-core, run-to-completion — one OS thread per core, actors pinned, no work-stealing, no cross-core migration. Cache locality by construction.
  • 📨 Zero-copy messagessend moves ownership. No clone, no Arc<Mutex>.
  • 🔒 Lock-free mailboxes — bounded MPSC ring, head/tail on separate cache lines to avoid false sharing.
  • 🎯 The whole triple, at once — static data-race-free + zero-GC-pause + no per-message heap alloc, clone, or Arc refcount. (The lock-free mailbox uses atomics like any MPSC — what's absent is per-message refcounting, not all atomics.) Pony proved capabilities but pays GC; other Rust actor frameworks have neither.

Quick start

[dependencies]
aetherflow = "0.1"
use aetherflow::{System, Actor};

// An actor is plain typed Rust: one message type, one handler.
struct OrderBook { bids: u64 }

impl Actor for OrderBook {
    type Message = Order;                 // fixed, `Send` — the sendable `iso`

    fn handle(&mut self, order: Order) {  // &mut self: sole owner, no lock needed
        self.bids += order.qty as u64;
        println!("matched {} @ {}", order.qty, order.price);
    }
}

struct Order { qty: u32, price: u32 }

fn main() {
    let sys = System::with_cores(4);              // 4 cores, 4 pinned threads
    let book = sys.spawn_on(0, OrderBook { bids: 0 });

    let order = Order { qty: 100, price: 42 };
    book.send_blocking(order).unwrap();            // moves `order` into core 0; Err(Closed) if the actor is gone
    // println!("{}", order.qty);                  // ← would NOT compile (E0382)

    sys.shutdown();
}

Heads-up: with_cores(n) defaults to IdleStrategy::BusySpin — lowest latency, but it keeps n cores at ~100% CPU. On a laptop or shared box, use System::with_cores_idle(n, IdleStrategy::backoff()).

Need a reply? ask puts the reply cell on the call stack — no per-call heap allocation (the caller blocks until the actor replies):

let depth: u64 = book.ask(|reply| Query::Depth(reply))?;

Why "the type system unlocks the speed"

Performance mechanisms — batching, per-core pools, emplace — are a treadmill: anyone copies your numbers in one release. Speed alone is not a moat.

The moat is the type system. Because the message value is moved (single-owned at the message boundary, checked at compile time), aggressive optimizations — no per-message atomic refcount, no GC, per-core message reuse — become structurally safe. A runtime without a type system can't copy them safely; it would have to build the type system too (Pony-scale cost).

And you never write a capability annotation. The theory works under the floor; on the surface you write ordinary Rust and the guarantees come free. That's the design principle: deep theory, shallow surface. See design.md §2.4–2.6.

Status & scope

Single-node v1. This is a systems project under active development.

  • ✅ typed actors · move messages · lock-free MPSC mailbox · thread-per-core · core pinning (best-effort) · zero-alloc ask
  • Tail latency validated on real hardware — on AWS Graviton3 (real Linux, native core pinning) the busy-spin tail collapses from milliseconds to ~3–5µs, and AetherFlow wins every percentile vs Tokio (median ~10×, p99 ~13×, p999 ~3–4.5×). Zero-alloc ask runs sub-µs (p50 268ns / p999 399ns). Core pinning is a no-op on macOS (an OS limitation, not ARM). See benchmarks.
  • 🎯 Next: isolated cores (isolcpus/nohz_full, bare metal) to drive p99.9 into single-digit µs — matching-engine / HFT territory.
  • 🧊 Frozen for now: distributed, clustering, persistence, and streams. These are on the roadmap, not the current build. See direction & roadmap.

Not for elite HFT (they build their own or go FPGA). The target is the tier that wants Disruptor-class speed with safety and productivity but has no HFT team: exchanges, brokers, real-time risk, market data, ad RTB, game tick servers.

Known limitations (honest scope for 0.1)

This is a young systems project. The concept and core are solid, but several correctness/robustness items are deliberately not done yet — we'd rather state them than have you discover them:

  • Isolation is at the message boundary, not deep. send moves the message value (use-after-send is E0382), but Rust's Send doesn't forbid explicitly shared internals — a message can still carry Arc<Mutex<_>> if you write it that way. This is ownership transfer, not Pony-iso-strength deep uniqueness.
  • ask liveness depends on the callee replying. If the actor is already gone when you ask, you get Err(AskError::Closed). But the reply cell lives on the caller's stack, so if an actor stores the Responder instead of replying, the caller blocks. Generation-tagged reply slots are on the roadmap.
  • Lock-free queue verification. Concurrent tests plus a Miri UB check on the single-threaded unsafe paths pass today; exhaustive interleaving verification (Loom) is on the roadmap before 1.0.
  • IdleStrategy::BusySpin is the default (100% CPU per core) — use IdleStrategy::backoff() on shared or battery-powered machines.

Documentation

Contributing

AetherFlow is open source and contributions are welcome — bug reports, feature requests, and pull requests alike. See CONTRIBUTING.md.

License

Licensed under either of

at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.