pub struct Link<A: ActorLike> { /* private fields */ }Implementations§
Source§impl<A: ActorLike> Link<A>
impl<A: ActorLike> Link<A>
pub async fn ask_dyn_async<T>( &self, message: T, ) -> BoxFuture<'static, <A as Handler<T>>::Reply>
pub async fn tell_dyn<T>(&self, message: T)
pub async fn relay_dyn<T>( &self, envelope: Envelope<T, <A as Handler<T>>::Reply>, )
Sourcepub async fn ask_dyn<T>(&self, message: T) -> <A as Handler<T>>::Reply
pub async fn ask_dyn<T>(&self, message: T) -> <A as Handler<T>>::Reply
Examples found in repository?
examples/ping_pong.rs (line 59)
52 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: StartPing) -> Self::Reply {
53 self.pong_actor = Some(msg.0);
54
55 // Start the ping-pong game
56 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 // Continue ping-pong for a few rounds
73 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
87// Pong Actor implementation
88impl 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 // We need the ping actor reference to send back Pong
113 // For this example, we'll use the actor context to get the sender
114 Ok(())
115 }
116}
117
118// Since we need bidirectional communication, let's modify the approach
119#[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; // true for ping, false for pong
134 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 this is the ping actor, start the game
162 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 // Spawn ping and pong actors
198 let ping = spawn::<PingPong>(true);
199 let pong = spawn::<PingPong>(false);
200
201 // Connect them
202 let _ = ping.ask_dyn(Connect(pong.clone())).await;
203 let _ = pong.ask_dyn(Connect(ping)).await;
204
205 // Wait for the game to finish
206 sleep(Duration::from_secs(2)).await;
207
208 Ok(())
209}More examples
examples/bank_account.rs (line 130)
112 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: Transfer) -> Self::Reply {
113 if msg.amount <= 0.0 {
114 return Err(BankError::InvalidAmount { amount: msg.amount }.into());
115 }
116
117 if self.balance < msg.amount {
118 return Err(BankError::InsufficientFunds {
119 balance: self.balance,
120 requested: msg.amount
121 }.into());
122 }
123
124 // Withdraw from this account
125 self.balance -= msg.amount;
126 println!("Account {}: Transfer out ${:.2}, new balance: ${:.2}",
127 self.account_number, msg.amount, self.balance);
128
129 // Deposit to target account
130 let _ = msg.to_account.ask_dyn(Deposit { amount: msg.amount }).await?;
131 println!("Transfer of ${:.2} completed from {} to target account",
132 msg.amount, self.account_number);
133
134 Ok(())
135 }
136}
137
138#[tokio::main]
139async fn main() -> anyhow::Result<()> {
140 // Create two bank accounts
141 let alice_account = spawn::<BankAccount>(("ALICE-001".to_string(), 1000.0));
142 let bob_account = spawn::<BankAccount>(("BOB-002".to_string(), 500.0));
143
144 // Perform some operations
145 println!("\n=== Initial Operations ===");
146
147 // Check initial balances
148 let alice_balance = alice_account.ask_dyn(GetBalance).await?;
149 let bob_balance = bob_account.ask_dyn(GetBalance).await?;
150 println!("Alice: ${:.2}, Bob: ${:.2}", alice_balance, bob_balance);
151
152 // Alice deposits money
153 let _ = alice_account.ask_dyn(Deposit { amount: 200.0 }).await?;
154
155 // Bob withdraws money
156 let _ = bob_account.ask_dyn(Withdraw { amount: 100.0 }).await?;
157
158 println!("\n=== Transfer Operation ===");
159
160 // Alice transfers money to Bob
161 alice_account.ask_dyn(Transfer {
162 to_account: bob_account.clone(),
163 amount: 300.0
164 }).await?;
165
166 println!("\n=== Final Balances ===");
167 let alice_final = alice_account.ask_dyn(GetBalance).await?;
168 let bob_final = bob_account.ask_dyn(GetBalance).await?;
169 println!("Alice: ${:.2}, Bob: ${:.2}", alice_final, bob_final);
170
171 println!("\n=== Error Handling ===");
172
173 // Try to withdraw more than available (should fail)
174 match alice_account.ask_dyn(Withdraw { amount: 2000.0 }).await {
175 Ok(_) => println!("Withdrawal succeeded unexpectedly!"),
176 Err(e) => println!("Withdrawal failed as expected: {}", e),
177 }
178
179 // Wait a moment before shutting down
180 sleep(Duration::from_millis(100)).await;
181
182 Ok(())
183}examples/handler_pattern.rs (line 105)
95async fn main() -> anyhow::Result<()> {
96 println!("=== Handler Pattern Example ===\n");
97
98 // Spawn the actor
99 let actor = spawn::<MultiHandlerActor>("CounterBot".to_string());
100
101 // Use different message types with the same actor
102 println!("1. Testing typed messages:");
103
104 // Increment counter
105 let count1: Result<i32, anyhow::Error> = actor.ask_dyn(IncrementMsg).await;
106 println!("Result: {:?}", count1);
107
108 let count2: Result<i32, anyhow::Error> = actor.ask_dyn(IncrementMsg).await;
109 println!("Result: {:?}", count2);
110
111 // Get current count
112 let current: Result<i32, anyhow::Error> = actor.ask_dyn(GetCountMsg).await;
113 println!("Current count: {:?}", current);
114
115 println!("\n2. Testing name operations:");
116
117 // Change name
118 let old_name: Result<String, anyhow::Error> = actor.ask_dyn(SetNameMsg("SuperBot".to_string())).await;
119 println!("Previous name: {:?}", old_name);
120
121 // Get current name
122 let name: Result<String, anyhow::Error> = actor.ask_dyn(GetNameMsg).await;
123 println!("Current name: {:?}", name);
124
125 println!("\n3. Testing dynamic string messages:");
126
127 // Send string messages dynamically
128 let response1: Result<String, anyhow::Error> = actor.ask_dyn("Hello there!".to_string()).await;
129 println!("Response: {:?}", response1);
130
131 let response2: Result<String, anyhow::Error> = actor.ask_dyn("How are you doing?".to_string()).await;
132 println!("Response: {:?}", response2);
133
134 println!("\n4. Final state check:");
135 let final_count: Result<i32, anyhow::Error> = actor.ask_dyn(GetCountMsg).await;
136 let final_name: Result<String, anyhow::Error> = actor.ask_dyn(GetNameMsg).await;
137 println!("Final count: {:?}, Final name: {:?}", final_count, final_name);
138
139 Ok(())
140}examples/worker_pool.rs (line 130)
93async fn main() -> anyhow::Result<()> {
94 println!("=== Worker Pool Example ===\n");
95
96 // Create workers
97 let worker1 = spawn::<Worker>(1);
98 let worker2 = spawn::<Worker>(2);
99 let worker3 = spawn::<Worker>(3);
100
101 // Submit several tasks to different workers
102 println!("Submitting tasks...\n");
103
104 let tasks = vec![
105 ("Calculate prime numbers", 500),
106 ("Process image", 800),
107 ("Analyze data", 300),
108 ("Generate report", 1000),
109 ("Send email", 200),
110 ("Update database", 600),
111 ];
112
113 // Submit tasks concurrently using tokio::spawn
114 let mut handles = vec![];
115
116 for (i, (task_name, duration)) in tasks.into_iter().enumerate() {
117 let worker = match i % 3 {
118 0 => worker1.clone(),
119 1 => worker2.clone(),
120 _ => worker3.clone(),
121 };
122
123 let handle = tokio::spawn(async move {
124 let task = Task {
125 id: (i + 1) as u32,
126 data: format!("{} #{}", task_name, i + 1),
127 processing_time_ms: duration,
128 };
129
130 worker.ask_dyn(task).await
131 });
132 handles.push(handle);
133 }
134
135 // Wait for all tasks to complete
136 println!("Waiting for all tasks to complete...\n");
137 for handle in handles {
138 match handle.await? {
139 Ok(result) => println!("✓ Task {} completed: {}", result.task_id, result.result),
140 Err(e) => println!("✗ Task failed: {}", e),
141 }
142 }
143
144 // Get worker statistics
145 println!("\n=== Worker Statistics ===");
146 for worker in [&worker1, &worker2, &worker3] {
147 match worker.ask_dyn(GetWorkerStats).await {
148 Ok(stats) => println!("Worker {}: {} tasks processed", stats.worker_id, stats.tasks_processed),
149 Err(e) => println!("Failed to get stats: {}", e),
150 }
151 }
152
153 println!("\n=== All tasks completed ===");
154
155 // Wait a moment for any remaining output
156 sleep(Duration::from_millis(500)).await;
157
158 Ok(())
159}examples/dynamic_dispatch.rs (lines 186-189)
178async fn main() -> anyhow::Result<()> {
179 println!("=== Dynamic Dispatch Example ===\n");
180
181 let router = spawn::<RouterActor>(());
182
183 // Test typed message handlers
184 println!("1. Setting up routes:");
185
186 let _: Result<bool, anyhow::Error> = router.ask_dyn(AddRouteRequest {
187 path: "/api/users".to_string(),
188 handler: "UserHandler".to_string(),
189 }).await;
190
191 let _: Result<bool, anyhow::Error> = router.ask_dyn(AddRouteRequest {
192 path: "/api/posts".to_string(),
193 handler: "PostHandler".to_string(),
194 }).await;
195
196 let _: Result<bool, anyhow::Error> = router.ask_dyn(AddRouteRequest {
197 path: "/health".to_string(),
198 handler: "HealthHandler".to_string(),
199 }).await;
200
201 println!("\n2. Testing route lookups:");
202
203 let response: Result<RouteResponse, anyhow::Error> = router.ask_dyn(GetRouteRequest {
204 path: "/api/users".to_string(),
205 }).await;
206 println!("Lookup result: {:?}", response);
207
208 let response: Result<RouteResponse, anyhow::Error> = router.ask_dyn(GetRouteRequest {
209 path: "/nonexistent".to_string(),
210 }).await;
211 println!("Lookup result: {:?}", response);
212
213 println!("\n3. Listing all routes:");
214 let routes: Result<Vec<(String, String)>, anyhow::Error> = router.ask_dyn(ListRoutesRequest).await;
215 println!("Routes: {:?}", routes);
216
217 println!("\n4. Testing dynamic string commands:");
218
219 let help: Result<String, anyhow::Error> = router.ask_dyn("help".to_string()).await;
220 println!("Help response: {:?}", help);
221
222 let status: Result<String, anyhow::Error> = router.ask_dyn("status".to_string()).await;
223 println!("Status response: {:?}", status);
224
225 let echo: Result<String, anyhow::Error> = router.ask_dyn("echo Hello dynamic world!".to_string()).await;
226 println!("Echo response: {:?}", echo);
227
228 let unknown: Result<String, anyhow::Error> = router.ask_dyn("unknown command".to_string()).await;
229 println!("Unknown command response: {:?}", unknown);
230
231 println!("\n5. Final stats:");
232 let stats: Result<(u32, usize), anyhow::Error> = router.ask_dyn(StatsRequest).await;
233 println!("Final stats: {:?}", stats);
234
235 Ok(())
236}Sourcepub async fn send<T, R>(&self, message: T) -> R
pub async fn send<T, R>(&self, message: T) -> R
Examples found in repository?
examples/echo_server.rs (line 40)
34async fn main() -> anyhow::Result<()> {
35 let echo_server = spawn::<EchoServer>(());
36
37 let messages = vec!["Hello", "World", "How are you?", "Goodbye"];
38
39 for message in messages {
40 let response: anyhow::Result<String> = echo_server.send(message.to_string()).await;
41 println!("Received: {}", response?);
42 }
43
44 Ok(())
45}More examples
examples/basic_actor.rs (line 75)
70async fn main() -> anyhow::Result<()> {
71 // Spawn a counter actor with initial value 0
72 let counter = spawn::<Counter>(0);
73
74 // Send increment messages
75 counter.send(()).await?;
76 counter.send(()).await?;
77 counter.send(()).await?;
78
79 println!("Sent 3 increment messages");
80
81 // For demonstration, we'll just show that we can increment
82 // A real multi-message actor would use the Multi<A> pattern
83 // as shown in the integration tests
84
85 Ok(())
86}examples/simple_counter.rs (line 60)
55async fn main() -> anyhow::Result<()> {
56 // Spawn a counter actor with initial value 0
57 let counter = spawn::<Counter>(0);
58
59 // Send increment messages
60 let _: anyhow::Result<CounterResponse> = counter.send(CounterRequest::Increment).await;
61 let _: anyhow::Result<CounterResponse> = counter.send(CounterRequest::Increment).await;
62 let _: anyhow::Result<CounterResponse> = counter.send(CounterRequest::Increment).await;
63
64 // Get the current count
65 let response: anyhow::Result<CounterResponse> = counter.send(CounterRequest::GetCount).await;
66 match response? {
67 CounterResponse::Count(count) => println!("Final count: {}", count),
68 _ => println!("Unexpected response"),
69 }
70
71 Ok(())
72}pub async fn send_raw( &self, message: A::Message, ) -> Result<(), <<<A as ActorLike>::Channel as ActorChannel>::Sender as ActorSender<<<A as ActorLike>::Channel as ActorChannel>::Message>>::Error>
pub fn cancel(&self, reason: A::Cancel)
pub async fn cancel_and_wait(&self, reason: A::Cancel)
pub fn to_dyn<M>(&self) -> DynLink<M>
Trait Implementations§
impl<A: ActorLike> Eq for Link<A>
Auto Trait Implementations§
impl<A> Freeze for Link<A>
impl<A> !RefUnwindSafe for Link<A>
impl<A> Send for Link<A>
impl<A> Sync for Link<A>
impl<A> Unpin for Link<A>
impl<A> !UnwindSafe for Link<A>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.