use async_trait::async_trait;
use joerl::ActorSystem;
use joerl::gen_server::{CallResponse, GenServer, GenServerContext};
struct CounterServer;
#[derive(Debug)]
enum CounterCall {
Get,
Add(i32),
}
#[derive(Debug)]
enum CounterCast {
Increment,
Decrement,
Reset,
}
#[async_trait]
impl GenServer for CounterServer {
type State = i32;
type Call = CounterCall;
type Cast = CounterCast;
type CallReply = i32;
async fn init(&mut self, ctx: &mut GenServerContext<'_, Self>) -> Self::State {
println!("[Counter {}] Initializing with state = 0", ctx.pid());
0
}
async fn handle_call(
&mut self,
call: Self::Call,
state: &mut Self::State,
ctx: &mut GenServerContext<'_, Self>,
) -> CallResponse<Self::CallReply> {
match call {
CounterCall::Get => {
println!("[Counter {}] handle_call(Get) -> {}", ctx.pid(), *state);
CallResponse::Reply(*state)
}
CounterCall::Add(n) => {
*state += n;
println!(
"[Counter {}] handle_call(Add({})) -> new state = {}",
ctx.pid(),
n,
*state
);
CallResponse::Reply(*state)
}
}
}
async fn handle_cast(
&mut self,
cast: Self::Cast,
state: &mut Self::State,
ctx: &mut GenServerContext<'_, Self>,
) {
match cast {
CounterCast::Increment => {
*state += 1;
println!(
"[Counter {}] handle_cast(Increment) -> state = {}",
ctx.pid(),
*state
);
}
CounterCast::Decrement => {
*state -= 1;
println!(
"[Counter {}] handle_cast(Decrement) -> state = {}",
ctx.pid(),
*state
);
}
CounterCast::Reset => {
*state = 0;
println!("[Counter {}] handle_cast(Reset) -> state = 0", ctx.pid());
}
}
}
async fn terminate(
&mut self,
reason: &joerl::ExitReason,
state: &mut Self::State,
ctx: &mut GenServerContext<'_, Self>,
) {
println!(
"[Counter {}] Terminating with reason: {}, final state: {}",
ctx.pid(),
reason,
*state
);
}
}
#[tokio::main]
async fn main() {
println!("=== GenServer Counter Example ===\n");
println!("This demonstrates Erlang-style gen_server behavior in Rust\n");
let system = ActorSystem::new();
println!("Starting counter server...\n");
let counter = joerl::gen_server::spawn(&system, CounterServer);
println!("Counter server started with PID: {}\n", counter.pid());
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
println!("--- Asynchronous casts (fire and forget) ---\n");
counter.cast(CounterCast::Increment).await.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
counter.cast(CounterCast::Increment).await.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
counter.cast(CounterCast::Increment).await.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
println!("\n--- Synchronous calls (wait for response) ---\n");
let value = counter.call(CounterCall::Get).await.unwrap();
println!("Client: Received response from Get: {}\n", value);
assert_eq!(value, 3);
let value = counter.call(CounterCall::Add(7)).await.unwrap();
println!("Client: Received response from Add(7): {}\n", value);
assert_eq!(value, 10);
let value = counter.call(CounterCall::Get).await.unwrap();
println!("Client: Received response from Get: {}\n", value);
assert_eq!(value, 10);
println!("--- More casts ---\n");
counter.cast(CounterCast::Decrement).await.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
counter.cast(CounterCast::Decrement).await.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
let value = counter.call(CounterCall::Get).await.unwrap();
println!("Client: Final value: {}\n", value);
assert_eq!(value, 8);
counter.cast(CounterCast::Reset).await.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
let value = counter.call(CounterCall::Get).await.unwrap();
println!("Client: Value after reset: {}\n", value);
assert_eq!(value, 0);
println!("--- Summary ---");
println!("✓ Demonstrated async casts (increment, decrement, reset)");
println!("✓ Demonstrated sync calls (get, add)");
println!("✓ State management with type-safe messages");
println!("✓ Erlang gen_server pattern in Rust");
println!("\nExample completed!");
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
}