An actors library for Rust and Tokio designed to work with async / await message handlers out of the box.

Overview

Akt

An actors framework for Rust and Tokio.

It is heavily inspired by Actix and right now it has very similar look and feel. The main difference is that in Actix (at least at the moment of this particular library creation) working with async / await and async handlers in particular is a little cumbersome. This library supports async handlers out of the box and even provide tools to simplify some unusual kinds of communications like waiting for result without even blocking the main message loop.

docs.rs Crates.io

Status

This library is on the very early stage of development. It means that:

  • You may face significant amount of bugs
  • API could be incompatibly changed any moment
  • Test coverage is not complete

However it is already used in production so you may give it a try in your project too.

Overview

Let's implement some actor to manage bank account.

use mpi_actors::{Actor, Context, Handler, Message};
use async_trait::async_trait;
use thiserror::Error;

// A state managed by our actor
struct Account {
    balance: u32,
}

// Implementing Actor trait makes an actor out of the state
impl Actor for Account {}

// Define messages to be handled by the actor

struct Deposit {
    pub amount: u32,
}

impl Message for Deposit {
  // Result the actor will respond with
    type Result = u32;
}

// Implement handler for the Deposit message and Account actor
// We need to use `async_trait` crate "magic" because async trait methods
// is not supported bu rust directly yet.
#[async_trait]
impl Handler<Deposit> for Account {
    async fn handle(&mut self, message: Deposit, _context: &mut Context<Account>) -> u32 {
        self.balance = self.balance + message.amount;

        self.balance
    }
}

struct Withdraw {
  pub amount: u32,
}

// Withdrawal may fail so we could provide specific error for it.
//
// It could be a struct, but for backwards compatibility reasons it could
// be a good idea to make enum even if for now we have only one variant.
//
// Here we use `thiserror` crate for convenient Error
// derivation, but it is completely optional.
#[derive(Debug, Error, PartialEq)]
enum WithdrawalError {
    #[error("Insufficient funds. {requested} was requested but only {available} is available.")]
    InsufficientFunds { requested: u32, available: u32 },
}

impl Message for Withdraw {
    type Result = Result<u32, WithdrawalError>;
}

#[async_trait]
impl Handler<Withdraw> for Account {
    async fn handle(
        &mut self,
        message: Withdraw,
        _context: &mut Context<Account>,
    ) -> Result<u32, WithdrawalError> {
        if self.balance < message.amount {
            return Err(WithdrawalError::InsufficientFunds {
                requested: message.amount,
                available: self.balance,
            });
        }

        self.balance = self.balance - message.amount;

        Ok(self.balance)
    }
}

#[tokio::main]
async fn main() {
   // Create actor
   let actor = Account { balance: 50 };

   // Run actor consuming it and returning its address
   let address = actor.run();

   // Send message and use regular `await` workflow to wait for the response.
   let balance = address.send(Withdraw { amount: 20 }).await;
   assert_eq!(balance, Ok(Ok(30)));

   let balance = address.send(Deposit { amount: 40 }).await;
   assert_eq!(balance, Ok(70));

   let balance = address.send(Withdraw { amount: 100 }).await;
   assert_eq!(
       balance,
       Ok(Err(WithdrawalError::InsufficientFunds {
           requested: 100,
           available: 70
       }))
   );

   // Actors addresses could be safely cloned
   let address_clone = address.clone();
   let balance = address_clone.send(Withdraw { amount: 10 }).await;
   assert_eq!(balance, Ok(Ok(60)));

   let balance = address.send(Withdraw { amount: 10 }).await;
   assert_eq!(balance, Ok(Ok(50)));
}
You might also like...
The utility is designed to check the availability of peers and automatically update them in the Yggdrasil configuration file, as well as using the admin API - addPeer method.

Yggrasil network peers checker / updater The utility is designed to check the availability of peers and automatically update them in the Yggdrasil con

syntax-level async join enabling branching control flow and shared mutable borrow

enjoin enjoin's async join macros operate at the syntax level. It allows you to... break, continue, and return out of async code running in a join for

Stack heap flexible string designed to improve performance for Rust

flexible-string A stack heap flexible string designed to improve performance. FlexibleString was first implemented in spdlog-rs crate, which improved

TodoX is a sophisticated Rust-based application designed to facilitate seamless todo management.

