Skip to main content

behavior/effects/
sending.rs

1//! Typed send effects, their composition contract, and event ownership.
2
3use crate::{
4    Behavior, BirthProtocol, BirthProtocolProduct, ChildDelivery, ChildInput, ComposedEvent,
5    Delivery, EndpointAddress, EstablishedDelivery, InjectEvent, Inside, NoBirthProtocols,
6    Protocol,
7};
8use core::future::Future;
9
10/// Total settlement of one statically selected action item.
11///
12/// Rejection and dependency blocking retain the complete original item.
13/// Interpreter corruption does the same. Accepted items are consumed and leave
14/// only the capability's promised receipt. Whether an item was attempted at all
15/// belongs to [`SettledItem`], so a concrete interpreter cannot fabricate that
16/// product-level fact.
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub enum ItemSettlement<Item, Accepted, Rejection, Prerequisite> {
19    /// The capability consumed the item and returned its promised receipt.
20    Accepted(Accepted),
21    /// The capability lawfully rejected the complete item.
22    Rejected { item: Item, reason: Rejection },
23    /// A declared prerequisite did not commit, so the item remains untouched.
24    Blocked {
25        item: Item,
26        prerequisite: Prerequisite,
27    },
28    /// The interpreter violated its contract while the item remained owned.
29    Corrupt { item: Item, fault: InterpreterFault },
30}
31
32/// Product-owned evidence that an action item was attempted or left untouched.
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34pub enum SettledItem<Item, Settlement> {
35    /// The concrete interpreter returned the item's complete settlement.
36    Attempted(Settlement),
37    /// Product traversal stopped at an earlier corrupt item.
38    Unattempted(Item),
39}
40
41/// Completion state of one total static product traversal.
42///
43/// Both variants own the complete settlement shape. `Corrupt` contains the
44/// factual committed prefix, the exact corrupt item, and every later item as
45/// [`SettledItem::Unattempted`].
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47pub enum Interpretation<Settlement> {
48    Complete(Settlement),
49    Corrupt(Settlement),
50}
51
52impl<Settlement> Interpretation<Settlement> {
53    /// Transform the complete settlement shape without changing whether the
54    /// interpreter completed or corrupted.
55    #[must_use]
56    pub fn map<Mapped>(self, map: impl FnOnce(Settlement) -> Mapped) -> Interpretation<Mapped> {
57        match self {
58            Self::Complete(settlement) => Interpretation::Complete(map(settlement)),
59            Self::Corrupt(settlement) => Interpretation::Corrupt(map(settlement)),
60        }
61    }
62
63    /// Recover the complete owned settlement shape.
64    #[must_use]
65    pub fn into_settlement(self) -> Settlement {
66        match self {
67            Self::Complete(settlement) | Self::Corrupt(settlement) => settlement,
68        }
69    }
70}
71
72/// Interpret two statically named send products in declared order.
73///
74/// A corrupt earlier product retains the complete later product as
75/// unattempted. Expected rejection inside the earlier product does not stop
76/// the later product because it remains a complete interpretation.
77#[doc(hidden)]
78pub async fn settle_in_order<Interpreter, RootEvent, Path, Earlier, Later>(
79    earlier: Earlier,
80    later: Later,
81    interpreter: &mut Interpreter,
82) -> Interpretation<(Earlier::Settlements, Later::Settlements)>
83where
84    Interpreter: Send,
85    Earlier: InterpretSends<Interpreter, RootEvent, Path>,
86    Later: InterpretSends<Interpreter, RootEvent, Path>,
87{
88    let earlier = match earlier.interpret(interpreter).await {
89        Interpretation::Complete(earlier) => earlier,
90        Interpretation::Corrupt(earlier) => {
91            return Interpretation::Corrupt((earlier, later.unattempted()));
92        }
93    };
94    later
95        .interpret(interpreter)
96        .await
97        .map(|later| (earlier, later))
98}
99
100/// Read-only control-flow status of one complete retained settlement product.
101#[derive(Clone, Copy, Debug, Eq, PartialEq)]
102pub enum SettlementStatus {
103    /// Every item was attempted and accepted.
104    Accepted,
105    /// At least one item was lawfully rejected or blocked and none corrupted.
106    Rejected,
107    /// Interpretation corrupted or left an unattempted suffix.
108    Corrupt,
109}
110
111impl SettlementStatus {
112    #[must_use]
113    pub const fn combine(self, later: Self) -> Self {
114        match (self, later) {
115            (Self::Corrupt, _) | (_, Self::Corrupt) => Self::Corrupt,
116            (Self::Rejected, _) | (_, Self::Rejected) => Self::Rejected,
117            (Self::Accepted, Self::Accepted) => Self::Accepted,
118        }
119    }
120}
121
122/// Lossless status projection over an exact retained settlement value.
123pub trait ClassifySettlement {
124    /// Inspect every member without consuming or rewriting the settlement.
125    fn settlement_status(&self) -> SettlementStatus;
126}
127
128impl<Item, Accepted, Rejection, Prerequisite> ClassifySettlement
129    for ItemSettlement<Item, Accepted, Rejection, Prerequisite>
130{
131    fn settlement_status(&self) -> SettlementStatus {
132        match self {
133            Self::Accepted(_) => SettlementStatus::Accepted,
134            Self::Rejected { .. } | Self::Blocked { .. } => SettlementStatus::Rejected,
135            Self::Corrupt { .. } => SettlementStatus::Corrupt,
136        }
137    }
138}
139
140impl<Item, Settlement> ClassifySettlement for SettledItem<Item, Settlement>
141where
142    Settlement: ClassifySettlement,
143{
144    fn settlement_status(&self) -> SettlementStatus {
145        match self {
146            Self::Attempted(settlement) => settlement.settlement_status(),
147            Self::Unattempted(_) => SettlementStatus::Corrupt,
148        }
149    }
150}
151
152impl<Settlement> ClassifySettlement for Interpretation<Settlement>
153where
154    Settlement: ClassifySettlement,
155{
156    fn settlement_status(&self) -> SettlementStatus {
157        match self {
158            Self::Complete(settlement) => settlement.settlement_status(),
159            Self::Corrupt(_) => SettlementStatus::Corrupt,
160        }
161    }
162}
163
164impl<Settlement> ClassifySettlement for Vec<Settlement>
165where
166    Settlement: ClassifySettlement,
167{
168    fn settlement_status(&self) -> SettlementStatus {
169        let mut status = SettlementStatus::Accepted;
170        for settlement in self {
171            status = status.combine(settlement.settlement_status());
172        }
173        status
174    }
175}
176
177impl ClassifySettlement for crate::Never {
178    fn settlement_status(&self) -> SettlementStatus {
179        match *self {}
180    }
181}
182
183/// One concrete value that can occur in [`crate::Actions`].
184///
185/// The capability item owns its settlement vocabulary. Every conforming
186/// interpreter therefore agrees on the exact accepted receipt, rejection,
187/// and prerequisite types for that item. Interpreter corruption is the one
188/// shared [`InterpreterFault`] sum.
189///
190/// A runtime cannot substitute a different rejection type for the same item:
191///
192/// ```compile_fail,E0053
193/// struct Request;
194/// struct RequiredRejection;
195/// struct RuntimeRejection;
196///
197/// impl behavior::ActionItem for Request {
198///     type Accepted = ();
199///     type Rejection = RequiredRejection;
200///     type Prerequisite = behavior::Never;
201/// }
202///
203/// struct Runtime;
204/// impl behavior::InterpretItem<Request, (), behavior::Here> for Runtime {
205///     fn interpret_item(
206///         &mut self,
207///         item: Request,
208///     ) -> impl core::future::Future<
209///         Output = behavior::ItemSettlement<
210///             Request,
211///             (),
212///             RuntimeRejection,
213///             behavior::Never,
214///         >,
215///     > + Send {
216///         async move {
217///             behavior::ItemSettlement::Rejected { item, reason: RuntimeRejection }
218///         }
219///     }
220/// }
221/// ```
222pub trait ActionItem: Sized + Send {
223    type Accepted: Send;
224    type Rejection: Send;
225    type Prerequisite: Send;
226}
227
228/// Exact result of one action item within an interpreted action product.
229///
230/// The inner sum records the capability attempt. The outer sum preserves an
231/// untouched item when an earlier corrupt item stopped ordered traversal.
232pub type ActionItemResult<
233    Item,
234    Accepted = <Item as ActionItem>::Accepted,
235    Rejection = <Item as ActionItem>::Rejection,
236    Prerequisite = <Item as ActionItem>::Prerequisite,
237> = SettledItem<Item, ItemSettlement<Item, Accepted, Rejection, Prerequisite>>;
238
239/// A broken interpreter invariant, distinct from expected capability rejection.
240#[derive(Clone, Copy, Debug, Eq, PartialEq)]
241pub enum InterpreterFault {
242    MissingCapability,
243    CorruptTraversal,
244}
245
246/// Exact reason one structural parent report was not accepted.
247#[derive(Clone, Copy, Debug, Eq, PartialEq)]
248pub enum ParentReportReason {
249    ClosedParentControlLane,
250}
251
252/// Concrete interpreter ownership port for one exact typed action item.
253///
254/// `Item`, `RootEvent`, and `Path` select the capability statically. Distinct
255/// delivery and runtime-request values remain distinct implementations without
256/// an erased envelope, registry, or runtime lookup.
257pub trait InterpretItem<Item, RootEvent, Path>: Send
258where
259    Item: ActionItem,
260{
261    /// Attempt exactly one item and return its complete settlement.
262    fn interpret_item(
263        &mut self,
264        item: Item,
265    ) -> impl Future<
266        Output = ItemSettlement<Item, Item::Accepted, Item::Rejection, Item::Prerequisite>,
267    > + Send;
268}
269
270/// Static settlement product determined solely by one concrete sends value.
271///
272/// Every action item declares its own accepted, rejection, and prerequisite
273/// types. A containing product therefore has one settlement type under every
274/// conforming interpreter. `unattempted` preserves every item untouched after
275/// an earlier corrupt item stops traversal.
276///
277/// A runtime cannot select another settlement product for the same sends value:
278///
279/// ```compile_fail,E0271
280/// struct RuntimeSettlement;
281///
282/// fn runtime_selected<Runtime>(
283///     requests: behavior::InterpreterRequests<behavior::ReportToParent<u8>>,
284///     runtime: &mut Runtime,
285/// ) -> impl core::future::Future<
286///     Output = behavior::Interpretation<RuntimeSettlement>,
287/// > + Send
288/// where
289///     Runtime: behavior::InterpretItem<
290///         behavior::ReportToParent<u8>,
291///         (),
292///         behavior::Here,
293///     >,
294/// {
295///     <behavior::InterpreterRequests<behavior::ReportToParent<u8>> as
296///         behavior::InterpretSends<Runtime, (), behavior::Here>>::interpret(
297///             requests,
298///             runtime,
299///         )
300/// }
301/// ```
302pub trait SendSettlements: Sized {
303    /// Complete settlement product corresponding to `Self`.
304    type Settlements: Send + ClassifySettlement;
305
306    /// Preserve every item without granting interpretation authority.
307    fn unattempted(self) -> Self::Settlements;
308}
309
310/// Static interpretation of one complete sends value at an absolute event path.
311///
312/// Implementations are monomorphized over `Interpreter`; there is no erased
313/// envelope, runtime lane lookup, or downcast. `RootEvent` is the event type
314/// ultimately enqueued for the actor and `Path` is the current send owner's
315/// absolute position in it. Lawful rejection and blocking continue to later
316/// independent items. Corruption stops interpretation but retains the exact
317/// fault item and every untouched suffix value in the settlement shape.
318pub trait InterpretSends<Interpreter, RootEvent, Path>: SendSettlements + Send {
319    /// Interpret every value in this product in its declared stable order.
320    fn interpret(
321        self,
322        interpreter: &mut Interpreter,
323    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send;
324}
325
326/// The lane owned by the current named send product.
327pub enum Own {}
328
329/// Static evidence that a sends type contains one request lane.
330///
331/// Implementations append the input exactly once to that lane and leave every
332/// other lane unchanged. `Path` distinguishes repeated request types without
333/// erasing their position or choosing a lane at runtime.
334///
335/// [`Own`] selects a named product's own semantic lane. [`SendLayer`] carries
336/// wrapper-owned and inner effects as explicit named fields; request routing
337/// remains a compile-time proof rather than a runtime lane lookup.
338pub trait SendInput<Input, Path> {
339    fn emit(&mut self, input: Input);
340}
341
342/// Send effects emitted by a pure actor transition.
343///
344/// Values compose without interpreting them. This keeps communications and
345/// interpreter requests inside the explicit [`crate::Actions`] boundary.
346pub trait SendEffects: Sized {
347    fn empty() -> Self;
348    fn append(&mut self, other: Self);
349
350    #[must_use]
351    fn combine(mut self, other: Self) -> Self {
352        self.append(other);
353        self
354    }
355
356    /// Append one request to its statically selected semantic lane.
357    fn send<Input, Path>(&mut self, input: Input)
358    where
359        Self: SendInput<Input, Path>,
360    {
361        <Self as SendInput<Input, Path>>::emit(self, input);
362    }
363
364    /// Build a send product containing one request in its selected lane.
365    #[must_use]
366    fn sending<Input, Path>(input: Input) -> Self
367    where
368        Self: SendInput<Input, Path>,
369    {
370        let mut sends = Self::empty();
371        sends.send(input);
372        sends
373    }
374}
375
376/// Static projection of intentional logical destinations from one concrete
377/// sends product.
378///
379/// Implementations mirror the product's [`InterpretSends`] traversal without
380/// inspecting values. Only [`Delivery<P>`] contributes `P`; exact established
381/// deliveries, creator-local child deliveries and inputs, and interpreter
382/// requests contribute nothing. Named products append their field projections
383/// in interpretation order, preserving repeated protocol occurrences.
384///
385/// Custom named sends products must implement this trait explicitly. There is
386/// deliberately no blanket `Vec<T>` implementation that could silently treat
387/// an unknown delivery representation as having no logical destination.
388///
389/// ```compile_fail,E0277
390/// use behavior::{
391///     Actions, Behavior, BehaviorActed, LogicalHostRequirements, MailAddr,
392///     Never, NoBirths, Protocol, SendEffects, User,
393/// };
394/// struct OpaqueSends;
395/// impl SendEffects for OpaqueSends {
396///     fn empty() -> Self { Self }
397///     fn append(&mut self, _: Self) {}
398/// }
399/// impl<E> behavior::SendsFor<E> for OpaqueSends {}
400/// struct Actor;
401/// impl Protocol for Actor { type Addr = MailAddr; type Msg = (); }
402/// impl Behavior for Actor {
403///     type Protocol = Self;
404///     type Event = User<MailAddr, ()>;
405///     type Sends = OpaqueSends;
406///     type Ph = Never;
407///     type Error = Never;
408///     type Birth = NoBirths;
409///     fn transition(&mut self, _: behavior::ActiveTurn, _: Self::Event)
410///         -> BehaviorActed<Self> { Ok(Actions::cont()) }
411/// }
412/// fn require_complete<B: LogicalHostRequirements>() {}
413/// require_complete::<Actor>();
414/// ```
415pub trait LogicalDeliveryProtocols: SendEffects {
416    /// Ordered, duplicate-preserving logical protocol occurrences.
417    type Protocols: BirthProtocolProduct;
418}
419
420/// Proof that send effects are lawful for one complete event type.
421///
422/// Ordinary communications are independent of `Event`. Interpreter requests
423/// that return a local fact are not: their continuation must select an exact
424/// member of `Event`. Composite products implement this trait structurally,
425/// reindexing only their wrapped behavior effects through an outer event
426/// injection.
427///
428/// An un-reindexed return to the emitter cannot be paired with an added outer event
429/// layer:
430///
431/// ```compile_fail
432/// use behavior::{SendsFor, EventLayer, Here, MailAddr, ReturnsToEmitter,
433///     InterpreterRequest, InterpreterRequests, User};
434/// struct Request;
435/// impl InterpreterRequest for Request {
436///     type ReturnToEmitter = ReturnsToEmitter<u8, Here>;
437/// }
438/// fn lawful<E, F: SendsFor<E>>() {}
439/// type Inner = EventLayer<u8, User<MailAddr, ()>>;
440/// type Outer = EventLayer<(), Inner>;
441/// lawful::<Outer, InterpreterRequests<Request>>();
442/// ```
443pub trait SendsFor<Event>: SendEffects {}
444
445/// One action whose exact interpretation result returns to its live source.
446///
447/// [`ActionItem`] determines the complete result. An implementation selects
448/// only the actor receiving it, so an action cannot discard a rejected or
449/// unattempted value or reinterpret its status. Bombay admits the exact input
450/// through [`SourceAdmission`] or keeps it in lifecycle custody.
451pub trait SourceAction: ActionItem {
452    /// Actor-owned ingress selection for the result.
453    type Source;
454}
455
456/// Ordered actions whose normalized results return to their emitting actor.
457///
458/// This product is interpreter-facing machinery. Aggregate builders expose
459/// domain operations, not this structural lane.
460pub struct SourceActions<Item> {
461    items: Vec<Item>,
462}
463
464impl<Item> SourceActions<Item> {
465    /// Number of requests retained in authored order.
466    #[must_use]
467    pub fn len(&self) -> usize {
468        self.items.len()
469    }
470
471    /// Report whether this ordered request lane contains no items.
472    #[must_use]
473    pub fn is_empty(&self) -> bool {
474        self.items.is_empty()
475    }
476
477    /// Consume the lane into its requests in authored order.
478    #[must_use]
479    pub fn into_items(self) -> Vec<Item> {
480        self.items
481    }
482}
483
484impl<Item> SendEffects for SourceActions<Item> {
485    fn empty() -> Self {
486        Self { items: Vec::new() }
487    }
488
489    fn append(&mut self, mut other: Self) {
490        self.items.append(&mut other.items);
491    }
492}
493
494impl<Item> SendInput<Item, Own> for SourceActions<Item> {
495    fn emit(&mut self, input: Item) {
496        self.items.push(input);
497    }
498}
499
500impl<Item> LogicalDeliveryProtocols for SourceActions<Item> {
501    type Protocols = crate::NoBirthProtocols;
502}
503
504impl<Event, Item> SendsFor<Event> for SourceActions<Item> where Item: SourceAction {}
505
506/// Exact results for one [`SourceActions`] lane.
507///
508/// Closed admission retains values in this same product. There is no second
509/// residual representation and no inverse conversion.
510pub struct SourceSettlements<Item>
511where
512    Item: SourceAction,
513{
514    inputs: Vec<ActionItemResult<Item>>,
515}
516
517impl<Item> SourceSettlements<Item>
518where
519    Item: SourceAction,
520{
521    fn new(inputs: Vec<ActionItemResult<Item>>) -> Self {
522        Self { inputs }
523    }
524
525    /// Transfer every retained input in authored order.
526    #[must_use]
527    pub fn into_inputs(self) -> Vec<ActionItemResult<Item>> {
528        self.inputs
529    }
530}
531
532impl<Item> ClassifySettlement for SourceSettlements<Item>
533where
534    Item: SourceAction,
535{
536    fn settlement_status(&self) -> SettlementStatus {
537        self.inputs.settlement_status()
538    }
539}
540
541impl<Item> SendSettlements for SourceActions<Item>
542where
543    Item: SourceAction,
544{
545    type Settlements = SourceSettlements<Item>;
546
547    fn unattempted(self) -> Self::Settlements {
548        SourceSettlements::new(
549            self.items
550                .into_iter()
551                .map(SettledItem::Unattempted)
552                .collect(),
553        )
554    }
555}
556
557impl<Interpreter, RootEvent, Path, Item> InterpretSends<Interpreter, RootEvent, Path>
558    for SourceActions<Item>
559where
560    Interpreter: InterpretItem<Item, RootEvent, Path>,
561    Item: SourceAction,
562{
563    fn interpret(
564        self,
565        interpreter: &mut Interpreter,
566    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
567        async move {
568            let mut items = self.items.into_iter();
569            let mut inputs = Vec::with_capacity(items.len());
570            while let Some(item) = items.next() {
571                match settle_item::<Item, Interpreter, RootEvent, Path>(item, interpreter).await {
572                    Interpretation::Complete(settlement) => {
573                        inputs.push(settlement);
574                    }
575                    Interpretation::Corrupt(settlement) => {
576                        inputs.push(settlement);
577                        inputs.extend(items.map(SettledItem::Unattempted));
578                        return Interpretation::Corrupt(SourceSettlements::new(inputs));
579                    }
580                }
581            }
582            Interpretation::Complete(SourceSettlements::new(inputs))
583        }
584    }
585}
586
587/// Bombay ownership port for one exact current-actor system input.
588///
589/// Success transfers the input to the existing actor loop. Closed admission
590/// returns the unchanged input to the current lifecycle host.
591///
592/// An event without the exact source ingress cannot implement this port:
593///
594/// ```compile_fail,E0277
595/// struct EventWithoutInput;
596/// struct Owner;
597/// struct Input;
598/// struct Host;
599/// impl behavior::SourceAdmission<EventWithoutInput, Owner, Input> for Host {
600///     async fn admit_source(&mut self, _: Input) -> Result<(), Input> { Ok(()) }
601/// }
602/// ```
603pub trait SourceAdmission<RootEvent, Source, Input>: Send
604where
605    RootEvent: crate::EventIngress<Source, Input>,
606{
607    /// Attempt one source input without discarding closed-control ownership.
608    fn admit_source(&mut self, input: Input) -> impl Future<Output = Result<(), Input>> + Send;
609}
610
611/// Progress of one ordered source-settlement custody pass.
612pub enum SourceCustody<Residual> {
613    /// Source admission remains available after processing this residual.
614    Open(Residual),
615    /// Admission closed; the residual contains the current and untouched suffix.
616    Closed(Residual),
617}
618
619/// Static ordered source admission for one complete settlement product.
620pub trait SourceSettlementCustody<Host, RootEvent>: Sized {
621    /// Offer source inputs in their declared order.
622    fn offer_to_source(self, host: &mut Host) -> impl Future<Output = SourceCustody<Self>> + Send;
623}
624
625impl<Host, RootEvent, Item> SourceSettlementCustody<Host, RootEvent> for SourceSettlements<Item>
626where
627    Host: SourceAdmission<RootEvent, Item::Source, ActionItemResult<Item>>,
628    RootEvent: crate::EventIngress<Item::Source, ActionItemResult<Item>>,
629    Item: SourceAction,
630{
631    fn offer_to_source(self, host: &mut Host) -> impl Future<Output = SourceCustody<Self>> + Send {
632        async move {
633            let mut source_inputs = self.inputs.into_iter();
634            let mut residual = Vec::new();
635            while let Some(input) = source_inputs.next() {
636                match host.admit_source(input).await {
637                    Ok(()) => {}
638                    Err(input) => {
639                        residual.push(input);
640                        residual.extend(source_inputs);
641                        return SourceCustody::Closed(Self::new(residual));
642                    }
643                }
644            }
645            SourceCustody::Open(Self::new(residual))
646        }
647    }
648}
649
650impl<Host, RootEvent> SourceSettlementCustody<Host, RootEvent> for NoSends {
651    fn offer_to_source(self, _: &mut Host) -> impl Future<Output = SourceCustody<Self>> + Send {
652        async move { SourceCustody::Open(self) }
653    }
654}
655
656impl<Host, RootEvent, Item> SourceSettlementCustody<Host, RootEvent> for Vec<ActionItemResult<Item>>
657where
658    Item: ActionItem,
659{
660    fn offer_to_source(self, _: &mut Host) -> impl Future<Output = SourceCustody<Self>> + Send {
661        async move { SourceCustody::Open(self) }
662    }
663}
664
665impl<Host, RootEvent> SourceSettlementCustody<Host, RootEvent> for Vec<crate::Never> {
666    fn offer_to_source(self, _: &mut Host) -> impl Future<Output = SourceCustody<Self>> + Send {
667        async move { SourceCustody::Open(self) }
668    }
669}
670
671impl<Host, RootEvent, Owned, Inner> SourceSettlementCustody<Host, RootEvent>
672    for SendLayer<Owned, Inner>
673where
674    Host: Send,
675    Owned: SourceSettlementCustody<Host, RootEvent> + Send,
676    Inner: SourceSettlementCustody<Host, RootEvent> + Send,
677{
678    fn offer_to_source(self, host: &mut Host) -> impl Future<Output = SourceCustody<Self>> + Send {
679        async move {
680            match self.inner.offer_to_source(host).await {
681                SourceCustody::Open(inner) => match self.owned.offer_to_source(host).await {
682                    SourceCustody::Open(owned) => SourceCustody::Open(SendLayer::new(owned, inner)),
683                    SourceCustody::Closed(owned) => {
684                        SourceCustody::Closed(SendLayer::new(owned, inner))
685                    }
686                },
687                SourceCustody::Closed(inner) => {
688                    SourceCustody::Closed(SendLayer::new(self.owned, inner))
689                }
690            }
691        }
692    }
693}
694
695/// An interpreter request that produces no later fact for the emitting actor.
696pub enum NoReturnToEmitter {}
697
698/// An interpreter request whose later `Input` returns to the emitting actor at
699/// `Path`, relative to the effect lane that owns the request.
700pub struct ReturnsToEmitter<Input, Path>(core::marker::PhantomData<fn(Input, Path)>);
701
702/// Local-return contract declared by one interpreter-facing request.
703pub trait ReturnToEmitterFor<Event> {}
704
705impl<Event> ReturnToEmitterFor<Event> for NoReturnToEmitter {}
706
707impl<Event, Input, Path> ReturnToEmitterFor<Event> for ReturnsToEmitter<Input, Path> where
708    Event: InjectEvent<Input, Path>
709{
710}
711
712/// Declares only the continuation returning to the actor that emitted this
713/// interpreter request. Destinations owned by a child, parent, ancestor, or
714/// established actor are separate capabilities and are not reindexed when the
715/// emitter is wrapped.
716pub trait InterpreterRequest {
717    type ReturnToEmitter;
718}
719
720/// Transfer one owned report to the emitter's established parent.
721///
722/// The request is an ordinary typed send effect. Its interpreter uses the
723/// already-established creator/child relationship, attaches the emitter's
724/// exact creator-local nonce, and injects a [`crate::ChildReport`] into the
725/// parent's closed event algebra. It performs no address or protocol lookup.
726/// A root behavior has no parent capability and therefore cannot interpret
727/// this request.
728#[derive(Debug, Clone, Copy, PartialEq, Eq)]
729pub struct ReportToParent<R> {
730    /// Complete report value transferred to the parent.
731    pub report: R,
732}
733
734impl<R> ReportToParent<R> {
735    /// Construct one structural parent report.
736    #[must_use]
737    pub const fn new(report: R) -> Self {
738        Self { report }
739    }
740
741    /// Recover ownership of the complete report value.
742    #[must_use]
743    pub fn into_inner(self) -> R {
744        self.report
745    }
746}
747
748impl<R> InterpreterRequest for ReportToParent<R> {
749    type ReturnToEmitter = NoReturnToEmitter;
750}
751
752impl<R> ActionItem for ReportToParent<R>
753where
754    R: Send,
755{
756    type Accepted = ();
757    type Rejection = ParentReportReason;
758    type Prerequisite = crate::Never;
759}
760
761/// Send effects containing no communications or interpreter requests.
762///
763/// A behavior layer that adds an event lane but emits nothing of its own uses
764/// this named value rather than an ambiguous `()`.
765#[derive(Debug, Clone, Copy, PartialEq, Eq)]
766pub struct NoSends;
767
768impl SendEffects for NoSends {
769    fn empty() -> Self {
770        Self
771    }
772
773    fn append(&mut self, _: Self) {}
774}
775
776impl LogicalDeliveryProtocols for NoSends {
777    type Protocols = NoBirthProtocols;
778}
779
780impl<Event> SendsFor<Event> for NoSends {}
781
782impl SendSettlements for NoSends {
783    type Settlements = Self;
784
785    fn unattempted(self) -> Self::Settlements {
786        self
787    }
788}
789
790impl ClassifySettlement for NoSends {
791    fn settlement_status(&self) -> SettlementStatus {
792        SettlementStatus::Accepted
793    }
794}
795
796impl<Interpreter, RootEvent, Path> InterpretSends<Interpreter, RootEvent, Path> for NoSends {
797    fn interpret(
798        self,
799        _: &mut Interpreter,
800    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
801        async move { Interpretation::Complete(self) }
802    }
803}
804
805/// Send effects introduced by one wrapper around inner send effects.
806///
807/// `owned` contains effects introduced by the current behavior layer and
808/// `inner` contains effects of the wrapped interaction. The structural
809/// [`SendsFor`] implementation is the composition law:
810///
811/// ```text
812/// Event'   = OwnedEvent + InnerEvent
813/// Effects' = OwnedEffects × InnerEffects
814/// ```
815///
816/// Owned return to the emitters target `Event'`; inner return to the emitters target
817/// `InnerEvent` and are therefore lifted through the same `Inner` injection.
818/// Established actor, child, and ancestor destinations are unaffected because
819/// they are not return to the emitters.
820#[derive(Debug, Clone, Copy, PartialEq, Eq)]
821pub struct SendLayer<Owned, Inner> {
822    pub owned: Owned,
823    pub inner: Inner,
824}
825
826impl<Owned, Inner> SendLayer<Owned, Inner> {
827    #[must_use]
828    pub const fn new(owned: Owned, inner: Inner) -> Self {
829        Self { owned, inner }
830    }
831}
832
833impl<Owned: SendEffects, Inner: SendEffects> SendEffects for SendLayer<Owned, Inner> {
834    fn empty() -> Self {
835        Self::new(Owned::empty(), Inner::empty())
836    }
837
838    fn append(&mut self, other: Self) {
839        self.owned.append(other.owned);
840        self.inner.append(other.inner);
841    }
842}
843
844impl<Owned, Inner> LogicalDeliveryProtocols for SendLayer<Owned, Inner>
845where
846    Owned: LogicalDeliveryProtocols,
847    Inner: LogicalDeliveryProtocols,
848{
849    // Interpretation preserves authored inner-to-outer wrapper order.
850    type Protocols = <Inner::Protocols as BirthProtocolProduct>::Append<Owned::Protocols>;
851}
852
853impl<Event, OwnedEffects, InnerEffects> SendsFor<Event> for SendLayer<OwnedEffects, InnerEffects>
854where
855    Event: ComposedEvent,
856    OwnedEffects: SendsFor<Event>,
857    InnerEffects: SendsFor<Event::Inner>,
858{
859}
860
861impl<Owned, Inner> SendSettlements for SendLayer<Owned, Inner>
862where
863    Owned: SendSettlements,
864    Inner: SendSettlements,
865{
866    type Settlements = SendLayer<Owned::Settlements, Inner::Settlements>;
867
868    fn unattempted(self) -> Self::Settlements {
869        SendLayer::new(self.owned.unattempted(), self.inner.unattempted())
870    }
871}
872
873impl<Owned, Inner> ClassifySettlement for SendLayer<Owned, Inner>
874where
875    Owned: ClassifySettlement,
876    Inner: ClassifySettlement,
877{
878    fn settlement_status(&self) -> SettlementStatus {
879        self.inner
880            .settlement_status()
881            .combine(self.owned.settlement_status())
882    }
883}
884
885impl<Input, Path, Owned, Inner> SendInput<Input, Path> for SendLayer<Owned, Inner>
886where
887    Owned: SendInput<Input, Path>,
888{
889    fn emit(&mut self, input: Input) {
890        self.owned.emit(input);
891    }
892}
893
894impl<Interpreter, RootEvent, Path, Owned, Inner> InterpretSends<Interpreter, RootEvent, Path>
895    for SendLayer<Owned, Inner>
896where
897    Interpreter: Send,
898    Owned: InterpretSends<Interpreter, RootEvent, Path> + Send,
899    Inner: InterpretSends<Interpreter, RootEvent, Inside<Path>> + Send,
900{
901    fn interpret(
902        self,
903        interpreter: &mut Interpreter,
904    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
905        async move {
906            let inner = <Inner as InterpretSends<Interpreter, RootEvent, Inside<Path>>>::interpret(
907                self.inner,
908                interpreter,
909            )
910            .await;
911            let inner = match inner {
912                Interpretation::Complete(inner) => inner,
913                Interpretation::Corrupt(inner) => {
914                    return Interpretation::Corrupt(SendLayer::new(
915                        self.owned.unattempted(),
916                        inner,
917                    ));
918                }
919            };
920            match <Owned as InterpretSends<Interpreter, RootEvent, Path>>::interpret(
921                self.owned,
922                interpreter,
923            )
924            .await
925            {
926                Interpretation::Complete(owned) => {
927                    Interpretation::Complete(SendLayer::new(owned, inner))
928                }
929                Interpretation::Corrupt(owned) => {
930                    Interpretation::Corrupt(SendLayer::new(owned, inner))
931                }
932            }
933        }
934    }
935}
936
937impl<T> SendEffects for Vec<T> {
938    fn empty() -> Self {
939        Vec::new()
940    }
941
942    fn append(&mut self, mut other: Self) {
943        Vec::append(self, &mut other);
944    }
945}
946
947impl<P: Protocol> LogicalDeliveryProtocols for Vec<Delivery<P>> {
948    type Protocols = BirthProtocol<P, NoBirthProtocols>;
949}
950
951impl<P: Protocol, Occurrence> LogicalDeliveryProtocols for Vec<ChildDelivery<P, Occurrence>> {
952    type Protocols = NoBirthProtocols;
953}
954
955impl<Child, Source, Input, Occurrence> LogicalDeliveryProtocols
956    for Vec<ChildInput<Child, Source, Input, Occurrence>>
957where
958    Child: Behavior,
959{
960    type Protocols = NoBirthProtocols;
961}
962
963impl<P> LogicalDeliveryProtocols for Vec<EstablishedDelivery<P>>
964where
965    P: Protocol,
966    P::Addr: EndpointAddress,
967{
968    type Protocols = NoBirthProtocols;
969}
970
971impl LogicalDeliveryProtocols for Vec<crate::Never> {
972    type Protocols = NoBirthProtocols;
973}
974
975impl<Event, T> SendsFor<Event> for Vec<T> {}
976
977impl<Item> SendSettlements for Vec<Item>
978where
979    Item: ActionItem,
980{
981    type Settlements = Vec<ActionItemResult<Item>>;
982
983    fn unattempted(self) -> Self::Settlements {
984        unattempted_items(self)
985    }
986}
987
988/// Interpret exactly one item and attach its product-owned attempt evidence.
989///
990/// This is the indivisible form of [`InterpretSends`]. It marks the enclosing
991/// interpretation corrupt exactly when the concrete item result is corrupt;
992/// lawful rejection and blocking remain complete outcomes.
993pub async fn settle_item<Item, Interpreter, RootEvent, Path>(
994    item: Item,
995    interpreter: &mut Interpreter,
996) -> Interpretation<ActionItemResult<Item>>
997where
998    Item: ActionItem,
999    Interpreter: InterpretItem<Item, RootEvent, Path>,
1000{
1001    let settlement =
1002        <Interpreter as InterpretItem<Item, RootEvent, Path>>::interpret_item(interpreter, item)
1003            .await;
1004    match settlement {
1005        corrupt @ ItemSettlement::Corrupt { .. } => {
1006            Interpretation::Corrupt(SettledItem::Attempted(corrupt))
1007        }
1008        settled => Interpretation::Complete(SettledItem::Attempted(settled)),
1009    }
1010}
1011
1012async fn interpret_items<Item, Interpreter, RootEvent, Path>(
1013    items: Vec<Item>,
1014    interpreter: &mut Interpreter,
1015) -> Interpretation<Vec<ActionItemResult<Item>>>
1016where
1017    Item: ActionItem,
1018    Interpreter: InterpretItem<Item, RootEvent, Path>,
1019{
1020    let mut items = items.into_iter();
1021    let mut settlements = Vec::with_capacity(items.len());
1022    while let Some(item) = items.next() {
1023        match settle_item::<Item, Interpreter, RootEvent, Path>(item, interpreter).await {
1024            Interpretation::Complete(settlement) => settlements.push(settlement),
1025            Interpretation::Corrupt(settlement) => {
1026                settlements.push(settlement);
1027                settlements.extend(items.map(SettledItem::Unattempted));
1028                return Interpretation::Corrupt(settlements);
1029            }
1030        }
1031    }
1032    Interpretation::Complete(settlements)
1033}
1034
1035fn unattempted_items<Item>(items: Vec<Item>) -> Vec<ActionItemResult<Item>>
1036where
1037    Item: ActionItem,
1038{
1039    items.into_iter().map(SettledItem::Unattempted).collect()
1040}
1041
1042impl<Interpreter, RootEvent, Path, P> InterpretSends<Interpreter, RootEvent, Path>
1043    for Vec<Delivery<P>>
1044where
1045    Interpreter: InterpretItem<Delivery<P>, RootEvent, Path>,
1046    P: Protocol,
1047    Delivery<P>: ActionItem,
1048{
1049    fn interpret(
1050        self,
1051        interpreter: &mut Interpreter,
1052    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
1053        interpret_items(self, interpreter)
1054    }
1055}
1056
1057impl<Interpreter, RootEvent, Path, P, Occurrence> InterpretSends<Interpreter, RootEvent, Path>
1058    for Vec<ChildDelivery<P, Occurrence>>
1059where
1060    Interpreter: InterpretItem<ChildDelivery<P, Occurrence>, RootEvent, Path>,
1061    P: Protocol,
1062    ChildDelivery<P, Occurrence>: ActionItem,
1063{
1064    fn interpret(
1065        self,
1066        interpreter: &mut Interpreter,
1067    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
1068        interpret_items(self, interpreter)
1069    }
1070}
1071
1072impl<Interpreter, RootEvent, Path, Child, Source, Input, Occurrence>
1073    InterpretSends<Interpreter, RootEvent, Path>
1074    for Vec<ChildInput<Child, Source, Input, Occurrence>>
1075where
1076    Interpreter: InterpretItem<ChildInput<Child, Source, Input, Occurrence>, RootEvent, Path>,
1077    Child: Behavior,
1078    Child::Event: crate::ChildInputIngress<Source, Input>,
1079    ChildInput<Child, Source, Input, Occurrence>: ActionItem,
1080{
1081    fn interpret(
1082        self,
1083        interpreter: &mut Interpreter,
1084    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
1085        interpret_items(self, interpreter)
1086    }
1087}
1088
1089impl<Interpreter, RootEvent, Path, P> InterpretSends<Interpreter, RootEvent, Path>
1090    for Vec<EstablishedDelivery<P>>
1091where
1092    Interpreter: InterpretItem<EstablishedDelivery<P>, RootEvent, Path>,
1093    P: Protocol,
1094    P::Addr: EndpointAddress,
1095    EstablishedDelivery<P>: ActionItem,
1096{
1097    fn interpret(
1098        self,
1099        interpreter: &mut Interpreter,
1100    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
1101        interpret_items(self, interpreter)
1102    }
1103}
1104
1105impl SendSettlements for Vec<crate::Never> {
1106    type Settlements = Self;
1107
1108    fn unattempted(self) -> Self::Settlements {
1109        self
1110    }
1111}
1112
1113impl<Interpreter, RootEvent, Path> InterpretSends<Interpreter, RootEvent, Path>
1114    for Vec<crate::Never>
1115{
1116    fn interpret(
1117        self,
1118        _: &mut Interpreter,
1119    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
1120        async move { Interpretation::Complete(self) }
1121    }
1122}
1123
1124impl<T> SendInput<T, Own> for Vec<T> {
1125    fn emit(&mut self, input: T) {
1126        self.push(input);
1127    }
1128}
1129
1130/// Requests interpreted by the runtime local to the emitting actor.
1131///
1132/// Unlike [`crate::Delivery`], a interpreter request has no actor address. Its
1133/// recipient is definitionally the interpreter of the actor whose transition
1134/// emitted it. This distinct send lane lets interpreters route ordinary
1135/// deliveries and interpreter requests with disjoint static implementations.
1136#[derive(Debug, Clone, PartialEq, Eq)]
1137pub struct InterpreterRequests<M> {
1138    requests: Vec<M>,
1139}
1140
1141impl<M> InterpreterRequests<M> {
1142    #[must_use]
1143    pub fn new(requests: Vec<M>) -> Self {
1144        Self { requests }
1145    }
1146    #[must_use]
1147    pub fn one(request: M) -> Self {
1148        Self::new(vec![request])
1149    }
1150    #[must_use]
1151    pub fn as_slice(&self) -> &[M] {
1152        &self.requests
1153    }
1154    pub fn iter(&self) -> core::slice::Iter<'_, M> {
1155        self.requests.iter()
1156    }
1157    #[must_use]
1158    pub fn len(&self) -> usize {
1159        self.requests.len()
1160    }
1161    #[must_use]
1162    pub fn is_empty(&self) -> bool {
1163        self.requests.is_empty()
1164    }
1165    pub fn extend(&mut self, requests: impl IntoIterator<Item = M>) {
1166        self.requests.extend(requests);
1167    }
1168    #[must_use]
1169    pub fn into_requests(self) -> Vec<M> {
1170        self.requests
1171    }
1172}
1173
1174impl<M> core::ops::Index<usize> for InterpreterRequests<M> {
1175    type Output = M;
1176    fn index(&self, index: usize) -> &Self::Output {
1177        &self.requests[index]
1178    }
1179}
1180
1181impl<M> IntoIterator for InterpreterRequests<M> {
1182    type Item = M;
1183    type IntoIter = std::vec::IntoIter<M>;
1184    fn into_iter(self) -> Self::IntoIter {
1185        self.requests.into_iter()
1186    }
1187}
1188
1189impl<'a, M> IntoIterator for &'a InterpreterRequests<M> {
1190    type Item = &'a M;
1191    type IntoIter = core::slice::Iter<'a, M>;
1192    fn into_iter(self) -> Self::IntoIter {
1193        self.requests.iter()
1194    }
1195}
1196
1197impl<M> SendEffects for InterpreterRequests<M> {
1198    fn empty() -> Self {
1199        Self::new(Vec::new())
1200    }
1201    fn append(&mut self, mut other: Self) {
1202        self.requests.append(&mut other.requests);
1203    }
1204}
1205
1206impl<M> LogicalDeliveryProtocols for InterpreterRequests<M> {
1207    type Protocols = NoBirthProtocols;
1208}
1209
1210impl<Event, M> SendsFor<Event> for InterpreterRequests<M>
1211where
1212    M: InterpreterRequest,
1213    M::ReturnToEmitter: ReturnToEmitterFor<Event>,
1214{
1215}
1216
1217impl<M> SendInput<M, Own> for InterpreterRequests<M> {
1218    fn emit(&mut self, input: M) {
1219        self.requests.push(input);
1220    }
1221}
1222
1223impl<Request> SendSettlements for InterpreterRequests<Request>
1224where
1225    Request: ActionItem,
1226{
1227    type Settlements = Vec<ActionItemResult<Request>>;
1228
1229    fn unattempted(self) -> Self::Settlements {
1230        unattempted_items(self.requests)
1231    }
1232}
1233
1234impl<Interpreter, RootEvent, Path, Request> InterpretSends<Interpreter, RootEvent, Path>
1235    for InterpreterRequests<Request>
1236where
1237    Interpreter: InterpretItem<Request, RootEvent, Path>,
1238    Request: ActionItem,
1239{
1240    fn interpret(
1241        self,
1242        interpreter: &mut Interpreter,
1243    ) -> impl Future<Output = Interpretation<Self::Settlements>> + Send {
1244        interpret_items(self.requests, interpreter)
1245    }
1246}
1247
1248#[cfg(test)]
1249mod tests {
1250    use super::*;
1251
1252    #[test]
1253    fn send_accumulation_obeys_identity_and_associativity() {
1254        let values = vec![1, 2];
1255        assert_eq!(Vec::new().combine(values.clone()), values);
1256        assert_eq!(values.clone().combine(Vec::new()), values);
1257
1258        let left = vec![1].combine(vec![2]).combine(vec![3]);
1259        let right = vec![1].combine(vec![2].combine(vec![3]));
1260        assert_eq!(left, right);
1261    }
1262
1263    #[test]
1264    fn vector_and_service_lanes_emit_and_iterate_in_order() {
1265        assert!(<Vec<u8> as SendEffects>::empty().is_empty());
1266        let mut vector = Vec::new();
1267        <Vec<u8> as SendInput<u8, Own>>::emit(&mut vector, 1);
1268        assert_eq!(vector, [1]);
1269
1270        let mut services = InterpreterRequests::one(2);
1271        services.extend([4, 5]);
1272        <InterpreterRequests<u8> as SendInput<u8, Own>>::emit(&mut services, 3);
1273        assert!(!services.is_empty());
1274        assert_eq!(services.as_slice(), [2, 4, 5, 3]);
1275        assert_eq!(
1276            (&services).into_iter().copied().collect::<Vec<_>>(),
1277            [2, 4, 5, 3]
1278        );
1279        assert_eq!(services.into_iter().collect::<Vec<_>>(), [2, 4, 5, 3]);
1280
1281        let requests = InterpreterRequests::new(vec![4, 5]).into_requests();
1282        assert_eq!(requests, [4, 5]);
1283    }
1284
1285    #[test]
1286    fn source_and_interpreter_lanes_report_complete_ordered_contents() {
1287        let empty = <SourceActions<u8> as SendEffects>::empty();
1288        assert!(empty.is_empty());
1289        assert_eq!(empty.len(), 0);
1290
1291        let mut prefix = <SourceActions<u8> as SendEffects>::empty();
1292        <SourceActions<u8> as SendInput<u8, Own>>::emit(&mut prefix, 1);
1293        <SourceActions<u8> as SendInput<u8, Own>>::emit(&mut prefix, 2);
1294        let mut suffix = <SourceActions<u8> as SendEffects>::empty();
1295        <SourceActions<u8> as SendInput<u8, Own>>::emit(&mut suffix, 3);
1296        <SourceActions<u8> as SendInput<u8, Own>>::emit(&mut suffix, 4);
1297        prefix.append(suffix);
1298        assert!(!prefix.is_empty());
1299        assert_eq!(prefix.len(), 4);
1300        assert_eq!(prefix.into_items(), [1, 2, 3, 4]);
1301
1302        let requests = InterpreterRequests::new(vec![5, 6, 7]);
1303        assert_eq!(requests.len(), 3);
1304    }
1305
1306    struct Returning;
1307
1308    impl InterpreterRequest for Returning {
1309        type ReturnToEmitter = ReturnsToEmitter<u8, crate::Here>;
1310    }
1311
1312    fn lawful<Event, Effects: SendsFor<Event>>() {}
1313
1314    #[test]
1315    fn local_return_proofs_compose_through_exact_event_layers() {
1316        type Inner = crate::EventLayer<u8, crate::User<crate::MailAddr, ()>>;
1317        type Outer = crate::EventLayer<(), Inner>;
1318
1319        lawful::<Inner, InterpreterRequests<Returning>>();
1320        lawful::<Outer, SendLayer<NoSends, InterpreterRequests<Returning>>>();
1321    }
1322
1323    #[test]
1324    fn send_layer_emits_into_its_designated_owned_lane() {
1325        let mut effects = SendLayer::new(Vec::<u8>::new(), Vec::<u16>::new());
1326        <SendLayer<Vec<u8>, Vec<u16>> as SendInput<u8, Own>>::emit(&mut effects, 7);
1327        assert_eq!(effects.owned, [7]);
1328        assert!(effects.inner.is_empty());
1329    }
1330
1331    #[derive(Debug, PartialEq, Eq)]
1332    enum Seen {
1333        Inner(u8),
1334        Outer(u16),
1335    }
1336
1337    struct Trace(Vec<Seen>);
1338
1339    type TraceEvent =
1340        crate::EventLayer<u16, crate::EventLayer<u8, crate::User<crate::MailAddr, ()>>>;
1341
1342    impl ActionItem for u8 {
1343        type Accepted = ();
1344        type Rejection = crate::Never;
1345        type Prerequisite = crate::Never;
1346    }
1347
1348    impl ActionItem for u16 {
1349        type Accepted = ();
1350        type Rejection = crate::Never;
1351        type Prerequisite = crate::Never;
1352    }
1353
1354    impl InterpretItem<u8, TraceEvent, crate::Inside<crate::Here>> for Trace {
1355        fn interpret_item(
1356            &mut self,
1357            request: u8,
1358        ) -> impl Future<
1359            Output = ItemSettlement<
1360                u8,
1361                <u8 as ActionItem>::Accepted,
1362                <u8 as ActionItem>::Rejection,
1363                <u8 as ActionItem>::Prerequisite,
1364            >,
1365        > + Send {
1366            async move {
1367                self.0.push(Seen::Inner(request));
1368                ItemSettlement::Accepted(())
1369            }
1370        }
1371    }
1372
1373    impl InterpretItem<u16, TraceEvent, crate::Here> for Trace {
1374        fn interpret_item(
1375            &mut self,
1376            request: u16,
1377        ) -> impl Future<
1378            Output = ItemSettlement<
1379                u16,
1380                <u16 as ActionItem>::Accepted,
1381                <u16 as ActionItem>::Rejection,
1382                <u16 as ActionItem>::Prerequisite,
1383            >,
1384        > + Send {
1385            async move {
1386                self.0.push(Seen::Outer(request));
1387                ItemSettlement::Accepted(())
1388            }
1389        }
1390    }
1391
1392    #[tokio::test]
1393    async fn structural_interpretation_visits_every_lane_inner_to_outer() {
1394        let effects = SendLayer::new(
1395            InterpreterRequests::new(vec![3_u16, 5]),
1396            SendLayer::new(InterpreterRequests::one(2_u8), NoSends),
1397        );
1398        let mut trace = Trace(Vec::new());
1399
1400        <_ as InterpretSends<_, TraceEvent, crate::Here>>::interpret(effects, &mut trace).await;
1401
1402        assert_eq!(trace.0, [Seen::Inner(2), Seen::Outer(3), Seen::Outer(5)]);
1403    }
1404}