1use actor12::prelude::*;
2use actor12::{Multi, MpscChannel, Call, spawn, Link};
3use std::future::Future;
4use std::time::Duration;
5use tokio::time::sleep;
6
7pub struct PingActor {
9 pong_actor: Option<Link<PongActor>>,
10 ping_count: u32,
11}
12
13pub struct PongActor {
15 pong_count: u32,
16}
17
18#[derive(Debug)]
20pub struct StartPing(pub Link<PongActor>);
21
22#[derive(Debug)]
23pub struct Ping(pub u32);
24
25#[derive(Debug)]
26pub struct Pong(pub u32);
27
28impl Actor for PingActor {
30 type Spec = ();
31 type Message = Multi<Self>;
32 type Channel = MpscChannel<Self::Message>;
33 type Cancel = ();
34 type State = ();
35
36 fn state(_spec: &Self::Spec) -> Self::State {}
37
38 fn init(_ctx: Init<'_, Self>) -> impl Future<Output = Result<Self, Self::Cancel>> + Send + 'static {
39 async move {
40 println!("PingActor initialized");
41 Ok(PingActor {
42 pong_actor: None,
43 ping_count: 0,
44 })
45 }
46 }
47}
48
49impl Handler<StartPing> for PingActor {
50 type Reply = Result<(), anyhow::Error>;
51
52 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: StartPing) -> Self::Reply {
53 self.pong_actor = Some(msg.0);
54
55 if let Some(ref pong) = self.pong_actor {
57 self.ping_count += 1;
58 println!("Ping #{}", self.ping_count);
59 let _ = pong.ask_dyn(Ping(self.ping_count)).await;
60 }
61
62 Ok(())
63 }
64}
65
66impl Handler<Pong> for PingActor {
67 type Reply = Result<(), anyhow::Error>;
68
69 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: Pong) -> Self::Reply {
70 println!("Received Pong #{}", msg.0);
71
72 if self.ping_count < 5 {
74 if let Some(ref pong) = self.pong_actor {
75 self.ping_count += 1;
76 println!("Ping #{}", self.ping_count);
77 let _ = pong.ask_dyn(Ping(self.ping_count)).await;
78 }
79 } else {
80 println!("Ping-pong game finished!");
81 }
82
83 Ok(())
84 }
85}
86
87impl Actor for PongActor {
89 type Spec = ();
90 type Message = Multi<Self>;
91 type Channel = MpscChannel<Self::Message>;
92 type Cancel = ();
93 type State = ();
94
95 fn state(_spec: &Self::Spec) -> Self::State {}
96
97 fn init(_ctx: Init<'_, Self>) -> impl Future<Output = Result<Self, Self::Cancel>> + Send + 'static {
98 async move {
99 println!("PongActor initialized");
100 Ok(PongActor { pong_count: 0 })
101 }
102 }
103}
104
105impl Handler<Ping> for PongActor {
106 type Reply = Result<(), anyhow::Error>;
107
108 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: Ping) -> Self::Reply {
109 self.pong_count += 1;
110 println!("Received Ping #{}, sending Pong #{}", msg.0, self.pong_count);
111
112 Ok(())
115 }
116}
117
118#[derive(Debug)]
120pub struct PingPong {
121 other_actor: Option<Link<PingPong>>,
122 is_ping: bool,
123 count: u32,
124}
125
126#[derive(Debug)]
127pub struct Connect(pub Link<PingPong>);
128
129#[derive(Debug)]
130pub struct Ball(pub u32);
131
132impl Actor for PingPong {
133 type Spec = bool; type Message = Multi<Self>;
135 type Channel = MpscChannel<Self::Message>;
136 type Cancel = ();
137 type State = ();
138
139 fn state(_spec: &Self::Spec) -> Self::State {}
140
141 fn init(ctx: Init<'_, Self>) -> impl Future<Output = Result<Self, Self::Cancel>> + Send + 'static {
142 let is_ping = ctx.spec;
143 async move {
144 let name = if is_ping { "Ping" } else { "Pong" };
145 println!("{} actor initialized", name);
146 Ok(PingPong {
147 other_actor: None,
148 is_ping,
149 count: 0,
150 })
151 }
152 }
153}
154
155impl Handler<Connect> for PingPong {
156 type Reply = Result<(), anyhow::Error>;
157
158 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: Connect) -> Self::Reply {
159 self.other_actor = Some(msg.0);
160
161 if self.is_ping {
163 if let Some(ref other) = self.other_actor {
164 self.count = 1;
165 println!("Ping sends ball #{}", self.count);
166 let _ = other.ask_dyn(Ball(self.count)).await;
167 }
168 }
169
170 Ok(())
171 }
172}
173
174impl Handler<Ball> for PingPong {
175 type Reply = Result<(), anyhow::Error>;
176
177 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: Ball) -> Self::Reply {
178 let name = if self.is_ping { "Ping" } else { "Pong" };
179 println!("{} receives ball #{}", name, msg.0);
180
181 if msg.0 < 10 {
182 if let Some(ref other) = self.other_actor {
183 let next_count = msg.0 + 1;
184 println!("{} sends ball #{}", name, next_count);
185 let _ = other.ask_dyn(Ball(next_count)).await;
186 }
187 } else {
188 println!("{} stops the game at ball #{}", name, msg.0);
189 }
190
191 Ok(())
192 }
193}
194
195#[tokio::main]
196async fn main() -> anyhow::Result<()> {
197 let ping = spawn::<PingPong>(true);
199 let pong = spawn::<PingPong>(false);
200
201 let _ = ping.ask_dyn(Connect(pong.clone())).await;
203 let _ = pong.ask_dyn(Connect(ping)).await;
204
205 sleep(Duration::from_secs(2)).await;
207
208 Ok(())
209}