Rust Todo List App is a command-line tool written in Rust that allows users to manage their tasks efficiently. Whether you need to add, mark as done, edit, or clear tasks from your todo list, this app provides essential functionalities to streamline your task management process. Additionally, I have integrated sqlite3 using the rusqlite crate. The database stores the data and will persist indefinitely until you manually delete it.

Portable linked-list allocator designed for baremetal systems

Palloc Portable linked-list allocator for embedded / baremetal systems. Using the crate Include this in the [dependencies] section of Cargo.toml pallo

🎮 game loop + 🐷 coroutine + 🌯 burrito = 🚀🔥 blazingly synchronous async executor for games 🔥🚀
🎮 game loop + 🐷 coroutine + 🌯 burrito = 🚀🔥 blazingly synchronous async executor for games 🔥🚀

🐷 Koryto 🐷 Pronounced like corrito, which is pronounced as if you combined coroutine and burrito, because everyone knows coroutines are burritos in

Code accompanying the 1 Hour Dive into Async live stream.
Code accompanying the 1 Hour Dive into Async live stream.

1 Hour Async This is the code accompanying the 1 Hour Dive into Async live-stream. The slides are here You can watch the recorded event on YouTube Inc

An inline SIMD accelerated hashmap designed for small amount of data.
An inline SIMD accelerated hashmap designed for small amount of data.

Small-Map An inline SIMD accelerated hashmap designed for small amount of data. Usage use small_map::SmallMap; // Don't worry about the 16 here. // Wh

Rust 核心库和标准库的源码级中文翻译,可作为 IDE 工具的智能提示 (Rust core library and standard library translation. can be used as IntelliSense for IDE tools)

Rust 标准库中文版 这是翻译 Rust 库 的地方, 相关源代码来自于 https://github.com/rust-lang/rust。 如果您不会说英语,那么拥有使用中文的文档至关重要,即使您会说英语,使用母语也仍然能让您感到愉快。Rust 标准库是高质量的,不管是新手还是老手,都可以从中

Owner
Artyom Kozhemiakin
Artyom Kozhemiakin
The non-opinionated Rust-based commit message linter.

Documentation | Website git-sumi The non-opinionated Rust-based commit message linter Transform your commit practices with flexible linting for consis

Óscar 6 Mar 1, 2024
Message Signaled Interrupts for RISC-V

RISC-V MSI Test in Rust Testing the new MSIs added by the draft Advanced Interrupt Architecture (AIA) specification. Blog Posts First blog post: 30-Ju

Stephen Marz 5 Jul 5, 2022
JackTheBox allows for client & server modifications to s&box independent of the current gamemode

JackTheBox allows for client & server modifications to s&box independent of the current gamemode (or even in the absence of a gamemode).

dank 5 Sep 27, 2022
fast rust implementation of online nonnegative matrix factorization as laid out in the paper "detect and track latent factors with online nonnegative matrix factorization"

ONMF status: early work in progress. still figuring this out. code still somewhat messy. api still in flux. fast rust implementation of online nonnega

null 2 Apr 10, 2020
The best Intermediate Rust course out there!

Ultimate Rust 2: Intermediate Concepts This is the companion repository for the Ultimate Rust 2: Intermediate Concepts (the followup to the popular Ul

Nathan Stocks 155 Jan 4, 2023
Print out some fibonacci numbers.

give-me-some-fibonacci A Rust library for some fibonacci. TL;DR: its just a joke. Usage To get started using give_me_some_fibonacci, just add this to

Leonardo Vieira 2 Mar 22, 2022
CloudLLM is a Rust library designed to seamlessly bridge applications with remote Language Learning Models (LLMs) across various platforms.

CloudLLM CloudLLM is a Rust library designed to seamlessly bridge applications with remote Language Learning Models (LLMs) across various platforms. W

null 4 Oct 13, 2023
The Fast Vector Similarity Library is designed to provide efficient computation of various similarity measures between vectors.

Fast Vector Similarity Library Introduction The Fast Vector Similarity Library is designed to provide efficient computation of various similarity meas

Jeff Emanuel 243 Sep 6, 2023
A set of Zero Knowledge modules, written in Rust and designed to be used in other system programming environments.

Zerokit A set of Zero Knowledge modules, written in Rust and designed to be used in other system programming environments. Initial scope Focus on RLN

vac 44 Dec 27, 2022
Mote is a systems-programming language designed to be practical, performant, and simple.

Mote NOTE: this following lists the goals for what Mote is supposed to be. It does not promise that any of the features here will be accomplished or a

The Mote Programming Language 14 Jul 28, 2021