feat(gen_server): synchronous call / async cast over a single actor (roadmap #5)

Thin request-reply layer on channels, no runtime change. A server is an
actor owning a GenServer state; clients hold a clonable ServerRef and issue
call (sync, parks for the reply) or cast (fire-and-forget).

- Single inbox carrying an internal Envelope { Call(req, reply_tx) | Cast },
  forced by the no-select / no-unified-mailbox invariant; call makes a
  one-shot reply channel and parks on it.
- Server-down detection is pure channel closure (no monitor): send fails if
  the inbox is gone; the reply sender drops on the server's unwind so a
  parked caller wakes to Err. Both collapse to CallError/CastError::ServerDown.
- init/terminate are optional trait hooks; terminate runs via a drop guard so
  it fires on every exit path (clean close, panic, request_stop). Must stay
  non-blocking — may run mid-unwind.
- ServerRef carries pid() for monitor/request_stop/link; start + start_under.

Tests: cast-then-call roundtrip, init/terminate ordering, both server-down
paths (reply-channel close on handler panic; inbox-send failure when gone).
This commit is contained in:
smarm-dev
2026-06-07 21:51:56 +00:00
parent 02f55fa0a0
commit 55221e9e98
3 changed files with 322 additions and 0 deletions
+2
View File
@@ -24,6 +24,7 @@ pub mod io;
pub mod mutex;
pub mod monitor;
pub mod link;
pub mod gen_server;
pub mod runtime;
pub mod trace;
@@ -39,6 +40,7 @@ static ALLOCATOR: preempt::PreemptingAllocator = preempt::PreemptingAllocator;
// ---------------------------------------------------------------------------
pub use channel::{channel, Receiver, RecvError, Sender};
pub use gen_server::{CallError, CastError, GenServer, ServerRef};
pub use link::{link, trap_exit, unlink, ExitSignal};
pub use monitor::{monitor, Down, DownReason};
pub use mutex::{LockTimeout, Mutex, MutexGuard};