Skip to content

Instantly share code, notes, and snippets.

@ddoronin
Last active June 1, 2022 03:22
Show Gist options
  • Save ddoronin/e733b4e6d146bef63db69c1dfc3ff1f9 to your computer and use it in GitHub Desktop.
Save ddoronin/e733b4e6d146bef63db69c1dfc3ff1f9 to your computer and use it in GitHub Desktop.
Actor System implementation in Rust
use std::fmt::Debug;
use std::future::Future;
use tokio::sync::mpsc;
use tokio::sync::{oneshot};
use tokio::sync::mpsc::{Sender, Receiver};
pub enum ActorMessage<State, Action> {
Message(Action),
Reply(oneshot::Sender<State>),
}
pub struct Actor<State, Action, Reducer, Effects> where State: Clone + Sized + Debug,
Action: Clone + Sized,
Reducer: Fn(State, Action) -> State,
Effects: Fn(State, Action) -> () {
pub state: State,
pub reducer: Reducer,
pub effects: Effects,
pub receiver: Receiver<ActorMessage<State, Action>>,
}
impl <State, Action, Reducer, Effects> Actor<State, Action, Reducer, Effects>
where State: Clone + Sized + Debug,
Action: Clone + Sized,
Reducer: Fn(State, Action) -> State,
Effects: Fn(State, Action) -> () {
fn handle_message(&mut self, msg: ActorMessage<State, Action>) {
match msg {
ActorMessage::Message(action) => {
self.state = (self.reducer)(self.state.clone(), action.clone());
(self.effects)(self.state.clone(), action.clone());
},
ActorMessage::Reply(sender) => {
sender.send(self.state.clone());
}
}
}
}
pub fn create_pure_actor<State, Action, Reducer>(state: State,
reducer: Reducer) -> (impl Future<Output=()>, Sender<ActorMessage<State, Action>>)
where State: Clone + Sized + Debug,
Action: Clone + Sized,
Reducer: Fn(State, Action) -> State + Send {
create_actor(state, reducer, |_, _| {}, 256)
}
pub fn create_actor<State, Action, Reducer, Effects>(
state: State,
reducer: Reducer,
effects: Effects,
message_box_buffer: usize) -> (impl Future<Output=()>, Sender<ActorMessage<State, Action>>)
where State: Clone + Sized + Debug,
Action: Clone + Sized,
Reducer: Fn(State, Action) -> State + Send,
Effects: Fn(State, Action) -> () {
let (sender, receiver) = mpsc::channel::<ActorMessage<State, Action>>(message_box_buffer);
let mut actor = Actor {
state,
reducer,
effects,
receiver
};
return (run_actor(actor), sender);
}
pub async fn request_actor_state<State, Action>(sender: &Sender<ActorMessage<State, Action>>) -> State
where State: Clone + Sized + Debug {
let (reply_tx, mut reply_rx) = oneshot::channel::<State>();
sender.send(ActorMessage::Reply(reply_tx)).await;
reply_rx.await.unwrap()
}
pub async fn run_actor<State, Action, Reducer, Effects>(mut actor: Actor<State, Action, Reducer, Effects>)
where State: Clone + Sized + Debug,
Action: Clone + Sized,
Reducer: Fn(State, Action) -> State + Send,
Effects: Fn(State, Action) -> () {
while let Some(msg) = actor.receiver.recv().await {
actor.handle_message(msg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment