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