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