Skip to main content

weida_runtime/
lib.rs

1//! The reactor, the resolver and the OS plumbing a messaging library needs,
2//! with no protocol in it.
3//!
4//! This crate is the answer to one question asked twice: *where does the
5//! async runtime live?* A library that opens sockets needs tasks, timers and
6//! name resolution, and its users must not have to be standing in a reactor
7//! to call it. Everything here exists so that a library can own that reactor
8//! instead of demanding one, and so that the same discipline does not have to
9//! be written twice for two protocols
10//! ([decisions/0013](../../../docs/decisions/0013-competitor-libraries.md)
11//! §4.2).
12//!
13//! Nothing in this crate knows a wire format. It depends on `weida-core` for
14//! one error vocabulary and on `tokio` for the reactor, and on nothing else;
15//! it MUST NOT depend on `weida-protocol` or `weida`. A consumer with no
16//! weida in the picture — a ZeroMQ or nanomsg implementation, say — is the
17//! case every doc comment here is written for.
18//!
19//! # What is here
20//!
21//! - [`Exec`] — the *whole* surface onto the async runtime: [`Exec::spawn`],
22//!   [`Exec::sleep`], [`Exec::within`], [`Exec::enter`] and
23//!   [`Exec::resolve`]. A consumer holds one and never touches `tokio`
24//!   directly, which is what makes "our library works on any executor" a
25//!   checkable claim rather than an intention.
26//! - Three ways to get one, differing only in where the reactor comes from:
27//!   [`Exec::current`] borrows the ambient reactor, [`Exec::from_handle`]
28//!   takes a handle to somebody else's, and [`Exec::owned`] creates one and
29//!   hands back the [`OwnedReactor`] that owns it — with the
30//!   background-shutdown discipline that dropping a reactor from inside its
31//!   own worker thread requires.
32//! - [`CloseBudget`] — a finite budget spanning the phases of a shutdown, so
33//!   that no close waits on a peer's behaviour forever. ZeroMQ's
34//!   `ZMQ_LINGER` defaults to infinite and `zmq_ctx_term()` can therefore
35//!   block for as long as a peer likes; this type is what a finite default
36//!   is built from.
37//! - [`NameRegistry`] — a process- or context-scoped namespace of bound
38//!   names with a byte budget, generic over what a bound name hands its
39//!   acceptor. weida's `weida+inproc://` buses and ZeroMQ's `inproc://`
40//!   endpoints are the same object under two names.
41//! - On unix: `BoundUnixSocket`, which binds an `AF_UNIX` socket with the
42//!   hygiene a filesystem endpoint needs — socket-type check, unlink before
43//!   bind, an explicit mode rather than whatever `umask` allowed, a
44//!   `sun_path` budget, and removal of the node on drop — and
45//!   `peer_credentials`, the kernel's answer to *who is on the other end*
46//!   ([decisions/0010](../../../docs/decisions/0010-local-transport.md)
47//!   §4.5).
48//! - On Windows: `BoundPipe`, which creates the instances of a named pipe
49//!   with an owner-only DACL, local clients only and the first-instance
50//!   flag, `connect_pipe`, which opens the client end and waits out
51//!   `ERROR_PIPE_BUSY`, and `client_principal` / `server_principal`, the
52//!   kernel's answer to the same question in SID form (0010 §4.4, §4.5).
53//!
54//! # The grep
55//!
56//! `Exec` is the enforcement point, and the enforcement is mechanical. Two
57//! greps, one per crate:
58//!
59//! ```text
60//! grep -rn 'tokio::spawn\|tokio::time\|lookup_host' crates/weida/src   # no call outside #[cfg(test)]
61//! grep -rn 'tokio::spawn\|tokio::time\|lookup_host' crates/runtime/src # only exec.rs calls them
62//! ```
63//!
64//! Every task, timer and name lookup in `weida` goes through an `Exec` from
65//! this crate, and the same grep over a consumer's own `src` is the same
66//! check for it (`docs/ARCHITECTURE.md` §5). The one place those three names
67//! are allowed to appear is [`Exec`]'s own module, which is the entire point
68//! of moving them here.
69
70mod budget;
71mod exec;
72#[cfg(windows)]
73mod pipe;
74mod registry;
75mod resolve;
76#[cfg(unix)]
77mod unix;
78
79pub use budget::CloseBudget;
80pub use exec::{Exec, OwnedReactor};
81#[cfg(windows)]
82pub use pipe::{BoundPipe, client_principal, connect_pipe, server_principal};
83pub use registry::NameRegistry;
84pub use resolve::{Resolved, Resolver, SharedResolver, SystemResolver};
85#[cfg(unix)]
86pub use unix::{BoundUnixSocket, peer_credentials};