ridl_rt/lib.rs
1//! The library that generated code links and a runtime implements.
2//!
3//! `ridl-rt` defines, once, the vocabulary that a package generated from ridl
4//! and a runtime agree on: identity, time and the envelope, samples, the
5//! payload traits, the interaction descriptors, the ports, and the contract and
6//! transport errors. It contains no runtime, but it carries the pure data
7//! structures every runtime would otherwise write alone, such as the
8//! [`correlate`] call table. A runtime is a separate crate that
9//! implements the traits of the `port` module (ADR-0020 decision 6), and
10//! generated code calls those traits without naming the runtime.
11//!
12//! With the `std` feature off — the default — the crate is `no_std` and
13//! allocates nothing; it contains no `unsafe` code and has no dependency in any
14//! feature combination. The cargo features `flatbuffers`,
15//! `proto3` and `repr-c` name the payload encodings. `flatbuffers` enables the
16//! [`flatbuffers`] module, the reading and writing a generated
17//! `Payload<FlatBuffers>` implementation shares; `proto3` and `repr-c` enable
18//! nothing in this version. A fourth feature, `std`, off by default, is not an
19//! encoding: it links the standard library and enables the [`task`] module —
20//! `block_on`, which waits on a future by parking the thread until a deadline,
21//! `noop_waker`, and `flag_waker`, whose wake sets a flag the caller reads —
22//! for a blocking client built over an async one and for a frame loop that
23//! polls a future once per frame, or again in the same frame when the future
24//! woke itself. `task` is the one module that links the standard library and
25//! allocates — one `Arc` per call of any of the three functions. Every other
26//! module stays `no_std` with the feature on.
27//!
28//! Every public item lives in one of eight modules, or in one of the two that
29//! the `flatbuffers` and `std` features add. Generated code names each
30//! item by its full path, for example `ridl_rt::sample::Sample`, and imports
31//! none, because several names here — `Duration`, `Handler`, `Kind` — are also
32//! names in `core` or in application code. The eighth module, [`face`], is the
33//! one whose items generated code implements rather than calls: the traits
34//! that carry the fixed methods of a generated `Client` and `Publisher` —
35//! `new`, `next_event`, `commit`, and under `std` `with_timeout` and
36//! `set_timeout` — so that a member of an interface may carry one of those
37//! names. A consumer of a generated face brings them into scope with
38//! `use <crate>::<iface>::prelude::*;` for each interface whose face it uses;
39//! each prelude brings the traits that interface's types implement, and
40//! rustc reports a prelude as an unused import when the other imported
41//! preludes already bring every item it would add.
42//!
43//! # Where to start
44//!
45//! Most of this crate is called by generated code, not by an application. An
46//! application implements one generated `Provider` trait and calls generated
47//! `Client` and `Publisher` methods; those methods call the ports here. So the
48//! shortest path in is to read one interaction kind at a time, from the
49//! generated side:
50//!
51//! | To do this | The generated face gives you | Over this port |
52//! | -------------------------------- | ---------------------------- | --------------------------------------------- |
53//! | Read a signal | `Client::<name>` | [`port::SignalReader`], returning [`sample::Sample`] |
54//! | Publish a signal | `Publisher::<name>`, `commit` | [`port::SignalWriter`] |
55//! | Receive an event | `Client::subscribe_<name>`, `Client::next_event` | [`port::EventSource`] |
56//! | Raise an event | `Publisher::<name>` | [`port::EventSink`] |
57//! | Call a command or a query | `Client::<name>`, returning the call's future | [`port::Caller`] |
58//! | Serve a command or a query | `Provider`, driven by the generated `serve` | [`port::Handler`] |
59//! | Read a provisioned constant | nothing yet — call the port | [`port::FixedReader`] |
60//!
61//! `docs/technotes/ridl-rt-by-example.md` in this repository walks that table
62//! from top to bottom against concrete generated code, introducing each type
63//! at the point where the generated code first needs it. The library's own
64//! as-built description is `docs/design/ridl-rt.md`.
65//!
66//! Two properties hold everywhere and are worth knowing before reading any
67//! individual item. **No port method waits** — every one returns immediately,
68//! and a call's outcome is retrieved separately through a
69//! [`port::Correlation`]. A face that waits registers its interest with the
70//! [`port::Wakeable`] extension, keyed by a [`port::Interest`], and reads the
71//! port again when the runtime wakes it; a runtime that serves a generated
72//! async client implements that extension. And **no port names a payload
73//! type** — ports carry interface numbers, ordinals and bytes, and the
74//! generated binding is what encodes and decodes, through [`payload::Ref`].
75//!
76//! A call made through the generated async client returns a named future,
77//! and the runtime keeps the call's outcome until the caller releases it. The
78//! future releases it: it calls [`port::Caller::forget`] when it leaves the
79//! waiting phase — in the poll that takes the outcome, at the call's deadline,
80//! and on drop while the call is still waiting — so a program over the
81//! generated face holds one slot per call in flight and forgets nothing by
82//! hand. A program that sends through [`port::Caller`] directly must call
83//! [`port::Caller::forget`] on a correlation once it has read the outcome;
84//! otherwise a runtime that bounds how many calls it holds at once refuses
85//! every call with [`port::SendError::Busy`] once that bound is reached.
86//!
87//! # How a runtime presents its ports
88//!
89//! A runtime crate exposes one handle type per port role it implements — a
90//! port role is one port trait — rather than one type implementing them all,
91//! and it may also offer an aggregate handle covering the port set one
92//! interface's face needs. A generated face is built over one value
93//! implementing at least the port traits its interface needs: the role handle
94//! itself when the face needs exactly one, and an aggregate — the runtime's,
95//! or one the application writes over role handles — when it needs more,
96//! because a generated `Client` may be bound over `SignalReader`,
97//! `EventSource` and `Caller` at once. Either value reaches the face by value
98//! or as a `&mut` borrow of itself, because every port trait is implemented
99//! for `&mut P` and the `&self`-only traits also for `&P`. In a runtime whose
100//! handles are used from more than one thread, a handle whose port traits all
101//! take `&self` is `Send + Sync`, because several threads may read one store
102//! at once, and a handle carrying a trait with a `&mut self` method is `Send`
103//! and need not be `Sync`, because one thread drives each. No port trait here
104//! carries `Send` or `Sync` as a supertrait, so a single-threaded `no_std`
105//! runtime whose handles use `Cell` or `RefCell` internally is held to
106//! neither; a runtime checks its own handles itself, with a compile-time
107//! assertion. ADR-0021 decision 12 records this.
108
109#![no_std]
110#![forbid(unsafe_code)]
111pub mod contract;
112pub mod correlate;
113pub mod encoding;
114pub mod error;
115pub mod face;
116#[cfg(feature = "flatbuffers")]
117pub mod flatbuffers;
118pub mod payload;
119pub mod port;
120pub mod sample;
121#[cfg(feature = "std")]
122pub mod task;
123
124/// Pins which enums stay `#[non_exhaustive]` under R-11: `Transport`,
125/// `ReadError`, `WriteError`, `RaiseError`, `SendError`, `SubscribeError`,
126/// `ServeError`, `SettleError`, `ClientError` and `ProviderError`. Each
127/// `compile_fail` block below matches every variant of one such enum, with
128/// no `_` arm. Matching a
129/// `#[non_exhaustive]` enum from outside its crate with no `_` arm does not
130/// compile, so a block fails until `#[non_exhaustive]` is removed from the
131/// enum it names.
132///
133/// ```compile_fail
134/// fn f(x: ridl_rt::error::Transport) {
135/// match x {
136/// ridl_rt::error::Transport::Timeout => {}
137/// ridl_rt::error::Transport::Undelivered => {}
138/// ridl_rt::error::Transport::Down => {}
139/// ridl_rt::error::Transport::Corrupt => {}
140/// ridl_rt::error::Transport::Busy => {}
141/// }
142/// }
143/// ```
144///
145/// ```compile_fail
146/// fn f(x: ridl_rt::port::ReadError) {
147/// match x {
148/// ridl_rt::port::ReadError::Short { .. } => {}
149/// ridl_rt::port::ReadError::ShortClaim { .. } => {}
150/// ridl_rt::port::ReadError::TooFewSamples { .. } => {}
151/// ridl_rt::port::ReadError::Contract(_) => {}
152/// ridl_rt::port::ReadError::Detached => {}
153/// }
154/// }
155/// ```
156///
157/// ```compile_fail
158/// fn f(x: ridl_rt::port::WriteError) {
159/// match x {
160/// ridl_rt::port::WriteError::TooLarge { .. } => {}
161/// ridl_rt::port::WriteError::NotOwner => {}
162/// ridl_rt::port::WriteError::Contract(_) => {}
163/// ridl_rt::port::WriteError::Detached => {}
164/// }
165/// }
166/// ```
167///
168/// ```compile_fail
169/// fn f(x: ridl_rt::port::RaiseError) {
170/// match x {
171/// ridl_rt::port::RaiseError::Busy => {}
172/// ridl_rt::port::RaiseError::TooLarge { .. } => {}
173/// ridl_rt::port::RaiseError::NotOwner => {}
174/// ridl_rt::port::RaiseError::Contract(_) => {}
175/// ridl_rt::port::RaiseError::Detached => {}
176/// }
177/// }
178/// ```
179///
180/// ```compile_fail
181/// fn f(x: ridl_rt::port::SendError) {
182/// match x {
183/// ridl_rt::port::SendError::Busy => {}
184/// ridl_rt::port::SendError::TooLarge { .. } => {}
185/// ridl_rt::port::SendError::Contract(_) => {}
186/// ridl_rt::port::SendError::Detached => {}
187/// }
188/// }
189/// ```
190///
191/// ```compile_fail
192/// fn f(x: ridl_rt::port::SubscribeError) {
193/// match x {
194/// ridl_rt::port::SubscribeError::Contract(_) => {}
195/// ridl_rt::port::SubscribeError::Detached => {}
196/// }
197/// }
198/// ```
199///
200/// ```compile_fail
201/// fn f(x: ridl_rt::port::ServeError) {
202/// match x {
203/// ridl_rt::port::ServeError::Contract(_) => {}
204/// ridl_rt::port::ServeError::NotOwner => {}
205/// ridl_rt::port::ServeError::Detached => {}
206/// }
207/// }
208/// ```
209///
210/// ```compile_fail
211/// fn f(x: ridl_rt::port::SettleError) {
212/// match x {
213/// ridl_rt::port::SettleError::UnknownClaim => {}
214/// ridl_rt::port::SettleError::TooLarge { .. } => {}
215/// ridl_rt::port::SettleError::Detached => {}
216/// }
217/// }
218/// ```
219///
220/// ```compile_fail
221/// fn f(x: ridl_rt::error::ClientError) {
222/// match x {
223/// ridl_rt::error::ClientError::Send(_) => {}
224/// ridl_rt::error::ClientError::Call(_) => {}
225/// ridl_rt::error::ClientError::Read(_) => {}
226/// }
227/// }
228/// ```
229///
230/// ```compile_fail
231/// fn f(x: ridl_rt::error::ProviderError) {
232/// match x {
233/// ridl_rt::error::ProviderError::Serve(_) => {}
234/// ridl_rt::error::ProviderError::Claim(_) => {}
235/// }
236/// }
237/// ```
238///
239/// The same ten matches, each with a `_` arm, compile: every path and every
240/// variant name above resolves, so a block above fails only because it names
241/// no `_` arm against a `#[non_exhaustive]` enum.
242///
243/// ```
244/// fn read_error(x: ridl_rt::port::ReadError) {
245/// match x {
246/// ridl_rt::port::ReadError::Short { .. } => {}
247/// ridl_rt::port::ReadError::ShortClaim { .. } => {}
248/// ridl_rt::port::ReadError::TooFewSamples { .. } => {}
249/// ridl_rt::port::ReadError::Contract(_) => {}
250/// ridl_rt::port::ReadError::Detached => {}
251/// _ => {}
252/// }
253/// }
254/// fn write_error(x: ridl_rt::port::WriteError) {
255/// match x {
256/// ridl_rt::port::WriteError::TooLarge { .. } => {}
257/// ridl_rt::port::WriteError::NotOwner => {}
258/// ridl_rt::port::WriteError::Contract(_) => {}
259/// ridl_rt::port::WriteError::Detached => {}
260/// _ => {}
261/// }
262/// }
263/// fn raise_error(x: ridl_rt::port::RaiseError) {
264/// match x {
265/// ridl_rt::port::RaiseError::Busy => {}
266/// ridl_rt::port::RaiseError::TooLarge { .. } => {}
267/// ridl_rt::port::RaiseError::NotOwner => {}
268/// ridl_rt::port::RaiseError::Contract(_) => {}
269/// ridl_rt::port::RaiseError::Detached => {}
270/// _ => {}
271/// }
272/// }
273/// fn send_error(x: ridl_rt::port::SendError) {
274/// match x {
275/// ridl_rt::port::SendError::Busy => {}
276/// ridl_rt::port::SendError::TooLarge { .. } => {}
277/// ridl_rt::port::SendError::Contract(_) => {}
278/// ridl_rt::port::SendError::Detached => {}
279/// _ => {}
280/// }
281/// }
282/// fn subscribe_error(x: ridl_rt::port::SubscribeError) {
283/// match x {
284/// ridl_rt::port::SubscribeError::Contract(_) => {}
285/// ridl_rt::port::SubscribeError::Detached => {}
286/// _ => {}
287/// }
288/// }
289/// fn serve_error(x: ridl_rt::port::ServeError) {
290/// match x {
291/// ridl_rt::port::ServeError::Contract(_) => {}
292/// ridl_rt::port::ServeError::NotOwner => {}
293/// ridl_rt::port::ServeError::Detached => {}
294/// _ => {}
295/// }
296/// }
297/// fn settle_error(x: ridl_rt::port::SettleError) {
298/// match x {
299/// ridl_rt::port::SettleError::UnknownClaim => {}
300/// ridl_rt::port::SettleError::TooLarge { .. } => {}
301/// ridl_rt::port::SettleError::Detached => {}
302/// _ => {}
303/// }
304/// }
305/// fn transport(x: ridl_rt::error::Transport) {
306/// match x {
307/// ridl_rt::error::Transport::Timeout => {}
308/// ridl_rt::error::Transport::Undelivered => {}
309/// ridl_rt::error::Transport::Down => {}
310/// ridl_rt::error::Transport::Corrupt => {}
311/// ridl_rt::error::Transport::Busy => {}
312/// _ => {}
313/// }
314/// }
315/// fn client_error(x: ridl_rt::error::ClientError) {
316/// match x {
317/// ridl_rt::error::ClientError::Send(_) => {}
318/// ridl_rt::error::ClientError::Call(_) => {}
319/// ridl_rt::error::ClientError::Read(_) => {}
320/// _ => {}
321/// }
322/// }
323/// fn provider_error(x: ridl_rt::error::ProviderError) {
324/// match x {
325/// ridl_rt::error::ProviderError::Serve(_) => {}
326/// ridl_rt::error::ProviderError::Claim(_) => {}
327/// _ => {}
328/// }
329/// }
330/// ```
331///
332/// `Contract` and `CallError` stay exhaustive under R-11: a match naming
333/// every variant, with no `_` arm, compiles.
334///
335/// ```
336/// fn contract(x: ridl_rt::error::Contract) {
337/// match x {
338/// ridl_rt::error::Contract::InvalidValue(_) => {}
339/// ridl_rt::error::Contract::PreconditionFailed => {}
340/// ridl_rt::error::Contract::ContractBroken => {}
341/// ridl_rt::error::Contract::UnknownInteraction => {}
342/// }
343/// }
344/// fn call_error(x: ridl_rt::error::CallError) {
345/// match x {
346/// ridl_rt::error::CallError::Contract(_) => {}
347/// ridl_rt::error::CallError::Transport(_) => {}
348/// }
349/// }
350/// ```
351///
352/// `port::Interest` is exhaustive too, because a runtime must handle every key
353/// (ADR-0021 decision 13): a match naming every key, with no `_` arm, compiles.
354///
355/// ```
356/// fn interest(x: ridl_rt::port::Interest) {
357/// match x {
358/// ridl_rt::port::Interest::Outcome(_) => {}
359/// ridl_rt::port::Interest::Slot => {}
360/// ridl_rt::port::Interest::Event(_) => {}
361/// ridl_rt::port::Interest::Claim(_) => {}
362/// }
363/// }
364/// ```
365#[cfg(doctest)]
366mod exhaustiveness {}