Skip to content

Instantly share code, notes, and snippets.

@j5ik2o
Created July 14, 2024 09:29
Show Gist options
  • Save j5ik2o/e320120b0e2b9ac640f2c959fa09767b to your computer and use it in GitHub Desktop.
Save j5ik2o/e320120b0e2b9ac640f2c959fa09767b to your computer and use it in GitHub Desktop.
use std::fmt::Debug;
use async_trait::async_trait;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
// 既存のインポートはそのまま維持
type BehaviorFn<M> = Box<dyn Fn(M, &mut ActorContext<M>) -> Pin<Box<dyn Future<Output = Behavior<M>> + Send>> + Send + Sync>;
pub struct Behavior<M: Message> {
f: BehaviorFn<M>,
}
impl<M: Message> Behavior<M> {
pub fn new<F, Fut>(f: F) -> Self
where
F: Fn(M, &mut ActorContext<M>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Behavior<M>> + Send + 'static,
{
Behavior {
f: Box::new(move |msg, ctx| Box::pin(f(msg, ctx))),
}
}
pub async fn receive(&self, msg: M, ctx: &mut ActorContext<M>) -> Behavior<M> {
(self.f)(msg, ctx).await
}
}
pub struct ActorContext<M: Message> {
context_handle: ContextHandle,
_phantom: std::marker::PhantomData<M>,
}
impl<M: Message> ActorContext<M> {
pub fn new(context_handle: ContextHandle) -> Self {
Self {
context_handle,
_phantom: std::marker::PhantomData,
}
}
pub fn context_handle(&self) -> &ContextHandle {
&self.context_handle
}
}
#[async_trait]
pub trait BehaviorActor: Actor {
type Message: Message;
fn create_initial_behavior() -> Behavior<Self::Message>;
async fn handle_behavior(&mut self, context_handle: ContextHandle) -> Result<(), ActorError> {
let message_handle = context_handle.get_message_handle().await;
let arm = message_handle.to_typed::<AutoReceiveMessage>();
match arm {
Some(arm) => match arm {
AutoReceiveMessage::PreStart => self.pre_start(context_handle).await,
AutoReceiveMessage::PostStart => self.post_start(context_handle).await,
AutoReceiveMessage::PreRestart => self.pre_restart(context_handle).await,
AutoReceiveMessage::PostRestart => self.post_restart(context_handle).await,
AutoReceiveMessage::PreStop => self.pre_stop(context_handle).await,
AutoReceiveMessage::PostStop => self.post_stop(context_handle).await,
AutoReceiveMessage::Terminated(t) => self.post_child_terminate(context_handle, &t).await,
},
_ => {
let msg = message_handle.to_typed::<Self::Message>().unwrap();
let mut actor_context = ActorContext::new(context_handle);
let mut current_behavior = Self::create_initial_behavior();
current_behavior = current_behavior.receive(msg, &mut actor_context).await;
Ok(())
},
}
}
}
#[derive(Debug, Clone)]
enum Message {
Greet(String),
SwitchToFormal,
SwitchToInformal,
}
impl Message for Message {
fn eq_message(&self, other: &dyn Message) -> bool {
other.eq_message(self)
}
fn as_any(&self) -> &(dyn Any + Send + Sync + 'static) {
self
}
}
#[derive(Debug)]
struct StateSwitchingActor;
impl StateSwitchingActor {
fn informal_behavior(greeting_count: usize) -> Behavior<Message> {
Behavior::new(move |msg, _ctx| async move {
match msg {
Message::Greet(name) => {
let new_count = greeting_count + 1;
println!("Hey, {}! What's up? (Greetings: {})", name, new_count);
Self::informal_behavior(new_count)
}
Message::SwitchToFormal => {
println!("Switching to formal behavior.");
Self::formal_behavior(greeting_count)
}
_ => {
println!("Informal: I don't understand that message.");
Self::informal_behavior(greeting_count)
}
}
})
}
fn formal_behavior(greeting_count: usize) -> Behavior<Message> {
Behavior::new(move |msg, _ctx| async move {
match msg {
Message::Greet(name) => {
let new_count = greeting_count + 1;
println!("Good day, {}. How may I assist you? (Greetings: {})", name, new_count);
Self::formal_behavior(new_count)
}
Message::SwitchToInformal => {
println!("Switching to informal behavior.");
Self::informal_behavior(greeting_count)
}
_ => {
println!("Formal: I do not understand that message.");
Self::formal_behavior(greeting_count)
}
}
})
}
}
#[async_trait]
impl Actor for StateSwitchingActor {
async fn receive(&mut self, context_handle: ContextHandle) -> Result<(), ActorError> {
self.handle_behavior(context_handle).await
}
}
impl BehaviorActor for StateSwitchingActor {
type Message = Message;
fn create_initial_behavior() -> Behavior<Self::Message> {
Self::informal_behavior(0)
}
}
#[tokio::main]
async fn main() {
let system = ActorSystem::new().await;
let mut root_context = system.get_root_context().await;
let actor_producer = |_| async { StateSwitchingActor };
let pid = root_context
.spawn(Props::from_actor_producer(actor_producer).await)
.await;
// 異なるメッセージを送信して動作を確認
root_context.send(pid, MessageHandle::new(Message::Greet("Alice".to_string()))).await;
root_context.send(pid, MessageHandle::new(Message::SwitchToFormal)).await;
root_context.send(pid, MessageHandle::new(Message::Greet("Bob".to_string()))).await;
root_context.send(pid, MessageHandle::new(Message::SwitchToInformal)).await;
root_context.send(pid, MessageHandle::new(Message::Greet("Charlie".to_string()))).await;
sleep(Duration::from_secs(1)).await;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment