Crate actor_helper

Crate actor_helper 

Source
Expand description

Minimal, self-contained actor runtime used in this crate.

This module provides a tiny, opinionated actor pattern built on top of tokio, with:

  • A per-actor mailbox (mpsc::Receiver<Action<A>>) of boxed async actions.
  • A Handle<A> you can clone and send across threads to schedule work on the actor’s single-threaded mutable state.
  • Ergonomic macros (act!, act_ok!) to write actor actions inline.
  • Panic capturing and error propagation to callers via anyhow::Result.

The pattern encourages a public API type (“Object”) that holds a Handle<ObjectActor> and a private type (“ObjectActor”) that owns the mutable state and the mailbox Receiver. The actor implements Actor for a simple run loop and is spawned with tokio::spawn.

Example: a simple counter

use anyhow::{anyhow, Result};
use iroh_lan::actor::{Actor, Handle, Action};
use tokio::sync::mpsc;

// Public API type (exposed from your module)
pub struct Counter {
    api: Handle<CounterActor>,
}

impl Counter {
    pub fn new() -> Self {
        // 1) Create channel and api handle
        let (api, rx) = Handle::channel(128);

        // 2) Create the actor with private state and the mailbox
        let actor = CounterActor { value: 0, rx };

        // 3) Spawn the run loop
        tokio::spawn(async move {
            let mut actor = actor;
            let _ = actor.run().await;
        });

        Self { api }
    }

    // Mutating API method
    pub async fn inc(&self, by: i32) -> Result<()> {
        self.api
            // act_ok! wraps the returned value into Ok(..)
            .call(act_ok!(actor => async move {
                actor.value += by;
            }))
            .await
    }

    // Query method returning a value
    pub async fn get(&self) -> Result<i32> {
        self.api
            .call(act_ok!(actor => actor.value))
            .await
    }

    // An example that can fail
    pub async fn set_non_negative(&self, v: i32) -> Result<()> {
        self.api
            .call(act!(actor => async move {
                if v < 0 {
                    Err(anyhow!("negative value"))
                } else {
                    actor.value = v;
                    Ok(())
                }
            }))
            .await
    }
}

// Private actor with its state and mailbox
struct CounterActor {
    value: i32,
    rx: mpsc::Receiver<Action<CounterActor>>,
}

impl Actor for CounterActor {
    async fn run(&mut self) -> Result<()> {
        async move {
            loop {
                tokio::select! {
                    Some(action) = self.rx.recv() => {
                        action(self).await;
                    }
                    Some(your_bytes) = your_reader.recv() => {
                        // do other background work if needed
                    }
                    // ... other background work ...
                }
            }
            Ok(())
        }
    }
}

Notes

  • Handle::call captures the call site location and wraps any panic from the actor action into an anyhow::Error delivered to the caller.
  • Actions must complete reasonably promptly; the actor processes actions sequentially and a long-running action blocks the mailbox.
  • Do not hold references across .await inside actions; prefer moving values or cloning as needed.

Macros§

act
Write an actor action that returns anyhow::Result<T>.
act_ok
Write an actor action that returns a plain T (wrapped as Ok(T)).

Structs§

Handle
A clonable handle to schedule actions onto an actor of type A.

Traits§

Actor
A minimal trait implemented by concrete actor types to run their mailbox.

Functions§

into_actor_fut_ok
Convert a future yielding T into a boxed future yielding anyhow::Result<T>.
into_actor_fut_res
Convert a future yielding anyhow::Result<T> into the standard boxed ActorFut.
into_actor_fut_unit_ok
Convert a unit future (Future<Output = ()>) into a boxed future yielding anyhow::Result<()>.

Type Aliases§

Action
An action scheduled onto an actor.
ActorFut
The boxed future type returned by actor actions.
PreBoxActorFut
The unboxed future type used for actor actions.