1use core::marker::PhantomData;
4
5use crate::{ActionItem, Behavior, MessageProtocol, Never, Protocol};
6
7pub 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
36pub trait EndpointAddress: Address + Sized {
99 type Established<P>: Clone
100 where
101 P: Protocol<Addr = Self>;
102}
103
104pub struct Recipient<P: Protocol> {
112 address: P::Addr,
113 protocol: PhantomData<fn() -> P>,
114}
115
116impl<P: Protocol> Copy for Recipient<P> {}
117
118impl<P: Protocol> Clone for Recipient<P> {
119 fn clone(&self) -> Self {
120 *self
121 }
122}
123
124impl<P: Protocol> Recipient<P> {
125 #[must_use]
126 pub fn global(address: P::Addr) -> Self {
127 Self::new(address)
128 }
129
130 #[must_use]
132 pub const fn address(self) -> P::Addr {
133 self.address
134 }
135
136 #[doc(hidden)]
137 const fn new(address: P::Addr) -> Self {
138 Self {
139 address,
140 protocol: PhantomData,
141 }
142 }
143}
144
145impl<A: Address, M> From<A> for Recipient<MessageProtocol<A, M>> {
146 fn from(address: A) -> Self {
147 Self::new(address)
148 }
149}
150
151pub struct EstablishedRecipient<P>
175where
176 P: Protocol,
177 P::Addr: EndpointAddress,
178{
179 pub(crate) endpoint: <P::Addr as EndpointAddress>::Established<P>,
180}
181
182impl<P> EstablishedRecipient<P>
183where
184 P: Protocol,
185 P::Addr: EndpointAddress,
186{
187 #[must_use]
194 pub const fn issued(endpoint: <P::Addr as EndpointAddress>::Established<P>) -> Self {
195 Self { endpoint }
196 }
197
198 pub fn interpret<I>(self, interpreter: &mut I) -> I::Output
200 where
201 I: InterpretEstablished<P>,
202 {
203 interpreter.interpret_established(self.endpoint)
204 }
205}
206
207pub trait InterpretEstablished<P>
209where
210 P: Protocol,
211 P::Addr: EndpointAddress,
212{
213 type Output;
214
215 fn interpret_established(
216 &mut self,
217 endpoint: <P::Addr as EndpointAddress>::Established<P>,
218 ) -> Self::Output;
219}
220
221impl<P> Clone for EstablishedRecipient<P>
222where
223 P: Protocol,
224 P::Addr: EndpointAddress,
225{
226 fn clone(&self) -> Self {
227 Self::issued(self.endpoint.clone())
228 }
229}
230
231impl<P> core::fmt::Debug for EstablishedRecipient<P>
232where
233 P: Protocol,
234 P::Addr: EndpointAddress,
235 <P::Addr as EndpointAddress>::Established<P>: core::fmt::Debug,
236{
237 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
238 formatter
239 .debug_tuple("EstablishedRecipient")
240 .field(&self.endpoint)
241 .finish()
242 }
243}
244
245impl<P> PartialEq for EstablishedRecipient<P>
246where
247 P: Protocol,
248 P::Addr: EndpointAddress,
249 <P::Addr as EndpointAddress>::Established<P>: PartialEq,
250{
251 fn eq(&self, other: &Self) -> bool {
252 self.endpoint == other.endpoint
253 }
254}
255
256impl<P> Eq for EstablishedRecipient<P>
257where
258 P: Protocol,
259 P::Addr: EndpointAddress,
260 <P::Addr as EndpointAddress>::Established<P>: Eq,
261{
262}
263
264pub struct EstablishedActor<B>
272where
273 B: Behavior,
274 <B::Protocol as Protocol>::Addr: EndpointAddress,
275{
276 recipient: EstablishedRecipient<B::Protocol>,
277 behavior: PhantomData<fn() -> B>,
278}
279
280impl<B> EstablishedActor<B>
281where
282 B: Behavior,
283 <B::Protocol as Protocol>::Addr: EndpointAddress,
284{
285 #[must_use]
291 pub const fn issued(
292 endpoint: <<B::Protocol as Protocol>::Addr as EndpointAddress>::Established<B::Protocol>,
293 ) -> Self {
294 Self {
295 recipient: EstablishedRecipient::issued(endpoint),
296 behavior: PhantomData,
297 }
298 }
299
300 pub(crate) const fn from_recipient(recipient: EstablishedRecipient<B::Protocol>) -> Self {
301 Self {
302 recipient,
303 behavior: PhantomData,
304 }
305 }
306
307 #[must_use]
309 pub fn recipient(&self) -> EstablishedRecipient<B::Protocol> {
310 self.recipient.clone()
311 }
312
313 #[must_use]
316 pub fn into_recipient(self) -> EstablishedRecipient<B::Protocol> {
317 self.recipient
318 }
319
320 pub fn interpret<I>(self, interpreter: &mut I) -> I::Output
323 where
324 I: InterpretEstablished<B::Protocol>,
325 {
326 self.recipient.interpret(interpreter)
327 }
328}
329
330impl<B> Clone for EstablishedActor<B>
331where
332 B: Behavior,
333 <B::Protocol as Protocol>::Addr: EndpointAddress,
334{
335 fn clone(&self) -> Self {
336 Self {
337 recipient: self.recipient.clone(),
338 behavior: PhantomData,
339 }
340 }
341}
342
343impl<B> core::fmt::Debug for EstablishedActor<B>
344where
345 B: Behavior,
346 <B::Protocol as Protocol>::Addr: EndpointAddress,
347 <<B::Protocol as Protocol>::Addr as EndpointAddress>::Established<B::Protocol>:
348 core::fmt::Debug,
349{
350 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
351 formatter
352 .debug_tuple("EstablishedActor")
353 .field(&self.recipient)
354 .finish()
355 }
356}
357
358impl<B> PartialEq for EstablishedActor<B>
359where
360 B: Behavior,
361 <B::Protocol as Protocol>::Addr: EndpointAddress,
362 <<B::Protocol as Protocol>::Addr as EndpointAddress>::Established<B::Protocol>: PartialEq,
363{
364 fn eq(&self, other: &Self) -> bool {
365 self.recipient == other.recipient
366 }
367}
368
369impl<B> Eq for EstablishedActor<B>
370where
371 B: Behavior,
372 <B::Protocol as Protocol>::Addr: EndpointAddress,
373 <<B::Protocol as Protocol>::Addr as EndpointAddress>::Established<B::Protocol>: Eq,
374{
375}
376
377impl<P: Protocol> PartialEq for Recipient<P> {
378 fn eq(&self, other: &Self) -> bool {
379 self.address == other.address
380 }
381}
382
383impl<P: Protocol> Eq for Recipient<P> {}
384
385impl<P: Protocol> core::fmt::Debug for Recipient<P>
386where
387 P::Addr: core::fmt::Debug,
388 <P::Addr as Address>::Nonce: core::fmt::Debug,
389{
390 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
391 self.address.fmt(f)
392 }
393}
394
395#[derive(Clone, Copy, Debug, Eq, PartialEq)]
480pub enum LogicalDeliveryReason {
481 UnknownAddress,
482 ClosedRecipient,
483}
484
485#[derive(Clone, Copy, Debug, Eq, PartialEq)]
487pub enum ExactDeliveryReason {
488 ClosedRecipient,
489}
490
491pub struct Delivery<P: Protocol> {
492 pub to: Recipient<P>,
493 pub message: P::Msg,
494}
495
496impl<P: Protocol> Delivery<P> {
497 #[must_use]
498 pub fn new(to: Recipient<P>, message: P::Msg) -> Self {
499 Self { to, message }
500 }
501}
502
503impl<P> Clone for Delivery<P>
504where
505 P: Protocol,
506 P::Msg: Clone,
507{
508 fn clone(&self) -> Self {
509 Self {
510 to: self.to,
511 message: self.message.clone(),
512 }
513 }
514}
515
516impl<P> PartialEq for Delivery<P>
517where
518 P: Protocol,
519 P::Msg: PartialEq,
520{
521 fn eq(&self, other: &Self) -> bool {
522 self.to == other.to && self.message == other.message
523 }
524}
525
526impl<P> Eq for Delivery<P>
527where
528 P: Protocol,
529 P::Msg: Eq,
530{
531}
532
533impl<P> ActionItem for Delivery<P>
534where
535 P: Protocol,
536 P::Addr: Send,
537 P::Msg: Send,
538{
539 type Accepted = ();
540 type Rejection = LogicalDeliveryReason;
541 type Prerequisite = Never;
542}
543
544pub struct EstablishedDelivery<P>
579where
580 P: Protocol,
581 P::Addr: EndpointAddress,
582{
583 pub to: EstablishedRecipient<P>,
584 pub message: P::Msg,
585}
586
587impl<P> EstablishedDelivery<P>
588where
589 P: Protocol,
590 P::Addr: EndpointAddress,
591{
592 #[must_use]
593 pub const fn new(to: EstablishedRecipient<P>, message: P::Msg) -> Self {
594 Self { to, message }
595 }
596}
597
598impl<P> Clone for EstablishedDelivery<P>
599where
600 P: Protocol,
601 P::Addr: EndpointAddress,
602 P::Msg: Clone,
603{
604 fn clone(&self) -> Self {
605 Self::new(self.to.clone(), self.message.clone())
606 }
607}
608
609impl<P> core::fmt::Debug for EstablishedDelivery<P>
610where
611 P: Protocol,
612 P::Addr: EndpointAddress,
613 EstablishedRecipient<P>: core::fmt::Debug,
614 P::Msg: core::fmt::Debug,
615{
616 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
617 formatter
618 .debug_struct("EstablishedDelivery")
619 .field("to", &self.to)
620 .field("message", &self.message)
621 .finish()
622 }
623}
624
625impl<P> PartialEq for EstablishedDelivery<P>
626where
627 P: Protocol,
628 P::Addr: EndpointAddress,
629 EstablishedRecipient<P>: PartialEq,
630 P::Msg: PartialEq,
631{
632 fn eq(&self, other: &Self) -> bool {
633 self.to == other.to && self.message == other.message
634 }
635}
636
637impl<P> Eq for EstablishedDelivery<P>
638where
639 P: Protocol,
640 P::Addr: EndpointAddress,
641 EstablishedRecipient<P>: Eq,
642 P::Msg: Eq,
643{
644}
645
646impl<P> ActionItem for EstablishedDelivery<P>
647where
648 P: Protocol,
649 P::Addr: EndpointAddress,
650 <P::Addr as EndpointAddress>::Established<P>: Send,
651 P::Msg: Send,
652{
653 type Accepted = ();
654 type Rejection = ExactDeliveryReason;
655 type Prerequisite = Never;
656}
657
658#[cfg(test)]
659mod tests {
660 use super::*;
661 use crate::{Actions, Never, NoBirths, User};
662 use std::rc::Rc;
663
664 struct Inbox;
665
666 struct SignatureOnly;
667
668 #[derive(Clone, Copy, PartialEq, Eq)]
669 struct LocalAddr(u8);
670
671 impl Address for LocalAddr {
672 type Nonce = u8;
673 }
674
675 struct LocalProtocol;
676
677 impl Protocol for LocalProtocol {
678 type Addr = LocalAddr;
679 type Msg = u8;
680 }
681
682 struct LocalEndpoint<P> {
683 token: Rc<()>,
684 protocol: PhantomData<fn() -> P>,
685 }
686
687 impl<P> Clone for LocalEndpoint<P> {
688 fn clone(&self) -> Self {
689 Self {
690 token: self.token.clone(),
691 protocol: PhantomData,
692 }
693 }
694 }
695
696 impl<P> core::fmt::Debug for LocalEndpoint<P> {
697 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
698 formatter.write_str("LocalEndpoint")
699 }
700 }
701
702 impl<P> PartialEq for LocalEndpoint<P> {
703 fn eq(&self, other: &Self) -> bool {
704 Rc::ptr_eq(&self.token, &other.token)
705 }
706 }
707
708 impl<P> Eq for LocalEndpoint<P> {}
709
710 impl EndpointAddress for LocalAddr {
711 type Established<P>
712 = LocalEndpoint<P>
713 where
714 P: Protocol<Addr = Self>;
715 }
716
717 struct LocalTransfer;
718
719 impl InterpretEstablished<LocalProtocol> for LocalTransfer {
720 type Output = Rc<()>;
721
722 fn interpret_established(
723 &mut self,
724 endpoint: LocalEndpoint<LocalProtocol>,
725 ) -> Self::Output {
726 endpoint.token
727 }
728 }
729
730 struct LocalBehavior;
731
732 impl Behavior for LocalBehavior {
733 type Protocol = LocalProtocol;
734 type Event = User<LocalAddr, u8>;
735 type Sends = Vec<Never>;
736 type Ph = Never;
737 type Error = Never;
738 type Birth = NoBirths;
739
740 fn transition(
741 &mut self,
742 _: crate::ActiveTurn,
743 _: Self::Event,
744 ) -> crate::BehaviorActed<Self> {
745 Ok(Actions::cont())
746 }
747 }
748
749 impl crate::Protocol for SignatureOnly {
750 type Addr = MailAddr;
751 type Msg = u8;
752 }
753
754 impl behavior::Protocol for Inbox {
755 type Addr = MailAddr;
756 type Msg = u8;
757 }
758
759 impl Behavior for Inbox {
760 type Protocol = Self;
761 type Event = User<MailAddr, u8>;
762 type Sends = Vec<Never>;
763 type Ph = Never;
764 type Error = Never;
765 type Birth = NoBirths;
766
767 fn init(&mut self, _: crate::InitializationTurn) -> crate::BehaviorActed<Self> {
768 Ok(Actions::cont())
769 }
770
771 fn transition(
772 &mut self,
773 _: crate::ActiveTurn,
774 _: Self::Event,
775 ) -> crate::BehaviorActed<Self> {
776 Ok(Actions::cont())
777 }
778 }
779
780 #[test]
781 fn mail_address_conversion_preserves_nonzero_value() {
782 assert_eq!(u64::from(MailAddr(41)), 41);
783 }
784
785 #[test]
786 fn routing_requires_only_the_static_protocol_signature() {
787 let recipient = Recipient::<SignatureOnly>::global(MailAddr(7));
788 let delivery = Delivery::new(recipient, 11);
789
790 assert_eq!(delivery.to.address(), MailAddr(7));
791 assert_eq!(delivery.message, 11);
792 }
793
794 #[test]
795 fn recipient_value_contract_distinguishes_logical_addresses() {
796 let global = Recipient::<Inbox>::global(MailAddr(7));
797 let same_global = Recipient::<Inbox>::global(MailAddr(7));
798 let other_global = Recipient::<Inbox>::global(MailAddr(8));
799
800 assert_eq!(global, same_global);
801 assert_ne!(global, other_global);
802 assert_eq!(global.address(), MailAddr(7));
803 assert_eq!(format!("{global:?}"), "MailAddr(7)");
804 }
805
806 #[test]
807 fn established_capability_accepts_a_local_non_send_endpoint() {
808 let token = Rc::new(());
809 let recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
810 token: token.clone(),
811 protocol: PhantomData,
812 });
813 let retained = recipient.clone();
814 let extracted = retained.interpret(&mut LocalTransfer);
815
816 assert!(Rc::ptr_eq(&token, &extracted));
817 drop(recipient);
818 }
819
820 #[test]
821 fn established_values_compare_complete_identity_and_expose_debug_shape() {
822 let token = Rc::new(());
823 let other_token = Rc::new(());
824 let recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
825 token: token.clone(),
826 protocol: PhantomData,
827 });
828 let same_recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
829 token,
830 protocol: PhantomData,
831 });
832 let other_recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
833 token: other_token,
834 protocol: PhantomData,
835 });
836
837 assert_eq!(recipient, same_recipient);
838 assert_ne!(recipient, other_recipient);
839 assert_eq!(
840 format!("{recipient:?}"),
841 "EstablishedRecipient(LocalEndpoint)"
842 );
843
844 let actor = EstablishedActor::<LocalBehavior>::from_recipient(recipient.clone());
845 let same_actor = EstablishedActor::<LocalBehavior>::from_recipient(same_recipient.clone());
846 let other_actor =
847 EstablishedActor::<LocalBehavior>::from_recipient(other_recipient.clone());
848 assert_eq!(actor, same_actor);
849 assert_ne!(actor, other_actor);
850 assert_eq!(
851 format!("{actor:?}"),
852 "EstablishedActor(EstablishedRecipient(LocalEndpoint))"
853 );
854
855 let delivery = EstablishedDelivery::new(recipient, 7);
856 let same_delivery = EstablishedDelivery::new(same_recipient.clone(), 7);
857 let other_destination = EstablishedDelivery::new(other_recipient.clone(), 7);
858 let other_message = EstablishedDelivery::new(same_recipient, 9);
859 let both_different = EstablishedDelivery::new(other_recipient, 9);
860 assert_eq!(delivery, same_delivery);
861 assert_ne!(delivery, other_destination);
862 assert_ne!(delivery, other_message);
863 assert_ne!(delivery, both_different);
864 assert_eq!(
865 format!("{delivery:?}"),
866 "EstablishedDelivery { to: EstablishedRecipient(LocalEndpoint), message: 7 }"
867 );
868 }
869
870 #[test]
871 fn delivery_equality_requires_both_destination_and_message() {
872 let value = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 5);
873 let same = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 5);
874 let other_destination = Delivery::<Inbox>::new(Recipient::global(MailAddr(2)), 5);
875 let other_message = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 6);
876 let both_different = Delivery::<Inbox>::new(Recipient::global(MailAddr(2)), 6);
877
878 assert!(value == same);
879 assert!(value != other_destination);
880 assert!(value != other_message);
881 assert!(value != both_different);
882 }
883}