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}