simple-actor 0.2.0

Provides an Actor type that wraps a state and allows mutating it in turns using an invoke function.
Documentation

simple-actor

Provides an Actor type that wraps a state and allows mutating it in turns using invoke and invoke_async.

Example

It is recommended to create a wrapper type around the Actor, and implement async functions that use invoke/invoke_async to interact with the inner private state.

use std::time::Duration;
use simple_actor::Actor;
use futures::FutureExt;

#[derive(Clone)]
pub struct Adder(Actor<u32>);

impl Adder {
    pub fn new(initial_value: u32) -> Self {
        let (actor, driver) = Actor::new(initial_value);
        tokio::spawn(driver);
        Self(actor)
    }

    pub async fn add(&self, x: u32) {
        let _ = self.0.invoke(move |state| {
            // We can update the state.
            *state += x
        }).await;
    }

    pub async fn add_twice_with_delay(&self, x: u32) -> Option<u32> {
        self.0
            .invoke_async(move |state| {
                async move {
                    *state += x;
                    // We can .await while holding the state.
                    tokio::time::sleep(Duration::from_millis(500)).await;

                    *state += x;
                    // We can return a value at the end.
                    *state
                }
                .boxed()
            })
            .await
    }

    pub async fn result(&self) -> Option<u32> {
        self.0.invoke(move |state| *state).await
    }

    pub fn shutdown(&self) {
        self.0.shutdown()
    }
}

#[tokio::main]
async fn main() {
    let adder = Adder::new(5);

    adder.add(3).await;
    assert_eq!(adder.result().await, Some(8));

    adder.add(2).await;
    assert_eq!(adder.result().await, Some(10));

    assert_eq!(adder.add_twice_with_delay(3).await, Some(16));
    assert_eq!(adder.result().await, Some(16));

    adder.shutdown();
    assert_eq!(adder.result().await, None);
}

Inspiration

This crate is inspired by ghost_actor, with a simpler implementation and API.

This crate [invoke] function returns None if the actor is down, which avoids dealing with error type conversions.

It also allows to hold the state in [invoke_async] and thus use async-based state.