counter/counter.rs
1//! Counter Actor Example
2//!
3//! This example demonstrates a simple counter Actor, illustrating the following features:
4//! - Actor state management
5//! - Asynchronous message processing
6//! - Synchronous instruction response (oneshot channel)
7//! - Starting and gracefully closing an Actor
8use acty::{Actor, ActorExt, AsyncClose};
9use futures::{Stream, StreamExt};
10use std::pin::pin;
11
12/// Counter Actor
13///
14/// This Actor maintains the count value `value` internally, but the struct itself
15/// contains no fields. The state is maintained asynchronously within the `run` method.
16struct Counter;
17
18/// Message types for the Counter Actor
19///
20/// The Actor updates or provides the count value by receiving these messages.
21enum CounterMessage {
22 /// Increments the count value
23 Increment,
24
25 /// Requests the current count value
26 ///
27 /// The sender receives the count result via `tokio::sync::oneshot::Receiver<u64>`
28 GetValue(tokio::sync::oneshot::Sender<u64>),
29}
30
31/// Implements the `Actor` trait for the `Counter` Actor
32///
33/// The Actor message type is `CounterMessage`, and it asynchronously maintains
34/// the internal count value `value`.
35///
36/// - Iterates over the inbox to process messages
37/// - Updates the state or returns the result via oneshot based on the message
38impl Actor for Counter {
39 type Message = CounterMessage;
40
41 async fn run(self, inbox: impl Stream<Item = Self::Message> + Send) {
42 // Pin the inbox to the stack for asynchronous iteration
43 let mut inbox = pin!(inbox);
44
45 // The count value (Actor state)
46 let mut value = 0;
47
48 // Asynchronously process each message
49 while let Some(msg) = inbox.next().await {
50 match msg {
51 // Increment the counter
52 CounterMessage::Increment => value += 1,
53
54 // Return the current count via oneshot
55 // If sending fails (e.g., the Actor has already finished), ignore the error
56 CounterMessage::GetValue(tx) => tx.send(value).unwrap_or(()),
57 }
58 }
59 }
60}
61
62#[tokio::main]
63async fn main() {
64 // Launch the counter Actor
65 let counter = Counter.start();
66
67 // Send three increment instructions
68 counter.send(CounterMessage::Increment).unwrap_or(());
69 counter.send(CounterMessage::Increment).unwrap_or(());
70 counter.send(CounterMessage::Increment).unwrap_or(());
71
72 // Create a oneshot channel to retrieve the current count value
73 let (rx, tx) = tokio::sync::oneshot::channel();
74 counter.send(CounterMessage::GetValue(rx)).unwrap_or(());
75
76 // Asynchronously wait for the result and print it
77 println!("count: {}", tx.await.unwrap());
78
79 // Close the outbox and wait for the Actor to finish
80 counter.close().await;
81}