Skip to main content

behavior/actor/
addressing.rs

1//! Protocol-indexed actor recipients and deliveries.
2
3use core::marker::PhantomData;
4
5use crate::{ActionItem, Behavior, MessageProtocol, Never, Protocol};
6
7/// A pure logical actor-address namespace.
8///
9/// An address names a transport or resolution domain. It does not allocate an
10/// actor and it does not prove that an actor is installed. Fresh allocation is
11/// interpreter-owned; the creator-local [`Address::Nonce`] is correlation
12/// evidence only and is deliberately not convertible into an address here.
13pub trait Address: Copy + Eq {
14    type Nonce: Copy + Eq;
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct MailAddr(pub u64);
19
20impl From<u64> for MailAddr {
21    fn from(value: u64) -> Self {
22        Self(value)
23    }
24}
25
26impl From<MailAddr> for u64 {
27    fn from(value: MailAddr) -> Self {
28        value.0
29    }
30}
31
32impl Address for MailAddr {
33    type Nonce = u64;
34}
35
36/// Runtime-owned exact message endpoint family for one logical address namespace.
37///
38/// A runtime implements this trait on its own address newtype, selecting one
39/// statically projected endpoint representation for each concrete protocol.
40/// The projection may reuse a representation; [`EstablishedRecipient<P>`]
41/// still preserves `P` and prevents cross-protocol substitution. Ordinary
42/// protocols continue to declare only their canonical [`Protocol::Addr`] and
43/// [`Protocol::Msg`]; they never author endpoint keys or endpoint associated
44/// types. An endpoint is cloneable acquaintance evidence, but it is not
45/// intrinsically `Send`: thread transfer is required only by the concrete
46/// asynchronous interpretation boundary that performs it.
47///
48/// A local endpoint remains valid, but cannot enter the sendable
49/// [`crate::InterpretSends`] path:
50///
51/// ```compile_fail,E0277
52/// #[derive(Clone, Copy, PartialEq, Eq)]
53/// struct LocalAddr(u8);
54/// impl behavior::Address for LocalAddr { type Nonce = u8; }
55/// struct LocalEndpoint<P>(std::rc::Rc<()>, core::marker::PhantomData<fn() -> P>);
56/// impl<P> Clone for LocalEndpoint<P> {
57///     fn clone(&self) -> Self { Self(self.0.clone(), core::marker::PhantomData) }
58/// }
59/// impl behavior::RecipientAddress for LocalAddr {
60///     type Established<P> = LocalEndpoint<P> where P: behavior::Protocol<Addr = Self>;
61/// }
62/// struct LocalProtocol;
63/// impl behavior::Protocol for LocalProtocol {
64///     type Addr = LocalAddr;
65///     type Msg = std::rc::Rc<()>;
66/// }
67/// struct Runtime;
68/// impl<RootEvent, Path> behavior::InterpretItem<behavior::EstablishedDelivery<LocalProtocol>, RootEvent, Path>
69///     for Runtime
70/// {
71///     fn interpret_item(
72///         &mut self,
73///         delivery: behavior::EstablishedDelivery<LocalProtocol>,
74///     ) -> impl core::future::Future<Output = behavior::ItemSettlement<
75///         behavior::EstablishedDelivery<LocalProtocol>, (), behavior::Never, behavior::Never,
76///     >> + Send {
77///         async move {
78///             drop(delivery);
79///             behavior::ItemSettlement::Accepted(())
80///         }
81///     }
82/// }
83/// fn require_async<T>()
84/// where
85///     T: behavior::InterpretSends<Runtime, behavior::User<LocalAddr, std::rc::Rc<()>>, behavior::Here>,
86/// {}
87/// let endpoint = LocalEndpoint(std::rc::Rc::new(()), core::marker::PhantomData);
88/// let recipient = behavior::EstablishedRecipient::<LocalProtocol>::issued(endpoint);
89/// let _delivery = behavior::EstablishedDelivery::new(recipient, std::rc::Rc::new(()));
90/// require_async::<Vec<behavior::EstablishedDelivery<LocalProtocol>>>();
91/// ```
92pub trait RecipientAddress: Address + Sized {
93    type Established<P>: Clone
94    where
95        P: Protocol<Addr = Self>;
96}
97
98/// Runtime-owned installed actor family for an address namespace.
99///
100/// The runtime must bind one protocol endpoint and its matching concrete
101/// lifecycle authority to the same incarnation before issuing this value.
102/// A namespace used only for protocol messaging implements
103/// [`RecipientAddress`] without this stronger port.
104pub trait EndpointAddress: Address + Sized {
105    type Established<P>: Clone
106    where
107        P: Protocol<Addr = Self>;
108
109    type Installed<B>: Clone
110    where
111        B: Behavior<Protocol: Protocol<Addr = Self>>;
112
113    /// Project the message-only endpoint from one installed actor.
114    fn recipient<B>(
115        installed: &Self::Installed<B>,
116    ) -> <Self as EndpointAddress>::Established<B::Protocol>
117    where
118        B: Behavior<Protocol: Protocol<Addr = Self>>;
119}
120
121impl<A: EndpointAddress> RecipientAddress for A {
122    type Established<P>
123        = <A as EndpointAddress>::Established<P>
124    where
125        P: Protocol<Addr = Self>;
126}
127
128/// Pure logical destination for one concrete protocol signature.
129///
130/// The destination protocol owner is part of the type even when two protocols
131/// share the same address namespace and message type. This value proves only
132/// the static signature at a logical address; it does not prove that an exact
133/// executable incarnation has been installed there. Addressed recipients are
134/// retained for genuine transport and name-resolution boundaries.
135pub struct Recipient<P: Protocol> {
136    address: P::Addr,
137    protocol: PhantomData<fn() -> P>,
138}
139
140impl<P: Protocol> Copy for Recipient<P> {}
141
142impl<P: Protocol> Clone for Recipient<P> {
143    fn clone(&self) -> Self {
144        *self
145    }
146}
147
148impl<P: Protocol> Recipient<P> {
149    #[must_use]
150    pub fn global(address: P::Addr) -> Self {
151        Self::new(address)
152    }
153
154    /// Return the logical address, independent of any sending actor.
155    #[must_use]
156    pub const fn address(self) -> P::Addr {
157        self.address
158    }
159
160    const fn new(address: P::Addr) -> Self {
161        Self {
162            address,
163            protocol: PhantomData,
164        }
165    }
166}
167
168impl<A: Address, M> From<A> for Recipient<MessageProtocol<A, M>> {
169    fn from(address: A) -> Self {
170        Self::new(address)
171    }
172}
173
174/// Inert capability for one exact protocol endpoint.
175///
176/// The endpoint type is selected by `P::Addr`, so `P` remains the only
177/// protocol identity and ordinary domain types carry no endpoint parameter.
178/// The endpoint has no direct accessor or send method. It crosses only an
179/// explicit interpretation boundary. That boundary is public and therefore a
180/// deliberate power-user authority boundary, not exclusive runtime authority.
181///
182/// ```compile_fail,E0599
183/// #[derive(Clone, Copy, PartialEq, Eq)]
184/// struct RuntimeAddr(u64);
185/// impl behavior::Address for RuntimeAddr { type Nonce = u64; }
186/// struct Worker;
187/// impl behavior::Protocol for Worker { type Addr = RuntimeAddr; type Msg = (); }
188/// #[derive(Clone)]
189/// struct Endpoint;
190/// impl behavior::RecipientAddress for RuntimeAddr {
191///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
192/// }
193/// let recipient = behavior::EstablishedRecipient::<Worker>::issued(Endpoint);
194/// let _endpoint = recipient.endpoint();
195/// ```
196pub struct EstablishedRecipient<P>
197where
198    P: Protocol,
199    P::Addr: RecipientAddress,
200{
201    pub(crate) endpoint: <P::Addr as RecipientAddress>::Established<P>,
202}
203
204impl<P> EstablishedRecipient<P>
205where
206    P: Protocol,
207    P::Addr: RecipientAddress,
208{
209    /// Issue a capability from an exact endpoint established or imported by
210    /// an interpreter.
211    ///
212    /// This constructor performs no allocation or validation. It proves only
213    /// protocol messaging; it never establishes a concrete behavior or
214    /// lifecycle authority.
215    #[must_use]
216    pub const fn issued(endpoint: <P::Addr as RecipientAddress>::Established<P>) -> Self {
217        Self { endpoint }
218    }
219
220    /// Transfer the endpoint through an explicit interpretation boundary.
221    pub fn interpret<I>(self, interpreter: &mut I) -> I::Output
222    where
223        I: InterpretEstablished<P>,
224    {
225        interpreter.interpret_established(self.endpoint)
226    }
227}
228
229/// Public power-user transfer boundary for one exact endpoint.
230pub trait InterpretEstablished<P>
231where
232    P: Protocol,
233    P::Addr: RecipientAddress,
234{
235    type Output;
236
237    fn interpret_established(
238        &mut self,
239        endpoint: <P::Addr as RecipientAddress>::Established<P>,
240    ) -> Self::Output;
241}
242
243impl<P> Clone for EstablishedRecipient<P>
244where
245    P: Protocol,
246    P::Addr: RecipientAddress,
247{
248    fn clone(&self) -> Self {
249        Self::issued(self.endpoint.clone())
250    }
251}
252
253impl<P> core::fmt::Debug for EstablishedRecipient<P>
254where
255    P: Protocol,
256    P::Addr: RecipientAddress,
257    <P::Addr as RecipientAddress>::Established<P>: core::fmt::Debug,
258{
259    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
260        formatter
261            .debug_tuple("EstablishedRecipient")
262            .field(&self.endpoint)
263            .finish()
264    }
265}
266
267impl<P> PartialEq for EstablishedRecipient<P>
268where
269    P: Protocol,
270    P::Addr: RecipientAddress,
271    <P::Addr as RecipientAddress>::Established<P>: PartialEq,
272{
273    fn eq(&self, other: &Self) -> bool {
274        self.endpoint == other.endpoint
275    }
276}
277
278impl<P> Eq for EstablishedRecipient<P>
279where
280    P: Protocol,
281    P::Addr: RecipientAddress,
282    <P::Addr as RecipientAddress>::Established<P>: Eq,
283{
284}
285
286/// Inert capability for one exact installed concrete behavior.
287///
288/// An established recipient proves the public protocol endpoint. This value
289/// additionally preserves which concrete behavior was installed, allowing
290/// lifecycle effects to require static evidence about that behavior's event
291/// algebra. It remains inert: no direct send, shutdown, endpoint accessor, or
292/// other ambient effect is exposed.
293///
294/// A protocol recipient cannot issue installed-actor authority:
295///
296/// ```compile_fail,E0271
297/// #[derive(Clone, Copy, Eq, PartialEq)]
298/// struct RuntimeAddr;
299/// impl behavior::Address for RuntimeAddr { type Nonce = u8; }
300/// #[derive(Clone)]
301/// struct Endpoint;
302/// struct Installed<B: behavior::Behavior>(Endpoint, std::sync::mpsc::Sender<B::Event>);
303/// impl<B: behavior::Behavior> Clone for Installed<B> {
304///     fn clone(&self) -> Self { Self(self.0.clone(), self.1.clone()) }
305/// }
306/// impl behavior::EndpointAddress for RuntimeAddr {
307///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
308///     type Installed<B> = Installed<B>
309///         where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>>;
310///     fn recipient<B>(installed: &Self::Installed<B>) -> Endpoint
311///     where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>> {
312///         installed.0.clone()
313///     }
314/// }
315/// struct Worker;
316/// impl behavior::Protocol for Worker { type Addr = RuntimeAddr; type Msg = (); }
317/// impl behavior::Behavior for Worker {
318///     type Protocol = Self;
319///     type Event = behavior::User<RuntimeAddr, ()>;
320///     type Sends = behavior::NoSends;
321///     type Ph = behavior::Never;
322///     type Error = behavior::Never;
323///     type Birth = behavior::NoBirths;
324///     fn transition(&mut self, _: behavior::ActiveTurn, _: Self::Event)
325///         -> behavior::BehaviorActed<Self> { Ok(behavior::Actions::cont()) }
326/// }
327/// let recipient = behavior::EstablishedRecipient::<Worker>::issued(Endpoint);
328/// let _: behavior::EstablishedActor<Worker> = behavior::EstablishedActor::issued(recipient);
329/// ```
330///
331/// Two behaviors sharing one protocol retain distinct installed authority:
332///
333/// ```compile_fail,E0308
334/// #[derive(Clone, Copy, Eq, PartialEq)]
335/// struct RuntimeAddr;
336/// impl behavior::Address for RuntimeAddr { type Nonce = u8; }
337/// #[derive(Clone)]
338/// struct Endpoint;
339/// struct Installed<B: behavior::Behavior>(Endpoint, std::sync::mpsc::Sender<B::Event>);
340/// impl<B: behavior::Behavior> Clone for Installed<B> {
341///     fn clone(&self) -> Self { Self(self.0.clone(), self.1.clone()) }
342/// }
343/// impl behavior::EndpointAddress for RuntimeAddr {
344///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
345///     type Installed<B> = Installed<B>
346///         where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>>;
347///     fn recipient<B>(installed: &Self::Installed<B>) -> Endpoint
348///     where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>> {
349///         installed.0.clone()
350///     }
351/// }
352/// struct Shared;
353/// impl behavior::Protocol for Shared { type Addr = RuntimeAddr; type Msg = (); }
354/// struct First;
355/// struct Second;
356/// impl behavior::Behavior for First {
357///     type Protocol = Shared;
358///     type Event = behavior::User<RuntimeAddr, ()>;
359///     type Sends = behavior::NoSends;
360///     type Ph = behavior::Never;
361///     type Error = behavior::Never;
362///     type Birth = behavior::NoBirths;
363///     fn transition(&mut self, _: behavior::ActiveTurn, _: Self::Event)
364///         -> behavior::BehaviorActed<Self> { Ok(behavior::Actions::cont()) }
365/// }
366/// impl behavior::Behavior for Second {
367///     type Protocol = Shared;
368///     type Event = behavior::EventLayer<u8, behavior::User<RuntimeAddr, ()>>;
369///     type Sends = behavior::NoSends;
370///     type Ph = behavior::Never;
371///     type Error = behavior::Never;
372///     type Birth = behavior::NoBirths;
373///     fn transition(&mut self, _: behavior::ActiveTurn, _: Self::Event)
374///         -> behavior::BehaviorActed<Self> { Ok(behavior::Actions::cont()) }
375/// }
376/// let (control, _inbox) = std::sync::mpsc::channel::<<First as behavior::Behavior>::Event>();
377/// let first = behavior::EstablishedActor::<First>::issued(Installed(Endpoint, control));
378/// let _: behavior::EstablishedActor<Second> = first;
379/// ```
380pub struct EstablishedActor<B>
381where
382    B: Behavior,
383    <B::Protocol as Protocol>::Addr: EndpointAddress,
384{
385    installed: <<B::Protocol as Protocol>::Addr as EndpointAddress>::Installed<B>,
386}
387
388impl<B> EstablishedActor<B>
389where
390    B: Behavior,
391    <B::Protocol as Protocol>::Addr: EndpointAddress,
392{
393    /// Issue an exact actor capability after successful installation.
394    ///
395    /// This power-user boundary accepts one runtime-owned installed value.
396    /// Only successful fresh installation and binding commit may issue it.
397    /// It performs no allocation or validation itself.
398    #[must_use]
399    pub const fn issued(
400        installed: <<B::Protocol as Protocol>::Addr as EndpointAddress>::Installed<B>,
401    ) -> Self {
402        Self { installed }
403    }
404
405    /// Project the exact public-protocol recipient for this incarnation.
406    #[must_use]
407    pub fn recipient(&self) -> EstablishedRecipient<B::Protocol> {
408        EstablishedRecipient::issued(
409            <<B::Protocol as Protocol>::Addr as EndpointAddress>::recipient(&self.installed),
410        )
411    }
412
413    /// Consume the concrete-actor proof and retain its exact protocol
414    /// recipient.
415    #[must_use]
416    pub fn into_recipient(self) -> EstablishedRecipient<B::Protocol> {
417        EstablishedRecipient::issued(
418            <<B::Protocol as Protocol>::Addr as EndpointAddress>::recipient(&self.installed),
419        )
420    }
421
422    /// Transfer the complete installed value with its exact `B` index.
423    pub fn interpret_actor<I>(self, interpreter: &mut I) -> I::Output
424    where
425        I: InterpretInstalledActor<B>,
426    {
427        interpreter.interpret_actor(self.installed)
428    }
429}
430
431/// Public power-user transfer boundary for one exact installed actor.
432pub trait InterpretInstalledActor<B>
433where
434    B: Behavior,
435    <B::Protocol as Protocol>::Addr: EndpointAddress,
436{
437    type Output;
438
439    fn interpret_actor(
440        &mut self,
441        installed: <<B::Protocol as Protocol>::Addr as EndpointAddress>::Installed<B>,
442    ) -> Self::Output;
443}
444
445impl<B> Clone for EstablishedActor<B>
446where
447    B: Behavior,
448    <B::Protocol as Protocol>::Addr: EndpointAddress,
449{
450    fn clone(&self) -> Self {
451        Self::issued(self.installed.clone())
452    }
453}
454
455impl<B> core::fmt::Debug for EstablishedActor<B>
456where
457    B: Behavior,
458    <B::Protocol as Protocol>::Addr: EndpointAddress,
459    <<B::Protocol as Protocol>::Addr as EndpointAddress>::Installed<B>: core::fmt::Debug,
460{
461    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
462        formatter
463            .debug_tuple("EstablishedActor")
464            .field(&self.installed)
465            .finish()
466    }
467}
468
469impl<B> PartialEq for EstablishedActor<B>
470where
471    B: Behavior,
472    <B::Protocol as Protocol>::Addr: EndpointAddress,
473    <<B::Protocol as Protocol>::Addr as EndpointAddress>::Installed<B>: PartialEq,
474{
475    fn eq(&self, other: &Self) -> bool {
476        self.installed == other.installed
477    }
478}
479
480impl<B> Eq for EstablishedActor<B>
481where
482    B: Behavior,
483    <B::Protocol as Protocol>::Addr: EndpointAddress,
484    <<B::Protocol as Protocol>::Addr as EndpointAddress>::Installed<B>: Eq,
485{
486}
487
488impl<P: Protocol> PartialEq for Recipient<P> {
489    fn eq(&self, other: &Self) -> bool {
490        self.address == other.address
491    }
492}
493
494impl<P: Protocol> Eq for Recipient<P> {}
495
496impl<P: Protocol> core::fmt::Debug for Recipient<P>
497where
498    P::Addr: core::fmt::Debug,
499    <P::Addr as Address>::Nonce: core::fmt::Debug,
500{
501    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
502        self.address.fmt(f)
503    }
504}
505
506/// One pure communication addressed to a concrete protocol signature.
507///
508/// Protocol identity is not inferred from the payload. Consequently, two
509/// protocols with the same address and message types still have distinct
510/// delivery types.
511///
512/// ```compile_fail,E0308
513/// struct Queue;
514/// struct Worker;
515/// impl behavior::Protocol for Queue {
516///     type Addr = behavior::MailAddr;
517///     type Msg = u8;
518/// }
519/// impl behavior::Protocol for Worker {
520///     type Addr = behavior::MailAddr;
521///     type Msg = u8;
522/// }
523///
524/// let worker = behavior::Recipient::<Worker>::global(behavior::MailAddr(1));
525/// let _: behavior::Delivery<Queue> = behavior::Delivery::new(worker, 7);
526/// ```
527///
528/// A destination also fixes its message and address namespaces:
529///
530/// ```compile_fail,E0308
531/// #[derive(Clone, Copy, PartialEq, Eq)]
532/// struct OtherAddr(u64);
533/// impl behavior::Address for OtherAddr {
534///     type Nonce = u64;
535/// }
536/// struct Worker;
537/// impl behavior::Protocol for Worker {
538///     type Addr = behavior::MailAddr;
539///     type Msg = u8;
540/// }
541/// let _ = behavior::Recipient::<Worker>::global(OtherAddr(1));
542/// ```
543///
544/// ```compile_fail,E0308
545/// # struct Worker;
546/// # impl behavior::Protocol for Worker {
547/// #     type Addr = behavior::MailAddr;
548/// #     type Msg = u8;
549/// # }
550/// let worker = behavior::Recipient::<Worker>::global(behavior::MailAddr(1));
551/// let _ = behavior::Delivery::<Worker>::new(worker, "wrong payload");
552/// ```
553/// Exact reason one logical delivery was not accepted.
554#[derive(Clone, Copy, Debug, Eq, PartialEq)]
555pub enum LogicalDeliveryReason {
556    UnknownAddress,
557    ClosedRecipient,
558}
559
560/// Exact reason one established delivery was not accepted.
561#[derive(Clone, Copy, Debug, Eq, PartialEq)]
562pub enum ExactDeliveryReason {
563    ClosedRecipient,
564}
565
566pub struct Delivery<P: Protocol> {
567    pub to: Recipient<P>,
568    pub message: P::Msg,
569}
570
571impl<P: Protocol> Delivery<P> {
572    #[must_use]
573    pub fn new(to: Recipient<P>, message: P::Msg) -> Self {
574        Self { to, message }
575    }
576}
577
578impl<P> Clone for Delivery<P>
579where
580    P: Protocol,
581    P::Msg: Clone,
582{
583    fn clone(&self) -> Self {
584        Self {
585            to: self.to,
586            message: self.message.clone(),
587        }
588    }
589}
590
591impl<P> PartialEq for Delivery<P>
592where
593    P: Protocol,
594    P::Msg: PartialEq,
595{
596    fn eq(&self, other: &Self) -> bool {
597        self.to == other.to && self.message == other.message
598    }
599}
600
601impl<P> Eq for Delivery<P>
602where
603    P: Protocol,
604    P::Msg: Eq,
605{
606}
607
608impl<P> ActionItem for Delivery<P>
609where
610    P: Protocol,
611    P::Addr: Send,
612    P::Msg: Send,
613{
614    type Accepted = ();
615    type Rejection = LogicalDeliveryReason;
616    type Prerequisite = Never;
617}
618
619/// One pure communication to an exact installed incarnation.
620///
621/// Unlike [`Delivery`], this effect carries the runtime-issued endpoint and
622/// requires no address-to-endpoint resolution. Constructing it remains pure;
623/// only an explicit [`crate::InterpretItem`] implementation for this exact
624/// delivery type can
625/// perform the communication.
626///
627/// Exact endpoints remain protocol-indexed even when two protocols share an
628/// address namespace and message type:
629///
630/// ```compile_fail,E0308
631/// #[derive(Clone, Copy, PartialEq, Eq)]
632/// struct RuntimeAddr(u64);
633/// impl behavior::Address for RuntimeAddr { type Nonce = u64; }
634/// struct Endpoint<P>(core::marker::PhantomData<fn() -> P>);
635/// impl<P> Clone for Endpoint<P> {
636///     fn clone(&self) -> Self { Self(core::marker::PhantomData) }
637/// }
638/// impl behavior::RecipientAddress for RuntimeAddr {
639///     type Established<P> = Endpoint<P> where P: behavior::Protocol<Addr = Self>;
640/// }
641/// struct Queue;
642/// struct Worker;
643/// impl behavior::Protocol for Queue { type Addr = RuntimeAddr; type Msg = u8; }
644/// impl behavior::Protocol for Worker { type Addr = RuntimeAddr; type Msg = u8; }
645/// let worker = behavior::EstablishedRecipient::<Worker>::issued(Endpoint(core::marker::PhantomData));
646/// let _: behavior::EstablishedDelivery<Queue> = behavior::EstablishedDelivery::new(worker, 7);
647/// ```
648pub struct EstablishedDelivery<P>
649where
650    P: Protocol,
651    P::Addr: RecipientAddress,
652{
653    pub to: EstablishedRecipient<P>,
654    pub message: P::Msg,
655}
656
657impl<P> EstablishedDelivery<P>
658where
659    P: Protocol,
660    P::Addr: RecipientAddress,
661{
662    #[must_use]
663    pub const fn new(to: EstablishedRecipient<P>, message: P::Msg) -> Self {
664        Self { to, message }
665    }
666}
667
668impl<P> Clone for EstablishedDelivery<P>
669where
670    P: Protocol,
671    P::Addr: RecipientAddress,
672    P::Msg: Clone,
673{
674    fn clone(&self) -> Self {
675        Self::new(self.to.clone(), self.message.clone())
676    }
677}
678
679impl<P> core::fmt::Debug for EstablishedDelivery<P>
680where
681    P: Protocol,
682    P::Addr: RecipientAddress,
683    EstablishedRecipient<P>: core::fmt::Debug,
684    P::Msg: core::fmt::Debug,
685{
686    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
687        formatter
688            .debug_struct("EstablishedDelivery")
689            .field("to", &self.to)
690            .field("message", &self.message)
691            .finish()
692    }
693}
694
695impl<P> PartialEq for EstablishedDelivery<P>
696where
697    P: Protocol,
698    P::Addr: RecipientAddress,
699    EstablishedRecipient<P>: PartialEq,
700    P::Msg: PartialEq,
701{
702    fn eq(&self, other: &Self) -> bool {
703        self.to == other.to && self.message == other.message
704    }
705}
706
707impl<P> Eq for EstablishedDelivery<P>
708where
709    P: Protocol,
710    P::Addr: RecipientAddress,
711    EstablishedRecipient<P>: Eq,
712    P::Msg: Eq,
713{
714}
715
716impl<P> ActionItem for EstablishedDelivery<P>
717where
718    P: Protocol,
719    P::Addr: RecipientAddress,
720    <P::Addr as RecipientAddress>::Established<P>: Send,
721    P::Msg: Send,
722{
723    type Accepted = ();
724    type Rejection = ExactDeliveryReason;
725    type Prerequisite = Never;
726}
727
728#[cfg(test)]
729mod tests {
730    use super::*;
731    use crate::{Actions, Never, NoBirths, User};
732    use std::rc::Rc;
733
734    struct Inbox;
735
736    struct SignatureOnly;
737
738    #[derive(Clone, Copy, PartialEq, Eq)]
739    struct LocalAddr(u8);
740
741    impl Address for LocalAddr {
742        type Nonce = u8;
743    }
744
745    struct LocalProtocol;
746
747    impl Protocol for LocalProtocol {
748        type Addr = LocalAddr;
749        type Msg = u8;
750    }
751
752    struct LocalEndpoint<P> {
753        token: Rc<()>,
754        protocol: PhantomData<fn() -> P>,
755    }
756
757    impl<P> Clone for LocalEndpoint<P> {
758        fn clone(&self) -> Self {
759            Self {
760                token: self.token.clone(),
761                protocol: PhantomData,
762            }
763        }
764    }
765
766    impl<P> core::fmt::Debug for LocalEndpoint<P> {
767        fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
768            formatter.write_str("LocalEndpoint")
769        }
770    }
771
772    impl<P> PartialEq for LocalEndpoint<P> {
773        fn eq(&self, other: &Self) -> bool {
774            Rc::ptr_eq(&self.token, &other.token)
775        }
776    }
777
778    impl<P> Eq for LocalEndpoint<P> {}
779
780    struct LocalInstalled<B: Behavior> {
781        endpoint: LocalEndpoint<B::Protocol>,
782        control: std::sync::mpsc::Sender<B::Event>,
783        incarnation: Rc<()>,
784    }
785
786    impl<B: Behavior> Clone for LocalInstalled<B> {
787        fn clone(&self) -> Self {
788            Self {
789                endpoint: self.endpoint.clone(),
790                control: self.control.clone(),
791                incarnation: self.incarnation.clone(),
792            }
793        }
794    }
795
796    impl<B: Behavior> core::fmt::Debug for LocalInstalled<B> {
797        fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
798            formatter.write_str("LocalInstalled")
799        }
800    }
801
802    impl<B: Behavior> PartialEq for LocalInstalled<B> {
803        fn eq(&self, other: &Self) -> bool {
804            Rc::ptr_eq(&self.incarnation, &other.incarnation)
805        }
806    }
807
808    impl<B: Behavior> Eq for LocalInstalled<B> {}
809
810    impl EndpointAddress for LocalAddr {
811        type Established<P>
812            = LocalEndpoint<P>
813        where
814            P: Protocol<Addr = Self>;
815
816        type Installed<B>
817            = LocalInstalled<B>
818        where
819            B: Behavior<Protocol: Protocol<Addr = Self>>;
820
821        fn recipient<B>(installed: &Self::Installed<B>) -> Self::Established<B::Protocol>
822        where
823            B: Behavior<Protocol: Protocol<Addr = Self>>,
824        {
825            installed.endpoint.clone()
826        }
827    }
828
829    struct LocalTransfer;
830
831    impl InterpretEstablished<LocalProtocol> for LocalTransfer {
832        type Output = Rc<()>;
833
834        fn interpret_established(
835            &mut self,
836            endpoint: LocalEndpoint<LocalProtocol>,
837        ) -> Self::Output {
838            endpoint.token
839        }
840    }
841
842    struct LocalEndpointTransfer;
843
844    impl InterpretEstablished<LocalProtocol> for LocalEndpointTransfer {
845        type Output = LocalEndpoint<LocalProtocol>;
846
847        fn interpret_established(
848            &mut self,
849            endpoint: LocalEndpoint<LocalProtocol>,
850        ) -> Self::Output {
851            endpoint
852        }
853    }
854
855    struct LocalBehavior;
856
857    impl Behavior for LocalBehavior {
858        type Protocol = LocalProtocol;
859        type Event = User<LocalAddr, u8>;
860        type Sends = Vec<Never>;
861        type Ph = Never;
862        type Error = Never;
863        type Birth = NoBirths;
864
865        fn transition(
866            &mut self,
867            _: crate::ActiveTurn,
868            _: Self::Event,
869        ) -> crate::BehaviorActed<Self> {
870            Ok(Actions::cont())
871        }
872    }
873
874    impl crate::Protocol for SignatureOnly {
875        type Addr = MailAddr;
876        type Msg = u8;
877    }
878
879    impl behavior::Protocol for Inbox {
880        type Addr = MailAddr;
881        type Msg = u8;
882    }
883
884    impl Behavior for Inbox {
885        type Protocol = Self;
886        type Event = User<MailAddr, u8>;
887        type Sends = Vec<Never>;
888        type Ph = Never;
889        type Error = Never;
890        type Birth = NoBirths;
891
892        fn init(&mut self, _: crate::InitializationTurn) -> crate::BehaviorActed<Self> {
893            Ok(Actions::cont())
894        }
895
896        fn transition(
897            &mut self,
898            _: crate::ActiveTurn,
899            _: Self::Event,
900        ) -> crate::BehaviorActed<Self> {
901            Ok(Actions::cont())
902        }
903    }
904
905    #[test]
906    fn mail_address_conversion_preserves_nonzero_value() {
907        assert_eq!(u64::from(MailAddr(41)), 41);
908    }
909
910    #[test]
911    fn routing_requires_only_the_static_protocol_signature() {
912        let recipient = Recipient::<SignatureOnly>::global(MailAddr(7));
913        let delivery = Delivery::new(recipient, 11);
914
915        assert_eq!(delivery.to.address(), MailAddr(7));
916        assert_eq!(delivery.message, 11);
917    }
918
919    #[test]
920    fn recipient_value_contract_distinguishes_logical_addresses() {
921        let global = Recipient::<Inbox>::global(MailAddr(7));
922        let same_global = Recipient::<Inbox>::global(MailAddr(7));
923        let other_global = Recipient::<Inbox>::global(MailAddr(8));
924
925        assert_eq!(global, same_global);
926        assert_ne!(global, other_global);
927        assert_eq!(global.address(), MailAddr(7));
928        assert_eq!(format!("{global:?}"), "MailAddr(7)");
929    }
930
931    #[test]
932    fn established_capability_accepts_a_local_non_send_endpoint() {
933        let token = Rc::new(());
934        let recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
935            token: token.clone(),
936            protocol: PhantomData,
937        });
938        let retained = recipient.clone();
939        let extracted = retained.interpret(&mut LocalTransfer);
940
941        assert!(Rc::ptr_eq(&token, &extracted));
942        drop(recipient);
943    }
944
945    #[test]
946    fn established_values_compare_complete_identity_and_expose_debug_shape() {
947        let token = Rc::new(());
948        let other_token = Rc::new(());
949        let recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
950            token: token.clone(),
951            protocol: PhantomData,
952        });
953        let same_recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
954            token,
955            protocol: PhantomData,
956        });
957        let other_recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
958            token: other_token,
959            protocol: PhantomData,
960        });
961
962        assert_eq!(recipient, same_recipient);
963        assert_ne!(recipient, other_recipient);
964        assert_eq!(
965            format!("{recipient:?}"),
966            "EstablishedRecipient(LocalEndpoint)"
967        );
968
969        let (control, _consumer) = std::sync::mpsc::channel();
970        let installed = LocalInstalled {
971            endpoint: recipient.clone().interpret(&mut LocalEndpointTransfer),
972            control,
973            incarnation: Rc::new(()),
974        };
975        let actor = EstablishedActor::<LocalBehavior>::issued(installed.clone());
976        let same_actor = EstablishedActor::<LocalBehavior>::issued(installed);
977        let (other_control, _other_consumer) = std::sync::mpsc::channel();
978        let other_actor = EstablishedActor::<LocalBehavior>::issued(LocalInstalled {
979            endpoint: other_recipient
980                .clone()
981                .interpret(&mut LocalEndpointTransfer),
982            control: other_control,
983            incarnation: Rc::new(()),
984        });
985        assert_eq!(actor, same_actor);
986        assert_ne!(actor, other_actor);
987        assert_eq!(format!("{actor:?}"), "EstablishedActor(LocalInstalled)");
988
989        let delivery = EstablishedDelivery::new(recipient, 7);
990        let same_delivery = EstablishedDelivery::new(same_recipient.clone(), 7);
991        let other_destination = EstablishedDelivery::new(other_recipient.clone(), 7);
992        let other_message = EstablishedDelivery::new(same_recipient, 9);
993        let both_different = EstablishedDelivery::new(other_recipient, 9);
994        assert_eq!(delivery, same_delivery);
995        assert_ne!(delivery, other_destination);
996        assert_ne!(delivery, other_message);
997        assert_ne!(delivery, both_different);
998        assert_eq!(
999            format!("{delivery:?}"),
1000            "EstablishedDelivery { to: EstablishedRecipient(LocalEndpoint), message: 7 }"
1001        );
1002    }
1003
1004    #[test]
1005    fn delivery_equality_requires_both_destination_and_message() {
1006        let value = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 5);
1007        let same = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 5);
1008        let other_destination = Delivery::<Inbox>::new(Recipient::global(MailAddr(2)), 5);
1009        let other_message = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 6);
1010        let both_different = Delivery::<Inbox>::new(Recipient::global(MailAddr(2)), 6);
1011
1012        assert!(value == same);
1013        assert!(value != other_destination);
1014        assert!(value != other_message);
1015        assert!(value != both_different);
1016    }
1017}