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 {
93 type Established<P>: Clone
94 where
95 P: Protocol<Addr = Self>;
96}
97
98pub struct Recipient<P: Protocol> {
106 address: P::Addr,
107 protocol: PhantomData<fn() -> P>,
108}
109
110impl<P: Protocol> Copy for Recipient<P> {}
111
112impl<P: Protocol> Clone for Recipient<P> {
113 fn clone(&self) -> Self {
114 *self
115 }
116}
117
118impl<P: Protocol> Recipient<P> {
119 #[must_use]
120 pub fn global(address: P::Addr) -> Self {
121 Self::new(address)
122 }
123
124 #[must_use]
126 pub const fn address(self) -> P::Addr {
127 self.address
128 }
129
130 const fn new(address: P::Addr) -> Self {
131 Self {
132 address,
133 protocol: PhantomData,
134 }
135 }
136}
137
138impl<A: Address, M> From<A> for Recipient<MessageProtocol<A, M>> {
139 fn from(address: A) -> Self {
140 Self::new(address)
141 }
142}
143
144pub struct EstablishedRecipient<P>
167where
168 P: Protocol,
169 P::Addr: EndpointAddress,
170{
171 pub(crate) endpoint: <P::Addr as EndpointAddress>::Established<P>,
172}
173
174impl<P> EstablishedRecipient<P>
175where
176 P: Protocol,
177 P::Addr: EndpointAddress,
178{
179 #[must_use]
186 pub const fn issued(endpoint: <P::Addr as EndpointAddress>::Established<P>) -> Self {
187 Self { endpoint }
188 }
189
190 pub fn interpret<I>(self, interpreter: &mut I) -> I::Output
192 where
193 I: InterpretEstablished<P>,
194 {
195 interpreter.interpret_established(self.endpoint)
196 }
197}
198
199pub trait InterpretEstablished<P>
201where
202 P: Protocol,
203 P::Addr: EndpointAddress,
204{
205 type Output;
206
207 fn interpret_established(
208 &mut self,
209 endpoint: <P::Addr as EndpointAddress>::Established<P>,
210 ) -> Self::Output;
211}
212
213impl<P> Clone for EstablishedRecipient<P>
214where
215 P: Protocol,
216 P::Addr: EndpointAddress,
217{
218 fn clone(&self) -> Self {
219 Self::issued(self.endpoint.clone())
220 }
221}
222
223impl<P> core::fmt::Debug for EstablishedRecipient<P>
224where
225 P: Protocol,
226 P::Addr: EndpointAddress,
227 <P::Addr as EndpointAddress>::Established<P>: core::fmt::Debug,
228{
229 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
230 formatter
231 .debug_tuple("EstablishedRecipient")
232 .field(&self.endpoint)
233 .finish()
234 }
235}
236
237impl<P> PartialEq for EstablishedRecipient<P>
238where
239 P: Protocol,
240 P::Addr: EndpointAddress,
241 <P::Addr as EndpointAddress>::Established<P>: PartialEq,
242{
243 fn eq(&self, other: &Self) -> bool {
244 self.endpoint == other.endpoint
245 }
246}
247
248impl<P> Eq for EstablishedRecipient<P>
249where
250 P: Protocol,
251 P::Addr: EndpointAddress,
252 <P::Addr as EndpointAddress>::Established<P>: Eq,
253{
254}
255
256pub struct EstablishedActor<B>
264where
265 B: Behavior,
266 <B::Protocol as Protocol>::Addr: EndpointAddress,
267{
268 recipient: EstablishedRecipient<B::Protocol>,
269 behavior: PhantomData<fn() -> B>,
270}
271
272impl<B> EstablishedActor<B>
273where
274 B: Behavior,
275 <B::Protocol as Protocol>::Addr: EndpointAddress,
276{
277 #[must_use]
283 pub const fn issued(
284 endpoint: <<B::Protocol as Protocol>::Addr as EndpointAddress>::Established<B::Protocol>,
285 ) -> Self {
286 Self {
287 recipient: EstablishedRecipient::issued(endpoint),
288 behavior: PhantomData,
289 }
290 }
291
292 pub(crate) const fn from_recipient(recipient: EstablishedRecipient<B::Protocol>) -> Self {
293 Self {
294 recipient,
295 behavior: PhantomData,
296 }
297 }
298
299 #[must_use]
301 pub fn recipient(&self) -> EstablishedRecipient<B::Protocol> {
302 self.recipient.clone()
303 }
304
305 #[must_use]
308 pub fn into_recipient(self) -> EstablishedRecipient<B::Protocol> {
309 self.recipient
310 }
311
312 pub fn interpret<I>(self, interpreter: &mut I) -> I::Output
315 where
316 I: InterpretEstablished<B::Protocol>,
317 {
318 self.recipient.interpret(interpreter)
319 }
320}
321
322impl<B> Clone for EstablishedActor<B>
323where
324 B: Behavior,
325 <B::Protocol as Protocol>::Addr: EndpointAddress,
326{
327 fn clone(&self) -> Self {
328 Self {
329 recipient: self.recipient.clone(),
330 behavior: PhantomData,
331 }
332 }
333}
334
335impl<B> core::fmt::Debug for EstablishedActor<B>
336where
337 B: Behavior,
338 <B::Protocol as Protocol>::Addr: EndpointAddress,
339 <<B::Protocol as Protocol>::Addr as EndpointAddress>::Established<B::Protocol>:
340 core::fmt::Debug,
341{
342 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
343 formatter
344 .debug_tuple("EstablishedActor")
345 .field(&self.recipient)
346 .finish()
347 }
348}
349
350impl<B> PartialEq for EstablishedActor<B>
351where
352 B: Behavior,
353 <B::Protocol as Protocol>::Addr: EndpointAddress,
354 <<B::Protocol as Protocol>::Addr as EndpointAddress>::Established<B::Protocol>: PartialEq,
355{
356 fn eq(&self, other: &Self) -> bool {
357 self.recipient == other.recipient
358 }
359}
360
361impl<B> Eq for EstablishedActor<B>
362where
363 B: Behavior,
364 <B::Protocol as Protocol>::Addr: EndpointAddress,
365 <<B::Protocol as Protocol>::Addr as EndpointAddress>::Established<B::Protocol>: Eq,
366{
367}
368
369impl<P: Protocol> PartialEq for Recipient<P> {
370 fn eq(&self, other: &Self) -> bool {
371 self.address == other.address
372 }
373}
374
375impl<P: Protocol> Eq for Recipient<P> {}
376
377impl<P: Protocol> core::fmt::Debug for Recipient<P>
378where
379 P::Addr: core::fmt::Debug,
380 <P::Addr as Address>::Nonce: core::fmt::Debug,
381{
382 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
383 self.address.fmt(f)
384 }
385}
386
387#[derive(Clone, Copy, Debug, Eq, PartialEq)]
436pub enum LogicalDeliveryReason {
437 UnknownAddress,
438 ClosedRecipient,
439}
440
441#[derive(Clone, Copy, Debug, Eq, PartialEq)]
443pub enum ExactDeliveryReason {
444 ClosedRecipient,
445}
446
447pub struct Delivery<P: Protocol> {
448 pub to: Recipient<P>,
449 pub message: P::Msg,
450}
451
452impl<P: Protocol> Delivery<P> {
453 #[must_use]
454 pub fn new(to: Recipient<P>, message: P::Msg) -> Self {
455 Self { to, message }
456 }
457}
458
459impl<P> Clone for Delivery<P>
460where
461 P: Protocol,
462 P::Msg: Clone,
463{
464 fn clone(&self) -> Self {
465 Self {
466 to: self.to,
467 message: self.message.clone(),
468 }
469 }
470}
471
472impl<P> PartialEq for Delivery<P>
473where
474 P: Protocol,
475 P::Msg: PartialEq,
476{
477 fn eq(&self, other: &Self) -> bool {
478 self.to == other.to && self.message == other.message
479 }
480}
481
482impl<P> Eq for Delivery<P>
483where
484 P: Protocol,
485 P::Msg: Eq,
486{
487}
488
489impl<P> ActionItem for Delivery<P>
490where
491 P: Protocol,
492 P::Addr: Send,
493 P::Msg: Send,
494{
495 type Accepted = ();
496 type Rejection = LogicalDeliveryReason;
497 type Prerequisite = Never;
498}
499
500pub struct EstablishedDelivery<P>
530where
531 P: Protocol,
532 P::Addr: EndpointAddress,
533{
534 pub to: EstablishedRecipient<P>,
535 pub message: P::Msg,
536}
537
538impl<P> EstablishedDelivery<P>
539where
540 P: Protocol,
541 P::Addr: EndpointAddress,
542{
543 #[must_use]
544 pub const fn new(to: EstablishedRecipient<P>, message: P::Msg) -> Self {
545 Self { to, message }
546 }
547}
548
549impl<P> Clone for EstablishedDelivery<P>
550where
551 P: Protocol,
552 P::Addr: EndpointAddress,
553 P::Msg: Clone,
554{
555 fn clone(&self) -> Self {
556 Self::new(self.to.clone(), self.message.clone())
557 }
558}
559
560impl<P> core::fmt::Debug for EstablishedDelivery<P>
561where
562 P: Protocol,
563 P::Addr: EndpointAddress,
564 EstablishedRecipient<P>: core::fmt::Debug,
565 P::Msg: core::fmt::Debug,
566{
567 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
568 formatter
569 .debug_struct("EstablishedDelivery")
570 .field("to", &self.to)
571 .field("message", &self.message)
572 .finish()
573 }
574}
575
576impl<P> PartialEq for EstablishedDelivery<P>
577where
578 P: Protocol,
579 P::Addr: EndpointAddress,
580 EstablishedRecipient<P>: PartialEq,
581 P::Msg: PartialEq,
582{
583 fn eq(&self, other: &Self) -> bool {
584 self.to == other.to && self.message == other.message
585 }
586}
587
588impl<P> Eq for EstablishedDelivery<P>
589where
590 P: Protocol,
591 P::Addr: EndpointAddress,
592 EstablishedRecipient<P>: Eq,
593 P::Msg: Eq,
594{
595}
596
597impl<P> ActionItem for EstablishedDelivery<P>
598where
599 P: Protocol,
600 P::Addr: EndpointAddress,
601 <P::Addr as EndpointAddress>::Established<P>: Send,
602 P::Msg: Send,
603{
604 type Accepted = ();
605 type Rejection = ExactDeliveryReason;
606 type Prerequisite = Never;
607}
608
609#[cfg(test)]
610mod tests {
611 use super::*;
612 use crate::{Actions, Never, NoBirths, User};
613 use std::rc::Rc;
614
615 struct Inbox;
616
617 struct SignatureOnly;
618
619 #[derive(Clone, Copy, PartialEq, Eq)]
620 struct LocalAddr(u8);
621
622 impl Address for LocalAddr {
623 type Nonce = u8;
624 }
625
626 struct LocalProtocol;
627
628 impl Protocol for LocalProtocol {
629 type Addr = LocalAddr;
630 type Msg = u8;
631 }
632
633 struct LocalEndpoint<P> {
634 token: Rc<()>,
635 protocol: PhantomData<fn() -> P>,
636 }
637
638 impl<P> Clone for LocalEndpoint<P> {
639 fn clone(&self) -> Self {
640 Self {
641 token: self.token.clone(),
642 protocol: PhantomData,
643 }
644 }
645 }
646
647 impl<P> core::fmt::Debug for LocalEndpoint<P> {
648 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
649 formatter.write_str("LocalEndpoint")
650 }
651 }
652
653 impl<P> PartialEq for LocalEndpoint<P> {
654 fn eq(&self, other: &Self) -> bool {
655 Rc::ptr_eq(&self.token, &other.token)
656 }
657 }
658
659 impl<P> Eq for LocalEndpoint<P> {}
660
661 impl EndpointAddress for LocalAddr {
662 type Established<P>
663 = LocalEndpoint<P>
664 where
665 P: Protocol<Addr = Self>;
666 }
667
668 struct LocalTransfer;
669
670 impl InterpretEstablished<LocalProtocol> for LocalTransfer {
671 type Output = Rc<()>;
672
673 fn interpret_established(
674 &mut self,
675 endpoint: LocalEndpoint<LocalProtocol>,
676 ) -> Self::Output {
677 endpoint.token
678 }
679 }
680
681 struct LocalBehavior;
682
683 impl Behavior for LocalBehavior {
684 type Protocol = LocalProtocol;
685 type Event = User<LocalAddr, u8>;
686 type Sends = Vec<Never>;
687 type Ph = Never;
688 type Error = Never;
689 type Birth = NoBirths;
690
691 fn transition(
692 &mut self,
693 _: crate::ActiveTurn,
694 _: Self::Event,
695 ) -> crate::BehaviorActed<Self> {
696 Ok(Actions::cont())
697 }
698 }
699
700 impl crate::Protocol for SignatureOnly {
701 type Addr = MailAddr;
702 type Msg = u8;
703 }
704
705 impl behavior::Protocol for Inbox {
706 type Addr = MailAddr;
707 type Msg = u8;
708 }
709
710 impl Behavior for Inbox {
711 type Protocol = Self;
712 type Event = User<MailAddr, u8>;
713 type Sends = Vec<Never>;
714 type Ph = Never;
715 type Error = Never;
716 type Birth = NoBirths;
717
718 fn init(&mut self, _: crate::InitializationTurn) -> crate::BehaviorActed<Self> {
719 Ok(Actions::cont())
720 }
721
722 fn transition(
723 &mut self,
724 _: crate::ActiveTurn,
725 _: Self::Event,
726 ) -> crate::BehaviorActed<Self> {
727 Ok(Actions::cont())
728 }
729 }
730
731 #[test]
732 fn mail_address_conversion_preserves_nonzero_value() {
733 assert_eq!(u64::from(MailAddr(41)), 41);
734 }
735
736 #[test]
737 fn routing_requires_only_the_static_protocol_signature() {
738 let recipient = Recipient::<SignatureOnly>::global(MailAddr(7));
739 let delivery = Delivery::new(recipient, 11);
740
741 assert_eq!(delivery.to.address(), MailAddr(7));
742 assert_eq!(delivery.message, 11);
743 }
744
745 #[test]
746 fn recipient_value_contract_distinguishes_logical_addresses() {
747 let global = Recipient::<Inbox>::global(MailAddr(7));
748 let same_global = Recipient::<Inbox>::global(MailAddr(7));
749 let other_global = Recipient::<Inbox>::global(MailAddr(8));
750
751 assert_eq!(global, same_global);
752 assert_ne!(global, other_global);
753 assert_eq!(global.address(), MailAddr(7));
754 assert_eq!(format!("{global:?}"), "MailAddr(7)");
755 }
756
757 #[test]
758 fn established_capability_accepts_a_local_non_send_endpoint() {
759 let token = Rc::new(());
760 let recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
761 token: token.clone(),
762 protocol: PhantomData,
763 });
764 let retained = recipient.clone();
765 let extracted = retained.interpret(&mut LocalTransfer);
766
767 assert!(Rc::ptr_eq(&token, &extracted));
768 drop(recipient);
769 }
770
771 #[test]
772 fn established_values_compare_complete_identity_and_expose_debug_shape() {
773 let token = Rc::new(());
774 let other_token = Rc::new(());
775 let recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
776 token: token.clone(),
777 protocol: PhantomData,
778 });
779 let same_recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
780 token,
781 protocol: PhantomData,
782 });
783 let other_recipient = EstablishedRecipient::<LocalProtocol>::issued(LocalEndpoint {
784 token: other_token,
785 protocol: PhantomData,
786 });
787
788 assert_eq!(recipient, same_recipient);
789 assert_ne!(recipient, other_recipient);
790 assert_eq!(
791 format!("{recipient:?}"),
792 "EstablishedRecipient(LocalEndpoint)"
793 );
794
795 let actor = EstablishedActor::<LocalBehavior>::from_recipient(recipient.clone());
796 let same_actor = EstablishedActor::<LocalBehavior>::from_recipient(same_recipient.clone());
797 let other_actor =
798 EstablishedActor::<LocalBehavior>::from_recipient(other_recipient.clone());
799 assert_eq!(actor, same_actor);
800 assert_ne!(actor, other_actor);
801 assert_eq!(
802 format!("{actor:?}"),
803 "EstablishedActor(EstablishedRecipient(LocalEndpoint))"
804 );
805
806 let delivery = EstablishedDelivery::new(recipient, 7);
807 let same_delivery = EstablishedDelivery::new(same_recipient.clone(), 7);
808 let other_destination = EstablishedDelivery::new(other_recipient.clone(), 7);
809 let other_message = EstablishedDelivery::new(same_recipient, 9);
810 let both_different = EstablishedDelivery::new(other_recipient, 9);
811 assert_eq!(delivery, same_delivery);
812 assert_ne!(delivery, other_destination);
813 assert_ne!(delivery, other_message);
814 assert_ne!(delivery, both_different);
815 assert_eq!(
816 format!("{delivery:?}"),
817 "EstablishedDelivery { to: EstablishedRecipient(LocalEndpoint), message: 7 }"
818 );
819 }
820
821 #[test]
822 fn delivery_equality_requires_both_destination_and_message() {
823 let value = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 5);
824 let same = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 5);
825 let other_destination = Delivery::<Inbox>::new(Recipient::global(MailAddr(2)), 5);
826 let other_message = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 6);
827 let both_different = Delivery::<Inbox>::new(Recipient::global(MailAddr(2)), 6);
828
829 assert!(value == same);
830 assert!(value != other_destination);
831 assert!(value != other_message);
832 assert!(value != both_different);
833 }
834}