//! Addressing a gen_server by a durable name. //! //! A gen_server is multi-message (call / cast over one inbox), so it is named //! by the *server* type rather than by a single message type. Registering it //! under a [`GenServerName`] lets clients `call` and `cast` by name, resolving on //! every use — so the address keeps working across a supervised restart, with //! no stale [`GenServerRef`] to refresh. use smarm::{call, cast, run, whereis_server, GenServer, GenServerBuilder, GenServerName, GenServerRef}; /// A counter server: synchronous `Get`, asynchronous `Inc` / `Add`. struct Counter { n: u64, } enum Query { Get, } enum Update { Inc, Add(u64), } impl GenServer for Counter { type Call = Query; type Reply = u64; type Cast = Update; type Info = (); type Timer = (); fn handle_call(&mut self, q: Query) -> u64 { match q { Query::Get => self.n, } } fn handle_cast(&mut self, u: Update) { match u { Update::Inc => self.n += 1, Update::Add(k) => self.n += k, } } } /// A durable name typed by the server, so by-name `call` / `cast` check against /// `Counter`'s `Call` / `Cast` / `Reply`. const COUNTER: GenServerName = GenServerName::new("counter"); fn main() { run(|| { // Start the server and bind its name in one step. A named start is // fallible: the name may already be held by another live server. GenServerBuilder::new(Counter { n: 0 }) .named(COUNTER) .start() .unwrap(); // Address it purely by name. Each call/cast resolves through the // registry, so a server restarted under the same name is reached // transparently. cast(COUNTER, Update::Inc).unwrap(); cast(COUNTER, Update::Add(41)).unwrap(); assert_eq!(call(COUNTER, Query::Get).unwrap(), 42); // When you want a handle to hold or pass on rather than resolve per // call, recover a typed `GenServerRef` from the name. let svc: Option> = whereis_server(COUNTER); if let Some(svc) = svc { let _ = svc.call(Query::Get); } }); }