Expand description
§Act.rs
X | Twitch | Youtube | Mastodon | GitHub | GitHub Sponsors
Act.rs is a minimal actor framework.
§What Is An Actor?
An actor is an object that runs in its own thread or task. You would usually communicate with it via channels.
§Async Actors
You can also create task based actors:
For Tokio functionality go to act_rs_tokio.
For smol functionality go to act_rs_smol.
§A Basic Example
//Adapted from the std TwoPlusTwoActorState ThreadActor test.
//use crate::ActorState;
use act_rs::ActorState;
use std::sync::mpsc::{Sender, channel};
//use super::*;
use act_rs::std::ThreadActor;
struct TwoPlusTwoActorState
{
number: u32,
client_sender: Sender<String>
}
impl TwoPlusTwoActorState
{
pub fn new(client_sender: Sender<String>) -> Self
{
Self
{
number: 2,
client_sender
}
}
}
impl ActorState for TwoPlusTwoActorState
{
fn run(&mut self) -> bool
{
if self.number < 4
{
self.number += 2;
let message = format!("two plus two is: {}", self.number);
if let Err(_) = self.client_sender.send(message)
{
return false;
}
return true;
}
false
}
}
fn main()
{
let (sender, receiver) = channel();
ThreadActor::spawn(TwoPlusTwoActorState::new(sender));
let res = receiver.recv().expect("Error: Message not delivered");
println!("{}", res);
}
In the above example an actor sends a String message to the main thread which prints it out.
Note that the actor continues or stops running depending on whether you return true or false from its run method. This is the run phase of the actor. There are also pre-run and post-run phases represented by pre_run and post_run methods which can also be manually implemented.
This is also the case with async actors as well, but each method you implement has an additional “_async” on the end of its name.
Lastly Act.rs actors do not handle communications or errors by default. It is left up to you to decide how to handle these issues.
§An Overview
You create a state struct that contains the state of your actor.
This state struct should implement either ActorState or ActorStateAsync depending on whether or not you want the actor to be async compatible.
Finally pass the state into the actor spawn method and there you have your actor, which basically runs until its run method returns false or equivalent.
§With Actorflow
use act_rs::{ActorState, ActorFlow};
use std::sync::mpsc::{Sender, channel};
//use super::*;
use act_rs::std::ThreadActor;
struct TwoPlusTwoActorState
{
number: u32,
client_sender: Sender<String>
}
impl TwoPlusTwoActorState
{
pub fn new(client_sender: Sender<String>) -> Self
{
Self
{
number: 2,
client_sender
}
}
fn run_flow(&mut self) -> ActorFlow
{
if self.number < 4
{
self.number += 2;
let message = format!("two plus two is: {}", self.number);
if let Err(_) = self.client_sender.send(message)
{
return ActorFlow::Exit;
}
return ActorFlow::Proceed;
}
ActorFlow::Exit
}
}
impl ActorState for TwoPlusTwoActorState
{
fn run(&mut self) -> bool
{
self.run_flow().into()
}
}
fn main()
{
let (sender, receiver) = channel();
ThreadActor::spawn(TwoPlusTwoActorState::new(sender));
let res = receiver.recv().expect("Error: Message not delivered");
println!("{}", res);
}
The ActorFlow enum can be used instead of bools when specifying whether or not the actor will proceed to the next loop.
§Pipelining
Actors can be used to help you setup pipelines.
You would setup a pipeline to divide work into stages which potentially would be performed on different threads depending on what kind of actors you chose among other things.
§Potential Issues When Setting Up
When setting up your actors with input channels or message queues, you should:
- Make sure that your actors don’t wait excessively or get stuck (wait indefinitely) when doing work.
- If you are using actors as part of a pipeline; watch out for message loops.
- Make sure that your actors don’t exit unexpectedly.
- Check for bottlenecks and possibly implement a way to add actors and remove actors from a particular stages or channels dynamically (pipelines).
If you follow these guidelines you should have a productive time using Act.rs.
§Examples
§Features
| Feature | Description |
|---|---|
| std | Enable std based actors. |
| async-trait | Enable async-trait related functionality. |
§Todo
- Add more examples
- Add more tests
- Cleanup the code
§Coding Style
This project uses a coding style that emphasises the use of white space over keeping the line and column counts as low as possible.
So this:
fn bar() {}
fn foo()
{
bar();
}
Not this:
fn bar() {}
fn foo()
{
bar();
}
§License
Licensed under either of:
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0 (see also: https://www.tldrlegal.com/license/apache-license-2-0-apache-2-0))
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT (see also: https://www.tldrlegal.com/license/mit-license))
at your discretion
§Contributing
Please clone the repository and create an issue explaining what feature or features you’d like to add or bug or bugs you’d like to fix and perhaps how you intend to implement these additions or fixes. Try to include details though it doesn’t need to be exhaustive and we’ll take it from there (dependant on availability).
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Modules§
- std
std - std::Thread based actors
Macros§
- get_
input - A boilerplate reducer intended to be used in actor run methods.
- get_
input_ async - A boilerplate reducer intended to be used in actor run_async methods.
- get_
input_ with_ err - A boilerplate reducer intended to be used in actor run methods.
- get_
input_ with_ err_ async - A boilerplate reducer intended to be used in actor run_async methods.
- get_
input_ with_ errs - A boilerplate reducer intended to be used in actor run methods.
- get_
input_ with_ errs_ async - A boilerplate reducer intended to be used in actor run_async methods.
- impl_
post_ run_ async - The “default” implementation of the post_run_async method for impl_mac_task_actor and impl_mac_task_actor_built_state implementators.
- impl_
pre_ and_ post_ run_ async - Produces the “default” implementations of both the pre_run_async and post_run_async methods.
- impl_
pre_ run_ async - The “default” implementation of the pre_run_async method for impl_mac_task_actor and impl_mac_task_actor_built_state implementators.
- impl_
pre_ run_ flow_ and_ post_ run_ async - impl_
pre_ run_ flow_ async
Enums§
- Actor
Flow - In-case you wanted another way to indicate whether or not an actor should proceed or exit.
Traits§
- Actor
State - The trait used for standard thread and blocking thread based actors.
- Actor
State Async - The trait used for async oriented actors.
- Actor
State Builder - The contract that all ActorStateBuilder obects are expected to adhere to. The build method is called during the “build” phase of supported actor type instances. If the result of this call is None then it is expected that the actor will exit without executing any further phases.
- Actor
State Builder Async - The contract that all ActorStateBuilderAsync obects are expected to adhere to. The build_async method is called during the “build” phase of supported actor type instances. If the result of this call is None then it is expected that the actor will exit without executing any further phases.
- Actor
State Builder Unwind Safe Async - Actor
State Flexible - An ActorState that deals with T.
- Actor
State Flexible Async - An async ActorState that deals with T.
- Actor
State Flexible Default - An ActorState that deals with T.
- Actor
State Flexible Default Async - An async ActorState that deals with T.
- Actor
State Flow - An ActorState that deals with ActorFlows.
- Actor
State Flow Async - An async ActorState that deals with ActorFlows.
- Actor
State Unwind Safe Async - Async
Panic Handler async-trait