use rsactor::{message_handlers, spawn, Actor, ActorRef};
use std::time::Duration;
#[derive(Debug)]
struct Ping;
#[derive(Debug)]
struct Echo(String);
#[derive(Debug)]
struct GetCounter;
#[derive(Debug)]
struct Increment;
#[derive(Debug)]
struct SlowOperation(u64);
#[derive(Debug)]
struct FailingMessage;
#[derive(Actor)]
struct TracingDemoActor {
counter: u64,
name: String,
}
#[message_handlers]
impl TracingDemoActor {
#[handler]
async fn handle_ping(&mut self, _msg: Ping, _: &ActorRef<Self>) -> String {
format!("Pong from {}", self.name)
}
#[handler]
async fn handle_echo(&mut self, msg: Echo, _: &ActorRef<Self>) -> String {
format!("{} echoes: {}", self.name, msg.0)
}
#[handler]
async fn handle_get_counter(&mut self, _msg: GetCounter, _: &ActorRef<Self>) -> u64 {
self.counter
}
#[handler]
async fn handle_increment(&mut self, _msg: Increment, _: &ActorRef<Self>) -> String {
self.counter += 1;
format!("Counter incremented to {}", self.counter)
}
#[handler]
async fn handle_slow_operation(&mut self, msg: SlowOperation, _: &ActorRef<Self>) -> String {
tokio::time::sleep(Duration::from_millis(msg.0)).await;
self.counter += 1;
format!(
"Slow operation completed after {}ms, counter: {}",
msg.0, self.counter
)
}
#[handler]
async fn handle_failing_message(
&mut self,
_msg: FailingMessage,
_: &ActorRef<Self>,
) -> Result<String, String> {
Err("This message always fails for demonstration".to_string())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.with_target(false)
.init();
let actor = TracingDemoActor {
counter: 0,
name: "DemoActor".to_string(),
};
let (actor_ref, _handle) = spawn::<TracingDemoActor>(actor);
println!("1. Testing ping message (ask)...");
let response: String = actor_ref.ask(Ping).await?;
println!("Response: {response}\n");
println!("2. Testing echo message (ask)...");
let response: String = actor_ref.ask(Echo("Hello World!".to_string())).await?;
println!("Response: {response}\n");
println!("3. Testing increment (ask for responses)...");
let response1: String = actor_ref.ask(Increment).await?;
let response2: String = actor_ref.ask(Increment).await?;
let response3: String = actor_ref.ask(Increment).await?;
println!("Increment responses: {response1}, {response2}, {response3}\n");
println!("4. Getting counter value...");
let counter: u64 = actor_ref.ask(GetCounter).await?;
println!("Counter value: {counter}\n");
println!("5. Testing slow operation...");
let response: String = actor_ref.ask(SlowOperation(100)).await?;
println!("Response: {response}\n");
println!("6. Testing ask with timeout...");
match actor_ref
.ask_with_timeout(SlowOperation(200), Duration::from_millis(150))
.await
{
Ok(response) => println!("Response: {response}"),
Err(e) => println!("Timeout occurred as expected: {e}\n"),
}
println!("7. Testing error handling...");
match actor_ref.ask(FailingMessage).await {
Ok(response) => println!("Unexpected success: {response:?}"),
Err(e) => println!("Error handled correctly: {e}\n"),
}
println!("8. Testing tell with timeout...");
actor_ref
.tell_with_timeout(Increment, Duration::from_millis(100))
.await?;
println!("Tell with timeout completed\n");
println!("9. Final counter check...");
let final_counter: u64 = actor_ref.ask(GetCounter).await?;
println!("Final counter value: {final_counter}\n");
println!("10. Gracefully stopping actor...");
actor_ref.stop().await?;
println!("Actor stopped successfully");
#[cfg(feature = "tracing")]
println!("\n✅ Demo completed! Check the trace logs above to see the complete message lifecycle tracking.");
#[cfg(not(feature = "tracing"))]
println!("\n✅ Demo completed! Run with --features tracing to see detailed message tracking.");
Ok(())
}