gen_server: prefix public types with Gen (GenServerRef, GenServerCtx, GenServerName, GenServerBuilder, NamedGenServerBuilder)
This commit is contained in:
+71
-71
@@ -2,9 +2,9 @@
|
||||
//!
|
||||
//! A thin request-reply layer on top of [`channel`](crate::channel()), modelled
|
||||
//! on Erlang's `gen_server`. A *server* is an actor owning a state value that
|
||||
//! implements [`GenServer`]; clients hold a clonable [`ServerRef`] and issue
|
||||
//! [`call`](ServerRef::call) (synchronous, returns a reply) or
|
||||
//! [`cast`](ServerRef::cast) (fire-and-forget).
|
||||
//! implements [`GenServer`]; clients hold a clonable [`GenServerRef`] and issue
|
||||
//! [`call`](GenServerRef::call) (synchronous, returns a reply) or
|
||||
//! [`cast`](GenServerRef::cast) (fire-and-forget).
|
||||
//!
|
||||
//! ## One inbox, many arms
|
||||
//!
|
||||
@@ -15,7 +15,7 @@
|
||||
//!
|
||||
//! Out-of-band messages ride *separate* channels composed at the wait via
|
||||
//! [`select`](channel::select): info channels handed over at start
|
||||
//! ([`ServerBuilder::with_info`]) are dispatched to
|
||||
//! ([`GenServerBuilder::with_info`]) are dispatched to
|
||||
//! [`handle_info`](GenServer::handle_info). Arm priority is
|
||||
//! **infos before inbox**, in declaration order — a hot inbox cannot starve
|
||||
//! an out-of-band message; conversely a hot info channel CAN starve the
|
||||
@@ -45,19 +45,19 @@
|
||||
//!
|
||||
//! ## Time (timers and idle)
|
||||
//!
|
||||
//! A server arms timers through a [`TimerHandle`] cloned from the [`ServerCtx`]
|
||||
//! A server arms timers through a [`TimerHandle`] cloned from the [`GenServerCtx`]
|
||||
//! in `init` and stored on the state — the same shape as [`Watcher`] for
|
||||
//! monitors. [`arm_after`](TimerHandle::arm_after) is a one-shot,
|
||||
//! [`tick_every`](TimerHandle::tick_every) a periodic; both fire into
|
||||
//! [`handle_timer`](GenServer::handle_timer) at *system priority* (above infos
|
||||
//! and the inbox, by arm position), and [`cancel`](TimerHandle::cancel) carries
|
||||
//! the substrate's race signal. Separately, [`ServerCtx::idle_after`] sets a
|
||||
//! the substrate's race signal. Separately, [`GenServerCtx::idle_after`] sets a
|
||||
//! receive-timeout window: quiet for the whole window fires
|
||||
//! [`handle_idle`](GenServer::handle_idle).
|
||||
//!
|
||||
//! Two unrelated things share the word *timeout*: the server-side **idle /
|
||||
//! receive timeout** above, and the client-side **call deadline**
|
||||
//! ([`ServerRef::call_timeout`]) — how long a caller waits for a reply. They sit
|
||||
//! ([`GenServerRef::call_timeout`]) — how long a caller waits for a reply. They sit
|
||||
//! on different axes and never interact (RFC 015 §7).
|
||||
//!
|
||||
//! ## Not here (yet)
|
||||
@@ -85,15 +85,15 @@ use std::time::{Duration, Instant};
|
||||
/// [`terminate`](Self::terminate) are optional lifecycle hooks with no-op
|
||||
/// defaults.
|
||||
pub trait GenServer: Send + 'static {
|
||||
/// Synchronous request type (carried by [`ServerRef::call`]).
|
||||
/// Synchronous request type (carried by [`GenServerRef::call`]).
|
||||
type Call: Send + 'static;
|
||||
/// Reply type returned for a `Call`.
|
||||
type Reply: Send + 'static;
|
||||
/// Asynchronous request type (carried by [`ServerRef::cast`]).
|
||||
/// Asynchronous request type (carried by [`GenServerRef::cast`]).
|
||||
type Cast: Send + 'static;
|
||||
/// Out-of-band message type, delivered to [`handle_info`](Self::handle_info)
|
||||
/// from the info channels registered at start
|
||||
/// ([`ServerBuilder::with_info`]). Servers with several out-of-band
|
||||
/// ([`GenServerBuilder::with_info`]). Servers with several out-of-band
|
||||
/// sources enum them up into one `Info`. Use `()` if unused.
|
||||
type Info: Send + 'static;
|
||||
/// The server's own scheduled-timer payload, delivered to
|
||||
@@ -107,10 +107,10 @@ pub trait GenServer: Send + 'static {
|
||||
type Timer: Send + 'static;
|
||||
|
||||
/// Runs once inside the server actor before any message is handled. The
|
||||
/// [`ServerCtx`] is the loop's one runtime hook: clone its [`Watcher`]
|
||||
/// [`GenServerCtx`] is the loop's one runtime hook: clone its [`Watcher`]
|
||||
/// into the state here to be able to [`watch`](Watcher::watch) monitors
|
||||
/// from any later handler.
|
||||
fn init(&mut self, _ctx: &ServerCtx<Self>)
|
||||
fn init(&mut self, _ctx: &GenServerCtx<Self>)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -138,7 +138,7 @@ pub trait GenServer: Send + 'static {
|
||||
fn handle_timer(&mut self, _msg: Self::Timer) {}
|
||||
|
||||
/// Handle a receive/idle timeout: fired when the loop has waited a full
|
||||
/// idle window (set once via [`ServerCtx::idle_after`]) with no message of
|
||||
/// idle window (set once via [`GenServerCtx::idle_after`]) with no message of
|
||||
/// any kind dispatched. The window resets on every dispatched message and
|
||||
/// re-arms after this fires (a steady idle detector); a server wanting
|
||||
/// one-shot idle-shutdown simply requests its own stop here. Default: no-op
|
||||
@@ -157,27 +157,27 @@ enum Envelope<G: GenServer> {
|
||||
}
|
||||
|
||||
/// A clonable handle to a running server. Cloning yields another sender to the
|
||||
/// same inbox; the server lives until the last `ServerRef` is dropped, at which
|
||||
/// same inbox; the server lives until the last `GenServerRef` is dropped, at which
|
||||
/// point its inbox closes and the loop exits normally.
|
||||
pub struct ServerRef<G: GenServer> {
|
||||
pub struct GenServerRef<G: GenServer> {
|
||||
tx: Sender<Envelope<G>>,
|
||||
pid: Pid,
|
||||
}
|
||||
|
||||
impl<G: GenServer> Clone for ServerRef<G> {
|
||||
impl<G: GenServer> Clone for GenServerRef<G> {
|
||||
fn clone(&self) -> Self {
|
||||
ServerRef { tx: self.tx.clone(), pid: self.pid }
|
||||
GenServerRef { tx: self.tx.clone(), pid: self.pid }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returned by [`ServerRef::call`] when the server is no longer reachable.
|
||||
/// Returned by [`GenServerRef::call`] when the server is no longer reachable.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum CallError {
|
||||
/// The server was already gone, or died before replying.
|
||||
ServerDown,
|
||||
}
|
||||
|
||||
/// Returned by [`ServerRef::call_timeout`].
|
||||
/// Returned by [`GenServerRef::call_timeout`].
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum CallTimeoutError {
|
||||
/// The server was already gone, or died before replying.
|
||||
@@ -190,14 +190,14 @@ pub enum CallTimeoutError {
|
||||
Timeout,
|
||||
}
|
||||
|
||||
/// Returned by [`ServerRef::cast`] when the server is no longer reachable.
|
||||
/// Returned by [`GenServerRef::cast`] when the server is no longer reachable.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum CastError {
|
||||
/// The server inbox was closed (the server is gone).
|
||||
ServerDown,
|
||||
}
|
||||
|
||||
impl<G: GenServer> ServerRef<G> {
|
||||
impl<G: GenServer> GenServerRef<G> {
|
||||
/// The server actor's pid — usable with `monitor`, `request_stop`, `link`.
|
||||
pub fn pid(&self) -> Pid {
|
||||
self.pid
|
||||
@@ -219,7 +219,7 @@ impl<G: GenServer> ServerRef<G> {
|
||||
///
|
||||
/// This `timeout` is a **client-side call deadline** — how long *this caller*
|
||||
/// waits for a reply — and is wholly separate from the server-side idle /
|
||||
/// receive timeout ([`ServerCtx::idle_after`] →
|
||||
/// receive timeout ([`GenServerCtx::idle_after`] →
|
||||
/// [`GenServer::handle_idle`]), which measures quiet on the *server's* inbox.
|
||||
/// Same word ("timeout"), two different axes (RFC 015 §7); neither touches
|
||||
/// the other.
|
||||
@@ -264,8 +264,8 @@ impl<G: GenServer> ServerRef<G> {
|
||||
/// stop unwind). Returns immediately if the server was already gone.
|
||||
///
|
||||
/// This is the explicit teardown for a server pinned alive by a registered
|
||||
/// [`ServerName`] (whose stored sender means dropping every external
|
||||
/// [`ServerRef`] no longer closes the inbox). Best-effort like all
|
||||
/// [`GenServerName`] (whose stored sender means dropping every external
|
||||
/// [`GenServerRef`] no longer closes the inbox). Best-effort like all
|
||||
/// cooperative cancellation: a server wedged in a tight loop with no
|
||||
/// observation point cannot be stopped. Panics if called outside
|
||||
/// `Runtime::run()`.
|
||||
@@ -302,17 +302,17 @@ enum Sys<G: GenServer> {
|
||||
/// loop's two clonable intake handles — the [`Watcher`] (monitors) and the
|
||||
/// [`TimerHandle`] (timers) — plus the one-shot idle-window setter. Opaque, so
|
||||
/// fields can grow without breaking.
|
||||
pub struct ServerCtx<G: GenServer> {
|
||||
pub struct GenServerCtx<G: GenServer> {
|
||||
sys_tx: Sender<Sys<G>>,
|
||||
reg: Arc<Mutex<TimerReg<G>>>,
|
||||
/// The idle/receive-timeout window, set once via [`idle_after`](Self::idle_after)
|
||||
/// during `init` and read by the loop after `init` returns. Interior-mutable
|
||||
/// because `init` holds only `&ctx`; not `Send`, but `ServerCtx` is only ever
|
||||
/// because `init` holds only `&ctx`; not `Send`, but `GenServerCtx` is only ever
|
||||
/// borrowed on the actor's own stack during `init`, never sent.
|
||||
idle: Cell<Option<Duration>>,
|
||||
}
|
||||
|
||||
impl<G: GenServer> ServerCtx<G> {
|
||||
impl<G: GenServer> GenServerCtx<G> {
|
||||
/// A clonable handle to the loop's monitor intake. Store it in the state
|
||||
/// during `init` to watch monitors from later handlers.
|
||||
pub fn watcher(&self) -> Watcher<G> {
|
||||
@@ -341,7 +341,7 @@ impl<G: GenServer> ServerCtx<G> {
|
||||
/// detector); a server wanting one-shot idle-shutdown requests its own stop
|
||||
/// in `handle_idle`.
|
||||
///
|
||||
/// Distinct from [`ServerRef::call_timeout`], which is a *client-side* call
|
||||
/// Distinct from [`GenServerRef::call_timeout`], which is a *client-side* call
|
||||
/// deadline — same word, different axis (§7).
|
||||
pub fn idle_after(&self, after: Duration) {
|
||||
self.idle.set(Some(after));
|
||||
@@ -414,7 +414,7 @@ impl<G: GenServer> TimerReg<G> {
|
||||
}
|
||||
|
||||
/// Arms, cancels, and (chunk 4) periodically ticks server timers, the time-side
|
||||
/// twin of [`Watcher`] (RFC 015 §4.3). Handed out by [`ServerCtx::timer`] in
|
||||
/// twin of [`Watcher`] (RFC 015 §4.3). Handed out by [`GenServerCtx::timer`] in
|
||||
/// `init` and stored on the state; later handlers arm timers without any change
|
||||
/// to their signatures. Clonable; the arm stays open while any clone (or an
|
||||
/// in-flight fire) lives.
|
||||
@@ -527,20 +527,20 @@ impl<G: GenServer> Watcher<G> {
|
||||
/// [`start`]: info channels, a supervisor. Consumed by [`start`](Self::start).
|
||||
///
|
||||
/// ```ignore
|
||||
/// let server = ServerBuilder::new(state)
|
||||
/// let server = GenServerBuilder::new(state)
|
||||
/// .with_info(events_rx)
|
||||
/// .under(supervisor_pid)
|
||||
/// .start();
|
||||
/// ```
|
||||
pub struct ServerBuilder<G: GenServer> {
|
||||
pub struct GenServerBuilder<G: GenServer> {
|
||||
state: G,
|
||||
infos: Vec<Receiver<G::Info>>,
|
||||
supervisor: Option<Pid>,
|
||||
}
|
||||
|
||||
impl<G: GenServer> ServerBuilder<G> {
|
||||
impl<G: GenServer> GenServerBuilder<G> {
|
||||
pub fn new(state: G) -> Self {
|
||||
ServerBuilder { state, infos: Vec::new(), supervisor: None }
|
||||
GenServerBuilder { state, infos: Vec::new(), supervisor: None }
|
||||
}
|
||||
|
||||
/// Add an out-of-band channel; messages arriving on it are dispatched to
|
||||
@@ -558,33 +558,33 @@ impl<G: GenServer> ServerBuilder<G> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Spawn the server actor and hand back its [`ServerRef`]. The server's
|
||||
/// Spawn the server actor and hand back its [`GenServerRef`]. The server's
|
||||
/// lifetime is governed by its refs, not by joining, so the backing join
|
||||
/// handle is dropped.
|
||||
pub fn start(self) -> ServerRef<G> {
|
||||
pub fn start(self) -> GenServerRef<G> {
|
||||
self.spawn_server()
|
||||
}
|
||||
|
||||
/// Bind the server to a durable [`ServerName`] as it starts. Switches to the
|
||||
/// fallible [`NamedServerBuilder::start`] (the name may already be held by a
|
||||
/// Bind the server to a durable [`GenServerName`] as it starts. Switches to the
|
||||
/// fallible [`NamedGenServerBuilder::start`] (the name may already be held by a
|
||||
/// live server). Consumes the builder, carrying its `with_info` / `under`
|
||||
/// configuration through.
|
||||
pub fn named(self, name: ServerName<G>) -> NamedServerBuilder<G> {
|
||||
NamedServerBuilder { builder: self, name: name.as_str() }
|
||||
pub fn named(self, name: GenServerName<G>) -> NamedGenServerBuilder<G> {
|
||||
NamedGenServerBuilder { builder: self, name: name.as_str() }
|
||||
}
|
||||
|
||||
/// The shared spawn body behind [`start`](Self::start) and
|
||||
/// [`NamedServerBuilder::start`]: make the inbox, spawn the loop, return the
|
||||
/// [`NamedGenServerBuilder::start`]: make the inbox, spawn the loop, return the
|
||||
/// ref. (The named path additionally publishes the inbox sender under the
|
||||
/// name before returning.)
|
||||
fn spawn_server(self) -> ServerRef<G> {
|
||||
fn spawn_server(self) -> GenServerRef<G> {
|
||||
let (tx, rx) = channel::<Envelope<G>>();
|
||||
let ServerBuilder { state, infos, supervisor } = self;
|
||||
let GenServerBuilder { state, infos, supervisor } = self;
|
||||
let handle = match supervisor {
|
||||
Some(sup) => spawn_under(sup, move || server_loop::<G>(rx, state, infos)),
|
||||
None => spawn(move || server_loop::<G>(rx, state, infos)),
|
||||
};
|
||||
ServerRef { tx, pid: handle.pid() }
|
||||
GenServerRef { tx, pid: handle.pid() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,19 +594,19 @@ impl<G: GenServer> ServerBuilder<G> {
|
||||
/// `G`'s `Call` / `Cast` / `Reply`. Declared as a constant and shared freely:
|
||||
///
|
||||
/// ```ignore
|
||||
/// const COUNTER: ServerName<Counter> = ServerName::new("counter");
|
||||
/// const COUNTER: GenServerName<Counter> = GenServerName::new("counter");
|
||||
/// ```
|
||||
///
|
||||
/// Under the hood the server's inbox is published into the registry as a
|
||||
/// `Sender<Envelope<G>>` keyed by its message `TypeId` — the same channel store
|
||||
/// every other name uses — so naming needs no separate directory. `Envelope`
|
||||
/// stays private: only `ServerName<G>` opens that door.
|
||||
pub struct ServerName<G> {
|
||||
/// stays private: only `GenServerName<G>` opens that door.
|
||||
pub struct GenServerName<G> {
|
||||
name: &'static str,
|
||||
_marker: PhantomData<fn() -> G>,
|
||||
}
|
||||
|
||||
impl<G> ServerName<G> {
|
||||
impl<G> GenServerName<G> {
|
||||
/// Bind a static string as a server name. `const`, so names live as
|
||||
/// associated constants at call sites.
|
||||
#[inline]
|
||||
@@ -621,30 +621,30 @@ impl<G> ServerName<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G> Copy for ServerName<G> {}
|
||||
impl<G> Clone for ServerName<G> {
|
||||
impl<G> Copy for GenServerName<G> {}
|
||||
impl<G> Clone for GenServerName<G> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`ServerBuilder`] that will bind a [`ServerName`] as it starts. Reached via
|
||||
/// [`ServerBuilder::named`]; its [`start`](Self::start) is fallible because the
|
||||
/// A [`GenServerBuilder`] that will bind a [`GenServerName`] as it starts. Reached via
|
||||
/// [`GenServerBuilder::named`]; its [`start`](Self::start) is fallible because the
|
||||
/// name may already be held by a live server. `with_info` / `under` stay
|
||||
/// available so configuration can come before or after `named`.
|
||||
pub struct NamedServerBuilder<G: GenServer> {
|
||||
builder: ServerBuilder<G>,
|
||||
pub struct NamedGenServerBuilder<G: GenServer> {
|
||||
builder: GenServerBuilder<G>,
|
||||
name: &'static str,
|
||||
}
|
||||
|
||||
impl<G: GenServer> NamedServerBuilder<G> {
|
||||
/// Add an out-of-band info channel (see [`ServerBuilder::with_info`]).
|
||||
impl<G: GenServer> NamedGenServerBuilder<G> {
|
||||
/// Add an out-of-band info channel (see [`GenServerBuilder::with_info`]).
|
||||
pub fn with_info(mut self, rx: Receiver<G::Info>) -> Self {
|
||||
self.builder = self.builder.with_info(rx);
|
||||
self
|
||||
}
|
||||
|
||||
/// Spawn under an explicit supervisor (see [`ServerBuilder::under`]).
|
||||
/// Spawn under an explicit supervisor (see [`GenServerBuilder::under`]).
|
||||
pub fn under(mut self, supervisor: Pid) -> Self {
|
||||
self.builder = self.builder.under(supervisor);
|
||||
self
|
||||
@@ -659,8 +659,8 @@ impl<G: GenServer> NamedServerBuilder<G> {
|
||||
/// `start()` returns — no race with the server body. On a name clash the
|
||||
/// just-spawned server is wound down (its only ref is dropped, closing the
|
||||
/// inbox), so a failed bind leaks no actor.
|
||||
pub fn start(self) -> Result<ServerRef<G>, RegisterError> {
|
||||
let NamedServerBuilder { builder, name } = self;
|
||||
pub fn start(self) -> Result<GenServerRef<G>, RegisterError> {
|
||||
let NamedGenServerBuilder { builder, name } = self;
|
||||
let server = builder.spawn_server();
|
||||
match register_with::<Envelope<G>>(server.pid, name, server.tx.clone()) {
|
||||
Ok(()) => Ok(server),
|
||||
@@ -672,13 +672,13 @@ impl<G: GenServer> NamedServerBuilder<G> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve a [`ServerName`] to a [`ServerRef`] when you want a handle to hold or
|
||||
/// Resolve a [`GenServerName`] to a [`GenServerRef`] when you want a handle to hold or
|
||||
/// pass on rather than resolve per call. Rebuilds the ref from the registry's
|
||||
/// stored inbox sender; `None` if no live server holds the name.
|
||||
///
|
||||
/// Panics if called outside `Runtime::run()`.
|
||||
pub fn whereis_server<G: GenServer>(name: ServerName<G>) -> Option<ServerRef<G>> {
|
||||
resolve_named_sender::<Envelope<G>>(name.as_str()).map(|(pid, tx)| ServerRef { tx, pid })
|
||||
pub fn whereis_server<G: GenServer>(name: GenServerName<G>) -> Option<GenServerRef<G>> {
|
||||
resolve_named_sender::<Envelope<G>>(name.as_str()).map(|(pid, tx)| GenServerRef { tx, pid })
|
||||
}
|
||||
|
||||
/// Synchronous request-reply to the server currently registered under `name`,
|
||||
@@ -687,7 +687,7 @@ pub fn whereis_server<G: GenServer>(name: ServerName<G>) -> Option<ServerRef<G>>
|
||||
/// server holds the name, or if it dies before replying.
|
||||
///
|
||||
/// Panics if called outside `Runtime::run()`.
|
||||
pub fn call<G: GenServer>(name: ServerName<G>, request: G::Call) -> Result<G::Reply, CallError> {
|
||||
pub fn call<G: GenServer>(name: GenServerName<G>, request: G::Call) -> Result<G::Reply, CallError> {
|
||||
match whereis_server(name) {
|
||||
Some(server) => server.call(request),
|
||||
None => Err(CallError::ServerDown),
|
||||
@@ -698,7 +698,7 @@ pub fn call<G: GenServer>(name: ServerName<G>, request: G::Call) -> Result<G::Re
|
||||
/// [`CastError::ServerDown`] if no live server holds the name.
|
||||
///
|
||||
/// Panics if called outside `Runtime::run()`.
|
||||
pub fn cast<G: GenServer>(name: ServerName<G>, request: G::Cast) -> Result<(), CastError> {
|
||||
pub fn cast<G: GenServer>(name: GenServerName<G>, request: G::Cast) -> Result<(), CastError> {
|
||||
match whereis_server(name) {
|
||||
Some(server) => server.cast(request),
|
||||
None => Err(CastError::ServerDown),
|
||||
@@ -706,25 +706,25 @@ pub fn cast<G: GenServer>(name: ServerName<G>, request: G::Cast) -> Result<(), C
|
||||
}
|
||||
|
||||
/// Terminate the server registered under `name` and block until it is down (see
|
||||
/// [`ServerRef::shutdown`]). A no-op if no live server holds the name.
|
||||
/// [`GenServerRef::shutdown`]). A no-op if no live server holds the name.
|
||||
///
|
||||
/// Panics if called outside `Runtime::run()`.
|
||||
pub fn shutdown<G: GenServer>(name: ServerName<G>) {
|
||||
pub fn shutdown<G: GenServer>(name: GenServerName<G>) {
|
||||
if let Some(server) = whereis_server(name) {
|
||||
server.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn `state` as a server under the current actor (via [`spawn`]). Returns a
|
||||
/// [`ServerRef`]. Shorthand for `ServerBuilder::new(state).start()`.
|
||||
pub fn start<G: GenServer>(state: G) -> ServerRef<G> {
|
||||
ServerBuilder::new(state).start()
|
||||
/// [`GenServerRef`]. Shorthand for `GenServerBuilder::new(state).start()`.
|
||||
pub fn start<G: GenServer>(state: G) -> GenServerRef<G> {
|
||||
GenServerBuilder::new(state).start()
|
||||
}
|
||||
|
||||
/// Like [`start`], but spawns the server under an explicit supervisor pid (via
|
||||
/// [`spawn_under`]) so it slots into the supervision tree.
|
||||
pub fn start_under<G: GenServer>(supervisor: Pid, state: G) -> ServerRef<G> {
|
||||
ServerBuilder::new(state).under(supervisor).start()
|
||||
pub fn start_under<G: GenServer>(supervisor: Pid, state: G) -> GenServerRef<G> {
|
||||
GenServerBuilder::new(state).under(supervisor).start()
|
||||
}
|
||||
|
||||
fn server_loop<G: GenServer>(
|
||||
@@ -788,7 +788,7 @@ fn server_loop<G: GenServer>(
|
||||
// Bind the ctx so the idle window set during init can be read back, then
|
||||
// drop it — that drops the loop's own Sys sender, so a state that cloned no
|
||||
// Watcher/TimerHandle lets the arm auto-close (the unused-ctx behaviour).
|
||||
let ctx = ServerCtx { sys_tx, reg: reg.clone(), idle: Cell::new(None) };
|
||||
let ctx = GenServerCtx { sys_tx, reg: reg.clone(), idle: Cell::new(None) };
|
||||
guard.0.init(&ctx);
|
||||
let idle = ctx.idle.get();
|
||||
drop(ctx);
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ pub use channel::{
|
||||
};
|
||||
pub use gen_server::{
|
||||
call, cast, shutdown, whereis_server, CallError, CallTimeoutError, CastError, GenServer,
|
||||
NamedServerBuilder, ServerBuilder, ServerCtx, ServerName, ServerRef, TimerHandle, Watcher,
|
||||
NamedGenServerBuilder, GenServerBuilder, GenServerCtx, GenServerName, GenServerRef, TimerHandle, Watcher,
|
||||
};
|
||||
pub use gen_statem::{
|
||||
CallError as StatemCallError, Cx, Machine, Reply, Resolution, SendError as StatemSendError,
|
||||
|
||||
+5
-5
@@ -29,7 +29,7 @@
|
||||
//! channel by value; that is intended, it is exactly what a remote observer
|
||||
//! (RFC 011) will serialize across a node boundary.
|
||||
|
||||
use crate::gen_server::{GenServer, ServerBuilder, ServerRef};
|
||||
use crate::gen_server::{GenServer, GenServerBuilder, GenServerRef};
|
||||
use crate::introspect::{actor_info, snapshot, tree};
|
||||
use crate::introspect::{ActorInfo, RuntimeSnapshot, RuntimeTree};
|
||||
use crate::pid::Pid;
|
||||
@@ -89,8 +89,8 @@ impl GenServer for Observer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn the observer under the current actor and hand back its [`ServerRef`].
|
||||
/// Shorthand for `ServerBuilder::new(Observer).start()`; use the builder
|
||||
/// Spawn the observer under the current actor and hand back its [`GenServerRef`].
|
||||
/// Shorthand for `GenServerBuilder::new(Observer).start()`; use the builder
|
||||
/// directly (e.g. `.under(sup)`) to slot it into a supervision tree.
|
||||
///
|
||||
/// ```
|
||||
@@ -109,6 +109,6 @@ impl GenServer for Observer {
|
||||
/// assert!(snap.actors.iter().any(|a| a.pid == obs.pid()));
|
||||
/// });
|
||||
/// ```
|
||||
pub fn start() -> ServerRef<Observer> {
|
||||
ServerBuilder::new(Observer).start()
|
||||
pub fn start() -> GenServerRef<Observer> {
|
||||
GenServerBuilder::new(Observer).start()
|
||||
}
|
||||
|
||||
+2
-2
@@ -53,7 +53,7 @@ impl std::fmt::Display for RawPid {
|
||||
}
|
||||
|
||||
/// Phantom actor type for a pid that has no single message type: raw `spawn`
|
||||
/// actors, gen_servers (intrinsically multi-message, addressed via `ServerRef`),
|
||||
/// actors, gen_servers (intrinsically multi-message, addressed via `GenServerRef`),
|
||||
/// and every identity-only context. Deliberately **not** [`Addressable`], so a
|
||||
/// typed `send` to a `Pid<Erased>` does not compile; the runtime-checked
|
||||
/// `send_dyn` escape hatch (RFC 014 §4.6) is the sanctioned bare-pid path.
|
||||
@@ -166,7 +166,7 @@ impl<A> std::fmt::Display for Pid<A> {
|
||||
/// An actor type with a single associated message type, so a [`Pid<Self>`] is a
|
||||
/// typed address. The raw channel layer has no such trait (actors are closures
|
||||
/// over channels) and `GenServer` is intrinsically multi-message (addressed via
|
||||
/// its own `ServerRef`); this is the minimal hook that lets the single-message
|
||||
/// its own `GenServerRef`); this is the minimal hook that lets the single-message
|
||||
/// actors carry their message type in their pid. (RFC 014 §4.2.)
|
||||
pub trait Addressable: 'static {
|
||||
/// The message this actor receives. A `Pid<Self>` delivers `Self::Msg`.
|
||||
|
||||
+1
-1
@@ -425,7 +425,7 @@ pub fn lookup_as<A: Addressable>(name: &str) -> Option<Pid<A>> {
|
||||
/// lock (clone-under-lock, then release). The crate-internal building block for
|
||||
/// `gen_server`'s by-name addressing: a named server publishes its inbox as a
|
||||
/// `Sender<Envelope<G>>` (via [`register_with`]), and `whereis_server` / `call`
|
||||
/// / `cast` recover that exact typed sender here to rebuild a `ServerRef<G>`.
|
||||
/// / `cast` recover that exact typed sender here to rebuild a `GenServerRef<G>`.
|
||||
/// `None` if unbound, dead (pruned on the way out), or holding no `M` channel.
|
||||
pub(crate) fn resolve_named_sender<M: Send + 'static>(name: &str) -> Option<(Pid, Sender<M>)> {
|
||||
with_runtime(|inner| {
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ pub fn spawn_under<A>(supervisor: Pid<A>, f: impl FnOnce() + Send + 'static) ->
|
||||
/// [`send_to`](crate::send_to) always resolves, never racing the body's first
|
||||
/// instruction. The actor is detached — its lifetime is governed by its own
|
||||
/// logic (an explicit stop message, or returning), like
|
||||
/// [`ServerBuilder::start`](crate::ServerBuilder::start) — so the backing join
|
||||
/// [`GenServerBuilder::start`](crate::GenServerBuilder::start) — so the backing join
|
||||
/// handle is dropped. Spawns under the current actor (via [`spawn`]).
|
||||
///
|
||||
/// Panics if called outside `Runtime::run()`.
|
||||
|
||||
Reference in New Issue
Block a user