Skip to main content

ridl_rt/
port.rs

1//! The ports: the traits a runtime implements and generated code calls.
2//!
3//! Every port method returns without waiting. Waiting — blocking, `async`, or
4//! a loop that drives the runtime — belongs to a face over a port, and this
5//! crate defines no face. A port carries interface numbers, ordinals and
6//! bytes, never a payload type: the generated binding decodes. No port method
7//! takes the current time; a runtime reads its own [`Clock`].
8//!
9//! A port is attached to one catalog ([`Attached`]), and the interface numbers
10//! and ordinals its methods take are scoped by that catalog. A port type may
11//! also state the encoding of the bytes it carries ([`Encoded`]); no port in
12//! this crate's workspace implements it yet, and the generated face does not
13//! read it yet.
14//!
15//! [`ScannableSignals`] and [`CoherentSignals`] are extensions. They describe
16//! mechanisms some runtimes have, not interaction semantics every runtime must
17//! present, so a runtime may omit them. [`Wakeable`] is an extension too: it
18//! is how a face that waits learns when to read a port again, and a runtime
19//! that serves a generated async client implements it.
20//!
21//! Each trait below names the generated method it backs, so a reader who
22//! arrived from generated code can find the port under it. The crate-level
23//! documentation has the whole table, and
24//! `docs/technotes/ridl-rt-by-example.md` in this repository walks it against
25//! concrete generated code.
26
27use core::task::Waker;
28
29use crate::contract::{CatalogRef, InterfaceNo, Ordinal};
30use crate::encoding::Encoding;
31use crate::error::{CallError, Contract};
32use crate::sample::{Duration, Envelope, Freshness, Provenance, Timestamp};
33use crate::trace::TraceContext;
34
35/// A port attached to one catalog.
36pub trait Attached {
37    /// The catalog this port serves.
38    fn catalog(&self) -> &CatalogRef;
39}
40
41/// The payload encoding of the bytes a port carries.
42///
43/// One session has one encoding (the frame specification's rule); a
44/// transport that serves several encodings hands out one port type per
45/// session, each typed with its own. Each transport picks its default
46/// encoding from how coupled its two ends are, and the construction of the
47/// port can override it; this crate takes no position on the default.
48///
49/// A separate trait, not a supertrait of [`Attached`], so a port that never
50/// meets a face — a conformance fixture — is not forced to name an encoding.
51/// What is built is the trait and its forwarding implementation for
52/// `&mut P`: no port type in this crate's workspace implements it, and the
53/// generated face is written over the FlatBuffers codec and does not read a
54/// port's encoding. A face that takes its encoding from its port, so that a
55/// port whose encoding the package does not carry is refused at the binding,
56/// is tracked as driftsys/ridl#801.
57pub trait Encoded {
58    /// The encoding of the bytes this port carries.
59    type Encoding: Encoding;
60}
61
62/// The clock envelopes are stamped from. A runtime has one.
63pub trait Clock {
64    /// The current time in the platform time base.
65    fn now(&self) -> Timestamp;
66}
67
68/// Signals, consumer side.
69///
70/// A generated `Client` has one method per signal over this port. It reads
71/// into a stack buffer sized from the payload's
72/// [`MAX_SIZE`](crate::payload::Payload::MAX_SIZE), checks the bytes, and
73/// returns a [`Sample`](crate::sample::Sample). Bytes that fail their check
74/// are not an error there: the sample carries the channel's init value and a
75/// provenance of [`Invalid`](crate::sample::Provenance::Invalid), so the
76/// [`ReadError`] here reports the read itself.
77pub trait SignalReader: Attached {
78    /// Copies the signal's current value into the front of `out` and returns
79    /// its provenance, its freshness and its envelope. The runtime resolves
80    /// both the provenance and the freshness.
81    ///
82    /// A sample whose provenance is `Init` or `Invalid(Declared)` may carry
83    /// zero bytes, because the runtime has no value to copy; `len` is then 0,
84    /// and a generated face returns the channel's init value under that
85    /// provenance (ADR-0021 decision 17).
86    ///
87    /// Returns `ReadError::Short` when `out` is shorter than the value.
88    fn read(
89        &self,
90        iface: InterfaceNo,
91        ord: Ordinal,
92        out: &mut [u8],
93    ) -> Result<RawSample, ReadError>;
94}
95
96/// What [`SignalReader::read`] returns beside the copied bytes.
97#[derive(Clone, Copy, Debug, PartialEq, Eq)]
98pub struct RawSample {
99    /// Where the value comes from.
100    pub provenance: Provenance,
101    /// How old the value is.
102    pub freshness: Freshness,
103    /// The sender's timestamp and sequence number.
104    pub envelope: Envelope,
105    /// The number of bytes copied into `out`.
106    pub len: usize,
107}
108
109/// Signals, provider side.
110///
111/// `set`, `invalidate` and `touch` stage a change. Each fails with
112/// [`WriteError::Contract`] when the ordinal names no member, and with
113/// [`WriteError::NotOwner`] when it names a member this provider does not
114/// own. `commit` publishes every staged change, with one generation
115/// increment and one timestamp per interface, taken from the runtime's
116/// [`Clock`].
117///
118/// A generated `Publisher` has one method per signal over `set`, plus an
119/// `invalidate_<name>` and a `commit`. The staging split is why a provider
120/// that updates several signals of one interface and then commits produces one
121/// coherent publication rather than several.
122pub trait SignalWriter: Attached {
123    /// Stages a new value.
124    fn set(&mut self, iface: InterfaceNo, ord: Ordinal, bytes: &[u8]) -> Result<(), WriteError>;
125    /// Stages the invalid state (ridl §4.5), with
126    /// [`Cause::Declared`](crate::sample::Cause::Declared).
127    fn invalidate(&mut self, iface: InterfaceNo, ord: Ordinal) -> Result<(), WriteError>;
128    /// Stages a re-affirmation of the current value, without a new value.
129    fn touch(&mut self, iface: InterfaceNo, ord: Ordinal) -> Result<(), WriteError>;
130    /// Publishes everything staged. It cannot fail, so it reports nothing —
131    /// including that the runtime behind the port is gone. A caller learns
132    /// that from [`WriteError::Detached`] on a later `set`, `invalidate` or
133    /// `touch`, never from that `commit`. What becomes of the changes staged
134    /// before a commit whose runtime has already detached is not fixed here.
135    fn commit(&mut self);
136}
137
138/// Events, consumer side.
139///
140/// A generated `Client` has a `subscribe_<name>` per event, but a single
141/// `next_event` for the whole interface, because [`next`](EventSource::next)
142/// returns the next occurrence of anything subscribed and the payload type is
143/// not known until its ordinal has been read. The generated method routes on
144/// that ordinal into an enum with one variant per event.
145///
146/// # Trace context delivery
147///
148/// - A runtime that carries the trace context delivers, on every
149///   [`RawOccurrence`] a `raise` produces (one for each subscriber), the
150///   value its sender passed, unchanged.
151/// - A runtime or transport that does not carry the trace context delivers
152///   `None`.
153/// - A sender's `None` is delivered as `None`.
154pub trait EventSource: Attached {
155    /// Starts delivery of the listed events.
156    fn subscribe(&mut self, iface: InterfaceNo, ords: &[Ordinal]) -> Result<(), SubscribeError>;
157    /// Stops delivery of the listed events.
158    fn unsubscribe(&mut self, iface: InterfaceNo, ords: &[Ordinal]);
159    /// Copies the next occurrence into the front of `out`. `Ok(None)` when no
160    /// occurrence is waiting.
161    ///
162    /// Occurrences come in order, and a gap in `seq` is a loss (ridl §3.1). An
163    /// occurrence older than its time to live is discarded here (ridl §5.2).
164    /// `ReadError::Short` does not consume the occurrence: the next call
165    /// returns the same one.
166    fn next(&mut self, out: &mut [u8]) -> Result<Option<RawOccurrence>, ReadError>;
167}
168
169/// What [`EventSource::next`] returns beside the copied bytes.
170#[derive(Clone, Copy, Debug, PartialEq, Eq)]
171pub struct RawOccurrence {
172    /// The interface of the event.
173    pub iface: InterfaceNo,
174    /// The ordinal of the event.
175    pub ord: Ordinal,
176    /// The sender's timestamp and sequence number.
177    pub envelope: Envelope,
178    /// The trace context the sender passed to `raise`, or `None` (see the
179    /// delivery rules on [`EventSource`]).
180    pub trace: Option<TraceContext>,
181    /// The number of bytes copied into `out`.
182    pub len: usize,
183}
184
185/// Events, provider side.
186///
187/// A generated `Publisher` has one method per event over this port. Unlike a
188/// signal, an occurrence is not staged and there is no `commit`: there is no
189/// coherent set to assemble.
190///
191/// # Trace context delivery
192///
193/// - A runtime that carries the trace context delivers, on every
194///   [`RawOccurrence`] a `raise` produces (one for each subscriber), the
195///   value its sender passed, unchanged.
196/// - A runtime or transport that does not carry the trace context delivers
197///   `None`.
198/// - A sender's `None` is delivered as `None`.
199pub trait EventSink: Attached {
200    /// Raises one occurrence.
201    fn raise(
202        &mut self,
203        iface: InterfaceNo,
204        ord: Ordinal,
205        bytes: &[u8],
206        trace: Option<TraceContext>,
207    ) -> Result<(), RaiseError>;
208}
209
210/// Calls, consumer side.
211///
212/// A command and a query are separate methods, because their outcomes differ
213/// (ridl §6, §7).
214///
215/// A generated `Client` has one method per command and query over this port,
216/// each returning a named future rather than an outcome, because nothing
217/// here waits. The method sends when it is called; the future's `poll` reads
218/// the outcome — [`ack`](Caller::ack) for a command, [`reply`](Caller::reply)
219/// for a query — and calls [`forget`](Caller::forget) when it leaves the
220/// waiting phase. A `require` clause is evaluated before sending, so a
221/// failing precondition costs no round trip and is reported as
222/// [`SendError::Contract`].
223///
224/// # Trace context delivery
225///
226/// - A runtime that carries the trace context delivers, on the [`Claim`] a
227///   command or query produces, the value its sender passed, unchanged.
228/// - A runtime or transport that does not carry the trace context delivers
229///   `None`.
230/// - A sender's `None` is delivered as `None`.
231pub trait Caller: Attached {
232    /// Sends a command and returns the correlation of its outcome.
233    fn command(
234        &mut self,
235        iface: InterfaceNo,
236        ord: Ordinal,
237        args: &[u8],
238        trace: Option<TraceContext>,
239    ) -> Result<Correlation, SendError>;
240    /// Sends a query and returns the correlation of its reply.
241    fn query(
242        &mut self,
243        iface: InterfaceNo,
244        ord: Ordinal,
245        args: &[u8],
246        trace: Option<TraceContext>,
247    ) -> Result<Correlation, SendError>;
248    /// A command's delivery acknowledgment (ridl §6.1), once it is known:
249    /// `Ok(())` when accepted, `Err(CallError::Contract(_))` when rejected,
250    /// `Err(CallError::Transport(Transport::Corrupt))` when the provider could
251    /// not read the command's argument bytes,
252    /// `Err(CallError::Transport(Transport::Busy))` when the providing runtime
253    /// refused the command at admission, and
254    /// `Err(CallError::Transport(Transport::Undelivered))` when no
255    /// acknowledgment came within the bound. `None` while unknown, and always
256    /// `None` for a query's correlation.
257    ///
258    /// `None` has two causes this method does not separate: the acknowledgment
259    /// is not known yet, and `c` is a query's correlation, for which `None` is
260    /// the standing answer. A caller that polls `ack` for a query's
261    /// correlation therefore never finishes. The return carries no error, so
262    /// keep the correlations [`command`](Caller::command) returned and ask
263    /// only about those. After [`forget`](Caller::forget) a correlation's
264    /// outcome is no longer retrievable, so do not ask about it.
265    fn ack(&mut self, c: Correlation) -> Option<Result<(), CallError>>;
266    /// A query's reply, once it is known: the reply bytes copied into the front
267    /// of `out` and their length, or the error. `Ok(None)` while unknown.
268    /// `ReadError::Short` does not consume the reply.
269    ///
270    /// The outer [`ReadError`] reports the port call itself: `Short` when
271    /// `out` is too short, and `Detached` when the local runtime is gone.
272    /// `reply` never returns `ReadError::Contract`. The inner [`CallError`] is
273    /// the outcome from the peer or the transport, such as a contract error
274    /// the provider settled, or `Transport::Down` when the connection to the
275    /// peer is lost.
276    fn reply(
277        &mut self,
278        c: Correlation,
279        out: &mut [u8],
280    ) -> Result<Option<Result<usize, CallError>>, ReadError>;
281    /// Releases a correlation whose outcome the caller no longer needs.
282    fn forget(&mut self, c: Correlation);
283}
284
285/// Identifies one sent call to its caller.
286#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
287pub struct Correlation(pub u64);
288
289/// Calls, provider side.
290///
291/// `next_claim` presents each delivered call once. A retransmission of a call
292/// already presented is not presented again and receives the cached
293/// acknowledgment. Two calls are presented again. One is a claim a dropped
294/// handler held and did not settle: the runtime returns it to the waiting
295/// calls, so another handler that serves the member can take it, as many
296/// times as a holder is dropped (ADR-0021 decision 5). The other is a claim
297/// offered through [`ReadError::ShortClaim`], which stays the next call, under
298/// the same id, until it is read with a large enough buffer or settled by
299/// that id (decision 5, amended 2026-09-28). Calls from two callers are never
300/// merged, even when they carry the same `seq`. A call lost in transport is never presented. The
301/// caller of a lost command sees `Transport::Undelivered` from `Caller::ack`;
302/// the caller of a lost query sees `Transport::Timeout` from `Caller::reply`
303/// once the response bound passes.
304///
305/// Every claim is settled. For a command, the generated dispatch settles
306/// `Ok(&[])` after the arguments and `require` pass, before application code
307/// runs. For a query, it settles with the reply bytes or the outcome the
308/// caller sees.
309///
310/// An application implements neither this trait nor a claim loop. It
311/// implements the generated `Provider` trait and polls the future the
312/// generated `serve` returns, which on each poll makes one pass over the
313/// claims already waiting, routes each by ordinal, decodes, evaluates
314/// `require`, calls the provider, evaluates a query's `ensure`, and settles.
315/// That future resolves in two cases only: at once, when this port's `serve`
316/// refused the members, and later, when this port fails.
317///
318/// # Trace context delivery
319///
320/// - A runtime that carries the trace context delivers, on the [`Claim`] a
321///   command or query produces, the value its sender passed, unchanged. The
322///   same holds for the `trace` field of [`ReadError::ShortClaim`], which
323///   reports that claim before its arguments are read.
324/// - A runtime or transport that does not carry the trace context delivers
325///   `None`.
326/// - A sender's `None` is delivered as `None`.
327pub trait Handler: Attached {
328    /// Starts presenting calls to the listed members.
329    fn serve(&mut self, iface: InterfaceNo, ords: &[Ordinal]) -> Result<(), ServeError>;
330    /// Copies the next call's arguments into the front of `out`. `Ok(None)`
331    /// when no call is waiting. When `out` is shorter than the next call's
332    /// arguments, returns [`ReadError::ShortClaim`] with that call's
333    /// `ClaimId` and the bytes it needs, and does not consume the call: a
334    /// later `next_claim` with a buffer of at least `needed` bytes presents
335    /// the same call under the same id. The id is assigned when the call is
336    /// first presented, whether through `ShortClaim` or through `Ok(Some)`,
337    /// and is unique in its channel. `next_claim` never returns
338    /// `ReadError::Short`.
339    fn next_claim(&mut self, out: &mut [u8]) -> Result<Option<Claim>, ReadError>;
340    /// Settles a claim with the reply bytes (empty for a command) or the
341    /// outcome the caller sees. A provider settles
342    /// [`CallError::Contract`] when the arguments break their typl
343    /// constraints, a `require` clause fails, or an `ensure` clause fails,
344    /// and `CallError::Transport(Transport::Corrupt)` when the argument
345    /// bytes fail the structure check.
346    ///
347    /// A claim presented through [`ReadError::ShortClaim`] is settled the
348    /// same way, with any outcome, although its arguments were never read:
349    /// `settle` does not distinguish a read claim from an unread one. The
350    /// settlement takes the call out of the waiting calls, so a later
351    /// `next_claim` does not present it.
352    fn settle(
353        &mut self,
354        claim: ClaimId,
355        outcome: Result<&[u8], CallError>,
356    ) -> Result<(), SettleError>;
357}
358
359/// One call presented to a provider.
360#[derive(Clone, Copy, Debug, PartialEq, Eq)]
361pub struct Claim {
362    /// Unique in its channel.
363    pub id: ClaimId,
364    /// The interface of the call.
365    pub iface: InterfaceNo,
366    /// The ordinal of the call. The descriptor at this ordinal gives the kind.
367    pub ord: Ordinal,
368    /// The caller's timestamp and sequence number. `seq` is unique for each
369    /// caller, not for each channel.
370    pub envelope: Envelope,
371    /// The trace context the sender passed to `command` or `query`, or `None`
372    /// (see the delivery rules on [`Handler`]).
373    pub trace: Option<TraceContext>,
374    /// The time left before the response bound passes. `None` when the call
375    /// has no response bound, as in a catalog built before commands and queries
376    /// took a default one (ridl §9.3).
377    pub remaining: Option<Duration>,
378    /// The number of argument bytes copied into `out`.
379    pub len: usize,
380}
381
382/// Identifies one claim to its provider.
383#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
384pub struct ClaimId(pub u64);
385
386/// `fixed`, consumer side (ridl §8).
387///
388/// The generated face carries no method over this port in this version: a
389/// `fixed` is provisioned rather than interacted with, so the emitter writes
390/// its descriptor and nothing else, and an application that needs a
391/// provisioned value calls [`read_fixed`](FixedReader::read_fixed) itself.
392/// There is no provider side either — a provisioned constant is supplied to
393/// the runtime, not published by application code.
394pub trait FixedReader: Attached {
395    /// Copies the provisioned value into the front of `out` and returns its
396    /// length.
397    fn read_fixed(
398        &self,
399        iface: InterfaceNo,
400        ord: Ordinal,
401        out: &mut [u8],
402    ) -> Result<usize, ReadError>;
403}
404
405/// Extension: signals in a store a consumer can walk. A runtime may omit it.
406pub trait ScannableSignals: SignalReader {
407    /// The interface's generation: a counter that each commit to the interface
408    /// increments.
409    ///
410    /// The return carries no error, so an interface the port's catalog does
411    /// not hold has no reserved answer: it gives a `u64` the caller cannot
412    /// tell from a real generation. Ask only about an interface of
413    /// [`catalog`](Attached::catalog).
414    fn generation(&self, iface: InterfaceNo) -> u64;
415    /// Writes the changes into `out`, interface by interface, in the order of
416    /// `marks`, and updates `marks`. An interface's changes are written all
417    /// together or not at all: when they do not fit in the rest of `out`,
418    /// none of them is written, that interface's mark is not updated, and
419    /// `scan` returns the number of entries written so far.
420    ///
421    /// The count alone does not say whether changes are still waiting, because
422    /// a return of 0 has two causes. To tell them apart, compare each mark
423    /// with its interface's [`generation`](ScannableSignals::generation) after
424    /// the call:
425    ///
426    /// - every mark's `generation` equals `generation(iface)` — nothing had
427    ///   changed, and the scan is complete;
428    /// - some mark's `generation` is behind `generation(iface)` — that
429    ///   interface's changes did not fit in `out`. When `scan` also returned
430    ///   0, `out` is shorter than the changes of the first such interface in
431    ///   the order of `marks`, and no call can make progress until `out` is
432    ///   longer.
433    ///
434    /// A caller that scans in a loop therefore grows `out` when `scan` returns
435    /// 0 and a mark is still behind its interface's generation.
436    fn scan(&self, marks: &mut [Watermark], out: &mut [Changed]) -> usize;
437}
438
439/// How far a consumer has scanned one interface.
440#[derive(Clone, Copy, Debug, PartialEq, Eq)]
441pub struct Watermark {
442    /// The interface.
443    pub iface: InterfaceNo,
444    /// The generation last scanned. Named `generation`, not `gen`, because
445    /// `gen` is a reserved keyword in the 2024 edition.
446    pub generation: u64,
447    /// The sequence number last scanned.
448    pub seq: u64,
449}
450
451/// A signal that changed since a [`Watermark`].
452#[derive(Clone, Copy, Debug, PartialEq, Eq)]
453pub struct Changed {
454    /// The interface of the signal.
455    pub iface: InterfaceNo,
456    /// The ordinal of the signal.
457    pub ord: Ordinal,
458    /// The signal's sequence number.
459    pub seq: u64,
460}
461
462/// Extension: reads of several signals of one interface from one publication.
463/// A runtime whose binding delivers each field separately cannot present this
464/// and omits it.
465pub trait CoherentSignals: SignalReader {
466    /// Answers every ordinal in `ords` from one publication. Copies the values
467    /// into `out` one after another, writes one `RawSample` for each ordinal
468    /// into `samples` in the order of `ords`, and returns the number of bytes
469    /// written to `out`.
470    ///
471    /// Returns `ReadError::Short` with the size the whole set needs when `out`
472    /// is too short, `ReadError::TooFewSamples` with the number of entries
473    /// `samples` needs when `samples` is shorter than `ords`, and
474    /// `ReadError::Contract(Contract::UnknownInteraction)` when an ordinal
475    /// names no member.
476    fn read_coherent(
477        &self,
478        iface: InterfaceNo,
479        ords: &[Ordinal],
480        out: &mut [u8],
481        samples: &mut [RawSample],
482    ) -> Result<usize, ReadError>;
483}
484
485/// Extension: a port that can wake a task. A runtime that serves a generated
486/// async client implements it.
487///
488/// No port method waits, so a task registers its interest here, reads the
489/// port, and returns when the read finds nothing; the runtime wakes the task
490/// when the thing it waits for may have changed, and the task reads the port
491/// again.
492///
493/// The contract:
494///
495/// - **One waker per kind of key per handle.** [`wake_on`](Wakeable::wake_on)
496///   stores a clone of `waker` on the handle it is called on, one for each
497///   kind — `Slot`, `Event`, `Claim` — and an `Outcome` waker with its call.
498///   A change to any key of that kind that the handle observes wakes the
499///   stored waker, so a task that registers `Event(a)` and then `Event(b)` is
500///   woken by an occurrence of either; the task reads the port again and
501///   finds out which.
502/// - **A refresh or a displacement.** A `wake_on` whose waker
503///   [`will_wake`](Waker::will_wake) the stored one is a refresh:
504///   it replaces the stored waker without waking it, because a task
505///   registers on every poll and waking it for its own registration would
506///   schedule the next poll from every poll. A waker of another task
507///   displaces the stored one, and the displaced waker is woken, so no task
508///   waits on a registration that can no longer fire. A second task waiting
509///   for the same events holds a second handle, and each handle's waiter is
510///   woken.
511/// - **Woken at most once.** A stored waker is woken after every change of
512///   its kind becomes visible, and is cleared when woken. A spurious wake is
513///   allowed: a runtime with one unkeyed "something changed" source may wake
514///   every waiter it holds on any change.
515/// - **Register, then read.** The caller registers on every poll, and
516///   registers before it reads the port, so a change between the read and
517///   the return still wakes it.
518///
519/// [`Interest::Event`] and [`Interest::Claim`] are keyed per interface,
520/// because [`EventSource::next`] and [`Handler::next_claim`] drain one queue
521/// whatever the ordinal, and the subscription and the served set already
522/// filter by member.
523pub trait Wakeable {
524    /// Wakes `waker` when the thing `what` names may have changed, under the
525    /// contract above.
526    fn wake_on(&self, what: Interest, waker: &Waker);
527}
528
529/// What a task waits for, as [`Wakeable::wake_on`] takes it.
530///
531/// Exhaustive: a runtime handles every key, because an unknown key has no
532/// safe default. Ignoring it leaves the waiter waiting, and waking it at once
533/// makes a busy loop. A new key is a 0.x minor (ADR-0021 decision 13).
534#[derive(Clone, Copy, Debug, PartialEq, Eq)]
535pub enum Interest {
536    /// The outcome of one call is known.
537    Outcome(Correlation),
538    /// A slot for a new call is free.
539    Slot,
540    /// An occurrence of one of the interface's events is waiting.
541    Event(InterfaceNo),
542    /// A claim on one of the interface's members is waiting.
543    Claim(InterfaceNo),
544}
545
546/// A read that failed.
547///
548/// One enum serves every read on every port, so a variant can be unreachable
549/// for the method that returns it: [`TooFewSamples`](ReadError::TooFewSamples)
550/// belongs to [`CoherentSignals::read_coherent`] alone, and
551/// [`Caller::reply`] never returns [`Contract`](ReadError::Contract). Each
552/// method documents what it can return.
553#[non_exhaustive]
554#[derive(Clone, Copy, Debug, PartialEq, Eq)]
555pub enum ReadError {
556    /// The output buffer is too short. Nothing was consumed.
557    Short {
558        /// The bytes the read needs.
559        needed: usize,
560    },
561    /// The output buffer is too short for the next claim's arguments
562    /// ([`Handler::next_claim`] alone). Nothing was consumed: the claim stays
563    /// the next one, and a later `next_claim` with a buffer of at least
564    /// `needed` bytes presents it under the same `claim`. The id is reported
565    /// so that a provider can settle the claim without reading its
566    /// arguments; the generated `serve` settles it
567    /// `CallError::Transport(Transport::Corrupt)`, because an argument that
568    /// does not fit the serving interface's `MAX_BUFFER_SIZE` — its largest
569    /// argument or reply payload, larger than any valid encoding of its
570    /// members — is not a well-formed encoding of one; a claim naming another
571    /// interface may be validly larger, and is settled the same, because the
572    /// serving step cannot read it (ADR-0021 decision 5, amended
573    /// 2026-09-28).
574    ShortClaim {
575        /// The claim whose arguments did not fit.
576        claim: ClaimId,
577        /// The bytes the read needs.
578        needed: usize,
579        /// The trace context the sender passed to `command` or `query`, or
580        /// `None`, under the delivery rules on [`Handler`] that apply to
581        /// [`Claim::trace`]. A provider that settles the claim without
582        /// reading it has the context here.
583        trace: Option<TraceContext>,
584    },
585    /// `samples` has fewer entries than `ords`. Nothing was consumed.
586    TooFewSamples {
587        /// The entries `samples` needs.
588        needed: usize,
589    },
590    /// A contract error, such as an unknown interaction.
591    Contract(Contract),
592    /// The runtime behind the port is gone.
593    Detached,
594}
595
596/// A [`SignalWriter::set`], [`SignalWriter::invalidate`] or
597/// [`SignalWriter::touch`] that failed.
598#[non_exhaustive]
599#[derive(Clone, Copy, Debug, PartialEq, Eq)]
600pub enum WriteError {
601    /// The value is larger than the signal's capacity.
602    TooLarge {
603        /// The capacity in bytes.
604        cap: usize,
605    },
606    /// This provider does not own the signal.
607    NotOwner,
608    /// A contract error, such as an unknown interaction.
609    Contract(Contract),
610    /// The runtime behind the port is gone.
611    Detached,
612}
613
614/// An [`EventSink::raise`] that failed.
615#[non_exhaustive]
616#[derive(Clone, Copy, Debug, PartialEq, Eq)]
617pub enum RaiseError {
618    /// The runtime cannot accept an occurrence now. Retryable.
619    Busy,
620    /// The occurrence is larger than the event's capacity.
621    TooLarge {
622        /// The capacity in bytes.
623        cap: usize,
624    },
625    /// This provider does not own the event.
626    NotOwner,
627    /// A contract error, such as an unknown interaction.
628    Contract(Contract),
629    /// The runtime behind the port is gone.
630    Detached,
631}
632
633/// A [`Caller::command`] or [`Caller::query`] that failed before sending.
634#[non_exhaustive]
635#[derive(Clone, Copy, Debug, PartialEq, Eq)]
636pub enum SendError {
637    /// The runtime cannot accept a call now. Retryable.
638    Busy,
639    /// The arguments are larger than the call's capacity.
640    TooLarge {
641        /// The capacity in bytes.
642        cap: usize,
643    },
644    /// A contract error, such as an unknown interaction.
645    Contract(Contract),
646    /// The runtime behind the port is gone.
647    Detached,
648}
649
650/// An [`EventSource::subscribe`] that failed.
651#[non_exhaustive]
652#[derive(Clone, Copy, Debug, PartialEq, Eq)]
653pub enum SubscribeError {
654    /// A contract error: an unknown interaction fails when subscribing (ridl
655    /// §10.2).
656    Contract(Contract),
657    /// The runtime behind the port is gone.
658    Detached,
659}
660
661/// A [`Handler::serve`] that failed.
662#[non_exhaustive]
663#[derive(Clone, Copy, Debug, PartialEq, Eq)]
664pub enum ServeError {
665    /// A contract error, such as an unknown interaction.
666    Contract(Contract),
667    /// This provider does not own the call.
668    NotOwner,
669    /// The runtime behind the port is gone.
670    Detached,
671}
672
673/// A [`Handler::settle`] that failed.
674#[non_exhaustive]
675#[derive(Clone, Copy, Debug, PartialEq, Eq)]
676pub enum SettleError {
677    /// The claim was already settled, or was never issued.
678    UnknownClaim,
679    /// The reply is larger than the call's capacity.
680    TooLarge {
681        /// The capacity in bytes.
682        cap: usize,
683    },
684    /// The runtime behind the port is gone.
685    Detached,
686}
687
688// Forwarding impls (ADR-0021 decision 11).
689//
690// Every port trait above is implemented for `&mut P`, and the seven whose
691// methods all take `&self` — `Attached`, `Clock`, `SignalReader`,
692// `FixedReader`, `ScannableSignals`, `CoherentSignals` and `Wakeable` — also
693// for `&P`.
694// What they buy is one thing: a value generic over a port trait, such as a
695// generated face, can be built over a reference to a port rather than over the
696// port itself. A wrapper that adds tracing and a test double are accepted by
697// such a bound with or without them, because each implements the port traits
698// itself.
699//
700// `impl<P: T + ?Sized> T for Box<P>` is deferred: it needs `alloc`, which only
701// the `std` feature brings in, and nothing needs a boxed port (ADR-0021 open
702// question 5).
703
704impl<P: Attached + ?Sized> Attached for &P {
705    fn catalog(&self) -> &CatalogRef {
706        (**self).catalog()
707    }
708}
709
710impl<P: Attached + ?Sized> Attached for &mut P {
711    fn catalog(&self) -> &CatalogRef {
712        (**self).catalog()
713    }
714}
715
716impl<P: Encoded + ?Sized> Encoded for &mut P {
717    type Encoding = P::Encoding;
718}
719
720impl<P: Clock + ?Sized> Clock for &P {
721    fn now(&self) -> Timestamp {
722        (**self).now()
723    }
724}
725
726impl<P: Clock + ?Sized> Clock for &mut P {
727    fn now(&self) -> Timestamp {
728        (**self).now()
729    }
730}
731
732impl<P: SignalReader + ?Sized> SignalReader for &P {
733    fn read(
734        &self,
735        iface: InterfaceNo,
736        ord: Ordinal,
737        out: &mut [u8],
738    ) -> Result<RawSample, ReadError> {
739        (**self).read(iface, ord, out)
740    }
741}
742
743impl<P: SignalReader + ?Sized> SignalReader for &mut P {
744    fn read(
745        &self,
746        iface: InterfaceNo,
747        ord: Ordinal,
748        out: &mut [u8],
749    ) -> Result<RawSample, ReadError> {
750        (**self).read(iface, ord, out)
751    }
752}
753
754impl<P: SignalWriter + ?Sized> SignalWriter for &mut P {
755    fn set(&mut self, iface: InterfaceNo, ord: Ordinal, bytes: &[u8]) -> Result<(), WriteError> {
756        (**self).set(iface, ord, bytes)
757    }
758    fn invalidate(&mut self, iface: InterfaceNo, ord: Ordinal) -> Result<(), WriteError> {
759        (**self).invalidate(iface, ord)
760    }
761    fn touch(&mut self, iface: InterfaceNo, ord: Ordinal) -> Result<(), WriteError> {
762        (**self).touch(iface, ord)
763    }
764    fn commit(&mut self) {
765        (**self).commit();
766    }
767}
768
769impl<P: EventSource + ?Sized> EventSource for &mut P {
770    fn subscribe(&mut self, iface: InterfaceNo, ords: &[Ordinal]) -> Result<(), SubscribeError> {
771        (**self).subscribe(iface, ords)
772    }
773    fn unsubscribe(&mut self, iface: InterfaceNo, ords: &[Ordinal]) {
774        (**self).unsubscribe(iface, ords);
775    }
776    fn next(&mut self, out: &mut [u8]) -> Result<Option<RawOccurrence>, ReadError> {
777        (**self).next(out)
778    }
779}
780
781impl<P: EventSink + ?Sized> EventSink for &mut P {
782    fn raise(
783        &mut self,
784        iface: InterfaceNo,
785        ord: Ordinal,
786        bytes: &[u8],
787        trace: Option<TraceContext>,
788    ) -> Result<(), RaiseError> {
789        (**self).raise(iface, ord, bytes, trace)
790    }
791}
792
793impl<P: Caller + ?Sized> Caller for &mut P {
794    fn command(
795        &mut self,
796        iface: InterfaceNo,
797        ord: Ordinal,
798        args: &[u8],
799        trace: Option<TraceContext>,
800    ) -> Result<Correlation, SendError> {
801        (**self).command(iface, ord, args, trace)
802    }
803    fn query(
804        &mut self,
805        iface: InterfaceNo,
806        ord: Ordinal,
807        args: &[u8],
808        trace: Option<TraceContext>,
809    ) -> Result<Correlation, SendError> {
810        (**self).query(iface, ord, args, trace)
811    }
812    fn ack(&mut self, c: Correlation) -> Option<Result<(), CallError>> {
813        (**self).ack(c)
814    }
815    fn reply(
816        &mut self,
817        c: Correlation,
818        out: &mut [u8],
819    ) -> Result<Option<Result<usize, CallError>>, ReadError> {
820        (**self).reply(c, out)
821    }
822    fn forget(&mut self, c: Correlation) {
823        (**self).forget(c);
824    }
825}
826
827impl<P: Handler + ?Sized> Handler for &mut P {
828    fn serve(&mut self, iface: InterfaceNo, ords: &[Ordinal]) -> Result<(), ServeError> {
829        (**self).serve(iface, ords)
830    }
831    fn next_claim(&mut self, out: &mut [u8]) -> Result<Option<Claim>, ReadError> {
832        (**self).next_claim(out)
833    }
834    fn settle(
835        &mut self,
836        claim: ClaimId,
837        outcome: Result<&[u8], CallError>,
838    ) -> Result<(), SettleError> {
839        (**self).settle(claim, outcome)
840    }
841}
842
843impl<P: FixedReader + ?Sized> FixedReader for &P {
844    fn read_fixed(
845        &self,
846        iface: InterfaceNo,
847        ord: Ordinal,
848        out: &mut [u8],
849    ) -> Result<usize, ReadError> {
850        (**self).read_fixed(iface, ord, out)
851    }
852}
853
854impl<P: FixedReader + ?Sized> FixedReader for &mut P {
855    fn read_fixed(
856        &self,
857        iface: InterfaceNo,
858        ord: Ordinal,
859        out: &mut [u8],
860    ) -> Result<usize, ReadError> {
861        (**self).read_fixed(iface, ord, out)
862    }
863}
864
865impl<P: ScannableSignals + ?Sized> ScannableSignals for &P {
866    fn generation(&self, iface: InterfaceNo) -> u64 {
867        (**self).generation(iface)
868    }
869    fn scan(&self, marks: &mut [Watermark], out: &mut [Changed]) -> usize {
870        (**self).scan(marks, out)
871    }
872}
873
874impl<P: ScannableSignals + ?Sized> ScannableSignals for &mut P {
875    fn generation(&self, iface: InterfaceNo) -> u64 {
876        (**self).generation(iface)
877    }
878    fn scan(&self, marks: &mut [Watermark], out: &mut [Changed]) -> usize {
879        (**self).scan(marks, out)
880    }
881}
882
883impl<P: CoherentSignals + ?Sized> CoherentSignals for &P {
884    fn read_coherent(
885        &self,
886        iface: InterfaceNo,
887        ords: &[Ordinal],
888        out: &mut [u8],
889        samples: &mut [RawSample],
890    ) -> Result<usize, ReadError> {
891        (**self).read_coherent(iface, ords, out, samples)
892    }
893}
894
895impl<P: CoherentSignals + ?Sized> CoherentSignals for &mut P {
896    fn read_coherent(
897        &self,
898        iface: InterfaceNo,
899        ords: &[Ordinal],
900        out: &mut [u8],
901        samples: &mut [RawSample],
902    ) -> Result<usize, ReadError> {
903        (**self).read_coherent(iface, ords, out, samples)
904    }
905}
906
907impl<P: Wakeable + ?Sized> Wakeable for &P {
908    fn wake_on(&self, what: Interest, waker: &Waker) {
909        (**self).wake_on(what, waker);
910    }
911}
912
913impl<P: Wakeable + ?Sized> Wakeable for &mut P {
914    fn wake_on(&self, what: Interest, waker: &Waker) {
915        (**self).wake_on(what, waker);
916    }
917}