9 releases

0.2.7 Mar 28, 2024
0.2.6 Mar 17, 2024
0.1.1 Mar 11, 2024

#200 in Asynchronous

Download history 593/week @ 2024-03-11 125/week @ 2024-03-18 121/week @ 2024-03-25 24/week @ 2024-04-01

863 downloads per month

MIT/Apache

39KB
669 lines

simpl_actor

simpl_actor is a Rust library for simplifying actor-based concurrency in Rust applications. It is built on top of Tokio, utilizing async/await and tokio mpsc channels for efficient and intuitive actor system implementation.

Features

  • Simple Actor Definition: Easily define actors with Rust structs and an attribute macro.
  • Automatic Message Handling: Implement message handling with minimal code, leveraging Rust's type system and async capabilities.
  • Asynchronous and Synchronous Messaging: Support for both asynchronous and synchronous message processing, allowing for flexible actor interaction patterns.
  • Lifecycle Management: Lifecycle hooks for initializing, restarting, and stopping actors, providing control over the actor lifecycle.

Quick Start

Define an actor:

use simpl_actor::{actor, Actor, Spawn};

#[derive(Actor)]
pub struct CounterActor {
    count: i64,
}

#[actor]
impl CounterActor {
    pub fn new() -> Self {
        CounterActor { count: 0 }
    }

    #[message]
    pub fn inc(&mut self, amount: i64) { ... }

    #[message]
    pub fn dec(&mut self, amount: i64) { ... }

    #[message(infallible)]
    pub fn count(&self) -> i64 { ... }
}

Interact with the actor:

let counter = CounterActor::new();
let actor = counter.spawn();

actor.inc(2).await?;
actor.dec(1).await?;
let count = actor.count().await?;

Messaging Variants

When you define a message in simpl_actor, two variants of the message handling function are automatically for syncronous and asyncronous processing:

#[actor]
impl MyActor {
    #[message]
    fn msg(&self) -> Result<i32, Err> {}
}

// Generates
impl MyActorRef {
    /// Sends the messages, waits for processing, and returns a response.
    async fn msg(&self) -> Result<i32, SendError>;
    /// Sends the message after a delay.
    fn msg_after(&self, delay: Duration) -> JoinHandle<Result<Result<i32, Err>, SendError>>;
    /// Sends the message asynchronously, not waiting for a response.
    fn msg_async(&self) -> Result<(), SendError>;
    /// Sends the message asynchronously after a delay.
    fn msg_async_after(&self, delay: Duration) -> JoinHandle<Result<(), SendError>>;
}

The _after and _async variants are only generated if the method does not have any lifetimes.

In other words, all parameters must be owned or &'static for the async variant to be generated, otherwise the actor might reference deallocated memory causing UB.

Contributing

Contributions are welcome! Feel free to submit pull requests, create issues, or suggest improvements.

License

simpl_actor is dual-licensed under either:

at your option.

This means you can choose the license that best suits your project's needs.

Dependencies

~3.5–5MB
~88K SLoC