xtra
A tiny, fast, and safe actor framework. It is modelled around Actix (copyright and license here).
Features
- Safe: there is no unsafe code in xtra (there is some necessary in
futures
, but that's par for the course).
- Small and lightweight: it only depends on
futures
by default.
- Asynchronous and synchronous message handlers.
- Simple asynchronous message handling interface which allows
async
/await
syntax. No more ActorFuture
and
laborious combinators - asynchronous responders just return impl Future
, even when borrowing self
.
- Does not depend on its own runtime and can be run with any futures executor (Tokio and
async-std have the
Actor::spawn
convenience method implemented out of the box).
- Quite fast (under Tokio, <170ns time from sending a message to it being processed for sending without waiting for a
result on my development machine with an AMD Ryzen 3 3200G)
Caveats
- The main caveat of this crate is that it uses many unstable features. For example, to get rid of
ActorFuture
,
Generic Associated Types (GATs)
must be used. This is an incomplete and unstable feature, which appears to be a way off from stabilisation.
It also uses impl Trait
Type Aliases to avoid Box
ing the futures
returned from the Handler
trait (the library, however, is not totally alloc-free). This means that it requires
nightly to use, and may be unstable in future as those features evolve. What you get in return for this is a cleaner,
simpler, and more expressive API.
- It is also still very much under development, so it may not be ready for production code.
Example
```rust
![feature(typealiasimpltrait, genericassociated_types)]
use futures::Future;
use xtra::prelude::*;
struct Printer {
times: usize,
}
impl Printer {
fn new() -> Self {
Printer { times: 0 }
}
}
impl Actor for Printer {}
struct Print(String);
impl Message for Print {
type Result = ();
}
// In the real world, the synchronous SyncHandler trait would be better-suited (and is a few ns faster)
impl Handler for Printer {
type Responder<'a> = impl Future