Messages. Convenient asynchronous communication

Status: CI

Project info: Docs.rs Latest Version License Rust 1.50+ required

Description

messages is a runtime-agnostic actor library.

It is heavily inspired by actix, a great actor framework.

This crate can be used with any runtime, whether it popular or not. However, for the biggest one (tokio and async-std) there is an optional built-in support enabling more convenient interface (such as an automatic actor spawning).

Key features

Which library should I choose?

actix is a great, thoughtful, polished, and optimized library. If it is possible for you, you should consider it as the main option.

However, if any of statements below apply to your use case, messages may be better:

But what about xactor?

xactor is another good library inspired by Actix. It initially was built for async-std but then gained tokio support.

Nonetheless, this library is not runtime-agnostic. It supports async-std and tokio v1, but is not (yet) compatible with another runtimes.

That being said, messages initially serves different purpose: provide a way to implement actor workflow without having to think about supported runtimes.

Asyncness

This library is async-first, meaning that everything is made with respect to asynchronous architecture. While in some cases synchronous interfaces could've been more performant, it'd make the interface much more bloated. If synchronous actor interface is preferred, consider using actix, as it provides one.

Performance

TL;DR: This library provides performance slightly worse that either actix (for asynchronous message handling) and raw channels, but not much.

More details are presented in the BENCHES.md.

Note: messages treats async and multi-threaded context as its main environment, thus it may be less suitable (or, more precisely, less efficient) for the partially sync context.

Examples

With runtime features

```rust use messages::prelude::*;

struct Example; // Most of the types can be an actor.

// While Actor implementation can be customized, it is not required.

[async_trait]

impl Actor for Example {}

// Message handler that calculated sum of two numbers.

[async_trait]

impl Handler<(u8, u8)> for Example { type Result = u16; async fn handle(&mut self, (a, b): (u8, u8), context: &Context) -> u16 { (a as u16) + (b as u16) } }

// Notification handler that calculated just writes received number to stdout.

[async_trait]

impl Notifiable for Example { async fn notify(&mut self, input: u8, context: &Context) { println!("Received number {}", input); } }

[tokio::main]

async fn main() { let mut addr = Example.spawn(); let result = addr.send((22, 20)).await.unwrap(); asserteq!(result, 42); addr.notify(42).await.unwrap(); addr.stop().await; addr.waitfor_stop().await;
} ```

Without runtime features

```rust use messages::prelude::*;

struct Ping;

[async_trait]

impl Actor for Ping {}

[async_trait]

impl Handler for Ping { type Result = u8; async fn handle(&mut self, input: u8, context: &Context) -> u8 { input } }

[tokio::main]

async fn main() { let context = Context::new(); let mut addr = context.address(); let actor = Ping; // Could've been any other runtime. let mut taskhandle = tokio::spawn(context.run(actor)); let result = addr.send(42).await.unwrap(); asserteq!(result, 42); addr.stop().await; addr.waitforstop().await; task_handle.await.unwrap(); } ```

More

More examples can be found in the examples directory.

List of currently provided examples:

Contributing

All kinds of contributions are really appreciated!

License

messages library is licensed under the MIT License. See LICENSE for details.