Created
July 14, 2024 09:29
-
-
Save j5ik2o/e320120b0e2b9ac640f2c959fa09767b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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