//! 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 [`ServerName`] lets clients `call` and `cast` by name, resolving on //! every use — so the address keeps working across a supervised restart, with //! no stale [`ServerRef`] to refresh. use smarm::{call, cast, run, whereis_server, GenServer, ServerBuilder, ServerName, ServerRef}; /// 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 = (); 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: ServerName = ServerName::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. ServerBuilder::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 `ServerRef` from the name. let svc: Option> = whereis_server(COUNTER); if let Some(svc) = svc { let _ = svc.call(Query::Get); } }); }