1use std::cmp::Ordering;
12use std::fmt;
13use std::hash::Hash;
14use std::hash::Hasher;
15use std::marker::PhantomData;
16
17use derivative::Derivative;
18use hyperactor_config::Flattrs;
19use serde::Deserialize;
20use serde::Deserializer;
21use serde::Serialize;
22use serde::Serializer;
23use typeuri::Named;
24
25use crate::Actor;
26use crate::ActorAddr;
27use crate::ActorHandle;
28use crate::Endpoint;
29use crate::EndpointLocation;
30use crate::PortAddr;
31use crate::RemoteEndpoint;
32use crate::RemoteHandles;
33use crate::RemoteMessage;
34use crate::accum::IdleFlushReducerOpts;
35use crate::accum::ReducerSpec;
36use crate::accum::StreamingReducerOpts;
37use crate::actor::Binds;
38use crate::actor::Referable;
39use crate::context;
40use crate::context::MailboxExt;
41use crate::mailbox::DeliveryFailureReport;
42use crate::mailbox::MailboxSenderError;
43use crate::mailbox::MailboxSenderErrorKind;
44use crate::mailbox::PortSink;
45use crate::port::Port;
46
47#[derive(typeuri::Named)]
49pub struct ActorRef<A: Referable> {
50 pub(crate) actor_addr: ActorAddr,
51 phantom: PhantomData<fn() -> A>,
53}
54
55impl<A: Referable> ActorRef<A> {
56 pub fn port<M: RemoteMessage>(&self) -> PortRef<M>
58 where
59 A: RemoteHandles<M>,
60 {
61 PortRef::attest(self.actor_addr.port_addr(Port::handler::<M>()))
62 }
63
64 pub fn attest(actor_addr: ActorAddr) -> Self {
69 Self {
70 actor_addr,
71 phantom: PhantomData,
72 }
73 }
74
75 pub fn actor_addr(&self) -> &ActorAddr {
77 &self.actor_addr
78 }
79
80 pub fn into_actor_addr(self) -> ActorAddr {
82 self.actor_addr
83 }
84
85 pub fn downcast_handle(&self, cx: &impl context::Actor) -> Option<ActorHandle<A>>
89 where
90 A: Actor,
91 {
92 cx.instance().proc().resolve_actor_ref(self)
93 }
94}
95
96impl<A, B> From<&ActorRef<A>> for ActorRef<B>
97where
98 A: Actor + Referable,
99 B: Binds<A>,
100{
101 fn from(value: &ActorRef<A>) -> Self {
102 ActorRef::attest(value.actor_addr().clone())
103 }
104}
105
106impl<A, M> Endpoint<M> for &ActorRef<A>
107where
108 A: Referable + RemoteHandles<M>,
109 M: RemoteMessage,
110{
111 fn endpoint_location(&self) -> EndpointLocation {
112 EndpointLocation::Actor(self.actor_addr.clone())
113 }
114
115 fn post<C>(self, cx: &C, message: M)
116 where
117 C: context::Actor,
118 {
119 RemoteEndpoint::post_with_headers(self, cx, Flattrs::new(), message)
120 }
121}
122
123impl<A, M> RemoteEndpoint<M> for &ActorRef<A>
124where
125 A: Referable + RemoteHandles<M>,
126 M: RemoteMessage,
127{
128 fn post_with_headers<C>(self, cx: &C, headers: Flattrs, message: M)
129 where
130 C: context::Actor,
131 {
132 RemoteEndpoint::post_with_headers(&self.port(), cx, headers, message)
133 }
134}
135
136impl<A: Referable> Serialize for ActorRef<A> {
138 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
139 where
140 S: Serializer,
141 {
142 self.actor_addr.serialize(serializer)
144 }
145}
146
147impl<'de, A: Referable> Deserialize<'de> for ActorRef<A> {
149 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
150 where
151 D: Deserializer<'de>,
152 {
153 let actor_addr = <ActorAddr>::deserialize(deserializer)?;
154 Ok(ActorRef {
155 actor_addr,
156 phantom: PhantomData,
157 })
158 }
159}
160
161impl<A: Referable> fmt::Debug for ActorRef<A> {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 f.debug_struct("ActorRef")
165 .field("actor_addr", &self.actor_addr)
166 .field("type", &std::any::type_name::<A>())
167 .finish()
168 }
169}
170
171impl<A: Referable> fmt::Display for ActorRef<A> {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 fmt::Display::fmt(&self.actor_addr, f)?;
174 write!(f, "<{}>", std::any::type_name::<A>())
175 }
176}
177
178impl<A: Referable> Clone for ActorRef<A> {
180 fn clone(&self) -> Self {
181 Self {
182 actor_addr: self.actor_addr.clone(),
183 phantom: PhantomData,
184 }
185 }
186}
187
188impl<A: Referable> PartialEq for ActorRef<A> {
189 fn eq(&self, other: &Self) -> bool {
190 self.actor_addr == other.actor_addr
191 }
192}
193
194impl<A: Referable> Eq for ActorRef<A> {}
195
196impl<A: Referable> PartialOrd for ActorRef<A> {
197 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
198 Some(self.cmp(other))
199 }
200}
201
202impl<A: Referable> Ord for ActorRef<A> {
203 fn cmp(&self, other: &Self) -> Ordering {
204 self.actor_addr.cmp(&other.actor_addr)
205 }
206}
207
208impl<A: Referable> Hash for ActorRef<A> {
209 fn hash<H: Hasher>(&self, state: &mut H) {
210 self.actor_addr.hash(state);
211 }
212}
213
214#[derive(Debug, Derivative, typeuri::Named)]
217#[derivative(PartialEq, Eq, PartialOrd, Hash, Ord)]
218pub struct PortRef<M> {
219 port_addr: PortAddr,
220 #[derivative(
221 PartialEq = "ignore",
222 PartialOrd = "ignore",
223 Ord = "ignore",
224 Hash = "ignore"
225 )]
226 reducer_spec: Option<ReducerSpec>,
227 #[derivative(
228 PartialEq = "ignore",
229 PartialOrd = "ignore",
230 Ord = "ignore",
231 Hash = "ignore"
232 )]
233 streaming_opts: StreamingReducerOpts,
234 phantom: PhantomData<M>,
235 return_undeliverable: bool,
236 #[derivative(
237 PartialEq = "ignore",
238 PartialOrd = "ignore",
239 Ord = "ignore",
240 Hash = "ignore"
241 )]
242 unsplit: bool,
243}
244
245#[doc(hidden)]
246#[derive(Debug, Clone, Serialize, Deserialize, typeuri::Named)]
247pub struct PortRefRepr {
248 port_addr: PortAddr,
249 reducer_spec: Option<ReducerSpec>,
250 streaming_opts: StreamingReducerOpts,
251 return_undeliverable: bool,
252 unsplit: bool,
253}
254
255impl PortRefRepr {
256 pub fn port_addr(&self) -> &PortAddr {
258 &self.port_addr
259 }
260
261 pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
263 &self.reducer_spec
264 }
265
266 pub fn streaming_opts(&self) -> &StreamingReducerOpts {
268 &self.streaming_opts
269 }
270
271 pub fn get_return_undeliverable(&self) -> bool {
273 self.return_undeliverable
274 }
275
276 pub fn unsplit(&self) -> bool {
278 self.unsplit
279 }
280
281 pub fn update_port_addr(&mut self, port_addr: PortAddr) {
283 self.port_addr = port_addr;
284 }
285}
286
287impl<M> TryFrom<&PortRef<M>> for PortRefRepr {
288 type Error = serde_multipart::Error;
289
290 fn try_from(port_ref: &PortRef<M>) -> serde_multipart::Result<Self> {
291 Ok(Self {
292 port_addr: port_ref.port_addr.clone(),
293 reducer_spec: port_ref.reducer_spec.clone(),
294 streaming_opts: port_ref.streaming_opts.clone(),
295 return_undeliverable: port_ref.return_undeliverable,
296 unsplit: port_ref.unsplit,
297 })
298 }
299}
300
301impl<M> TryFrom<PortRefRepr> for PortRef<M> {
302 type Error = serde_multipart::Error;
303
304 fn try_from(repr: PortRefRepr) -> serde_multipart::Result<Self> {
305 Ok(Self {
306 port_addr: repr.port_addr,
307 reducer_spec: repr.reducer_spec,
308 streaming_opts: repr.streaming_opts,
309 phantom: PhantomData,
310 return_undeliverable: repr.return_undeliverable,
311 unsplit: repr.unsplit,
312 })
313 }
314}
315
316serde_multipart::part_codec! {
317 impl<M> PortRef<M>
318 {
319 type Repr = PortRefRepr;
320 }
321}
322
323impl<M: RemoteMessage> PortRef<M> {
324 pub fn attest(port_addr: PortAddr) -> Self {
327 Self {
328 port_addr,
329 reducer_spec: None,
330 streaming_opts: StreamingReducerOpts::default(),
331 phantom: PhantomData,
332 return_undeliverable: true,
333 unsplit: false,
334 }
335 }
336
337 pub fn attest_reducible(
340 port_addr: PortAddr,
341 reducer_spec: Option<ReducerSpec>,
342 streaming_opts: StreamingReducerOpts,
343 ) -> Self {
344 Self {
345 port_addr,
346 reducer_spec,
347 streaming_opts,
348 phantom: PhantomData,
349 return_undeliverable: true,
350 unsplit: false,
351 }
352 }
353
354 pub fn unsplit(mut self) -> Self {
356 self.unsplit = true;
357 self
358 }
359
360 pub fn attest_handler_port(actor: &ActorAddr) -> Self {
363 PortRef::<M>::attest(actor.port_addr(Port::handler::<M>()))
364 }
365
366 pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
369 &self.reducer_spec
370 }
371
372 pub fn port_addr(&self) -> &PortAddr {
374 &self.port_addr
375 }
376
377 pub fn into_port_addr(self) -> PortAddr {
379 self.port_addr
380 }
381
382 pub fn into_idle_flush(self, reducer_opts: IdleFlushReducerOpts) -> IdleFlushPortRef<M> {
387 IdleFlushPortRef {
388 port_addr: self.port_addr,
389 reducer_spec: self.reducer_spec,
390 streaming_opts: self.streaming_opts,
391 reducer_opts,
392 return_undeliverable: self.return_undeliverable,
393 unsplit: self.unsplit,
394 phantom: PhantomData,
395 }
396 }
397
398 pub fn into_once(self) -> OncePortRef<M> {
401 let return_undeliverable = self.return_undeliverable;
402 let unsplit = self.unsplit;
403 let mut once = OncePortRef::attest(self.into_port_addr());
404 once.return_undeliverable = return_undeliverable;
405 once.unsplit = unsplit;
406 once
407 }
408
409 pub fn post_serialized(
412 &self,
413 cx: &impl context::Actor,
414 mut headers: Flattrs,
415 message: wirevalue::Any,
416 ) {
417 crate::mailbox::headers::set_send_timestamp(&mut headers);
418 crate::mailbox::headers::set_rust_message_type::<M>(&mut headers);
419 cx.post(
420 self.port_addr.clone(),
421 headers,
422 message,
423 self.return_undeliverable,
424 context::SeqInfoPolicy::AssignNew,
425 );
426 }
427
428 pub fn into_sink<C: context::Actor>(self, cx: C) -> PortSink<C, M> {
430 PortSink::new(cx, self)
431 }
432
433 pub fn get_return_undeliverable(&self) -> bool {
436 self.return_undeliverable
437 }
438
439 pub fn return_undeliverable(&mut self, return_undeliverable: bool) {
442 self.return_undeliverable = return_undeliverable;
443 }
444}
445
446impl<M> Endpoint<M> for &PortRef<M>
447where
448 M: RemoteMessage,
449{
450 fn endpoint_location(&self) -> EndpointLocation {
451 EndpointLocation::Port(self.port_addr.clone())
452 }
453
454 fn post<C>(self, cx: &C, message: M)
455 where
456 C: context::Actor,
457 {
458 RemoteEndpoint::post_with_headers(self, cx, Flattrs::new(), message)
459 }
460}
461
462impl<M> RemoteEndpoint<M> for &PortRef<M>
463where
464 M: RemoteMessage,
465{
466 fn post_with_headers<C>(self, cx: &C, headers: Flattrs, message: M)
467 where
468 C: context::Actor,
469 {
470 let serialized = match wirevalue::Any::serialize(&message).map_err(|err| {
471 MailboxSenderError::new_bound(
472 self.port_addr.clone(),
473 MailboxSenderErrorKind::Serialize(err.into()),
474 )
475 }) {
476 Ok(serialized) => serialized,
477 Err(err) => {
478 cx.instance()
479 .report_delivery_failure(DeliveryFailureReport::from_send_error::<M>(
480 cx.mailbox().actor_addr().clone(),
481 self.endpoint_location(),
482 &err,
483 ));
484 return;
485 }
486 };
487 self.post_serialized(cx, headers, serialized);
488 }
489}
490
491impl<M: RemoteMessage> Clone for PortRef<M> {
492 fn clone(&self) -> Self {
493 Self {
494 port_addr: self.port_addr.clone(),
495 reducer_spec: self.reducer_spec.clone(),
496 streaming_opts: self.streaming_opts.clone(),
497 phantom: PhantomData,
498 return_undeliverable: self.return_undeliverable,
499 unsplit: self.unsplit,
500 }
501 }
502}
503
504impl<M: RemoteMessage> fmt::Display for PortRef<M> {
505 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
506 fmt::Display::fmt(&self.port_addr, f)
507 }
508}
509
510#[derive(Debug, PartialEq, typeuri::Named)]
512pub struct IdleFlushPortRef<M> {
513 port_addr: PortAddr,
514 reducer_spec: Option<ReducerSpec>,
515 streaming_opts: StreamingReducerOpts,
516 reducer_opts: IdleFlushReducerOpts,
517 return_undeliverable: bool,
518 unsplit: bool,
519 phantom: PhantomData<M>,
520}
521
522#[doc(hidden)]
523#[derive(Debug, Clone, Serialize, Deserialize, typeuri::Named)]
524pub struct IdleFlushPortRefRepr {
525 port_addr: PortAddr,
526 reducer_spec: Option<ReducerSpec>,
527 streaming_opts: StreamingReducerOpts,
528 reducer_opts: IdleFlushReducerOpts,
529 return_undeliverable: bool,
530 unsplit: bool,
531}
532
533impl IdleFlushPortRefRepr {
534 pub fn port_addr(&self) -> &PortAddr {
536 &self.port_addr
537 }
538
539 pub fn reducer_spec(&self) -> Option<&ReducerSpec> {
541 self.reducer_spec.as_ref()
542 }
543
544 pub fn reducer_opts(&self) -> &IdleFlushReducerOpts {
546 &self.reducer_opts
547 }
548
549 pub fn get_return_undeliverable(&self) -> bool {
551 self.return_undeliverable
552 }
553
554 pub fn unsplit(&self) -> bool {
556 self.unsplit
557 }
558
559 pub fn update_port_addr(&mut self, port_addr: PortAddr) {
561 self.port_addr = port_addr;
562 }
563}
564
565impl<M> TryFrom<&IdleFlushPortRef<M>> for IdleFlushPortRefRepr {
566 type Error = serde_multipart::Error;
567
568 fn try_from(port_ref: &IdleFlushPortRef<M>) -> serde_multipart::Result<Self> {
569 Ok(Self {
570 port_addr: port_ref.port_addr.clone(),
571 reducer_spec: port_ref.reducer_spec.clone(),
572 streaming_opts: port_ref.streaming_opts.clone(),
573 reducer_opts: port_ref.reducer_opts.clone(),
574 return_undeliverable: port_ref.return_undeliverable,
575 unsplit: port_ref.unsplit,
576 })
577 }
578}
579
580impl<M> TryFrom<IdleFlushPortRefRepr> for IdleFlushPortRef<M> {
581 type Error = serde_multipart::Error;
582
583 fn try_from(repr: IdleFlushPortRefRepr) -> serde_multipart::Result<Self> {
584 Ok(Self {
585 port_addr: repr.port_addr,
586 reducer_spec: repr.reducer_spec,
587 streaming_opts: repr.streaming_opts,
588 reducer_opts: repr.reducer_opts,
589 return_undeliverable: repr.return_undeliverable,
590 unsplit: repr.unsplit,
591 phantom: PhantomData,
592 })
593 }
594}
595
596serde_multipart::part_codec! {
597 impl<M> IdleFlushPortRef<M>
598 {
599 type Repr = IdleFlushPortRefRepr;
600 }
601}
602
603impl<M: RemoteMessage> IdleFlushPortRef<M> {
604 pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
606 &self.reducer_spec
607 }
608
609 pub fn port_addr(&self) -> &PortAddr {
611 &self.port_addr
612 }
613
614 pub fn into_port_addr(self) -> PortAddr {
616 self.port_addr
617 }
618
619 pub fn post_serialized(
622 &self,
623 cx: &impl context::Actor,
624 mut headers: Flattrs,
625 message: wirevalue::Any,
626 ) {
627 crate::mailbox::headers::set_send_timestamp(&mut headers);
628 crate::mailbox::headers::set_rust_message_type::<M>(&mut headers);
629 cx.post(
630 self.port_addr.clone(),
631 headers,
632 message,
633 self.return_undeliverable,
634 context::SeqInfoPolicy::AssignNew,
635 );
636 }
637
638 pub fn get_return_undeliverable(&self) -> bool {
641 self.return_undeliverable
642 }
643
644 pub fn return_undeliverable(&mut self, return_undeliverable: bool) {
647 self.return_undeliverable = return_undeliverable;
648 }
649}
650
651impl<M> Endpoint<M> for &IdleFlushPortRef<M>
652where
653 M: RemoteMessage,
654{
655 fn endpoint_location(&self) -> EndpointLocation {
656 EndpointLocation::Port(self.port_addr.clone())
657 }
658
659 fn post<C>(self, cx: &C, message: M)
660 where
661 C: context::Actor,
662 {
663 RemoteEndpoint::post_with_headers(self, cx, Flattrs::new(), message)
664 }
665}
666
667impl<M> RemoteEndpoint<M> for &IdleFlushPortRef<M>
668where
669 M: RemoteMessage,
670{
671 fn post_with_headers<C>(self, cx: &C, headers: Flattrs, message: M)
672 where
673 C: context::Actor,
674 {
675 let serialized = match wirevalue::Any::serialize(&message).map_err(|err| {
676 MailboxSenderError::new_bound(
677 self.port_addr.clone(),
678 MailboxSenderErrorKind::Serialize(err.into()),
679 )
680 }) {
681 Ok(serialized) => serialized,
682 Err(err) => {
683 cx.instance()
684 .report_delivery_failure(DeliveryFailureReport::from_send_error::<M>(
685 cx.mailbox().actor_addr().clone(),
686 self.endpoint_location(),
687 &err,
688 ));
689 return;
690 }
691 };
692 self.post_serialized(cx, headers, serialized);
693 }
694}
695
696impl<M: RemoteMessage> Clone for IdleFlushPortRef<M> {
697 fn clone(&self) -> Self {
698 Self {
699 port_addr: self.port_addr.clone(),
700 reducer_spec: self.reducer_spec.clone(),
701 streaming_opts: self.streaming_opts.clone(),
702 reducer_opts: self.reducer_opts.clone(),
703 return_undeliverable: self.return_undeliverable,
704 unsplit: self.unsplit,
705 phantom: PhantomData,
706 }
707 }
708}
709
710#[derive(Debug, PartialEq)]
714pub struct OncePortRef<M> {
715 port_addr: PortAddr,
716 reducer_spec: Option<ReducerSpec>,
717 return_undeliverable: bool,
718 unsplit: bool,
719 phantom: PhantomData<M>,
720}
721
722#[doc(hidden)]
723#[derive(Debug, Clone, Serialize, Deserialize, typeuri::Named)]
724pub struct OncePortRefRepr {
725 port_addr: PortAddr,
726 reducer_spec: Option<ReducerSpec>,
727 return_undeliverable: bool,
728 unsplit: bool,
729}
730
731impl OncePortRefRepr {
732 pub fn port_addr(&self) -> &PortAddr {
734 &self.port_addr
735 }
736
737 pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
739 &self.reducer_spec
740 }
741
742 pub fn get_return_undeliverable(&self) -> bool {
744 self.return_undeliverable
745 }
746
747 pub fn unsplit(&self) -> bool {
749 self.unsplit
750 }
751
752 pub fn update_port_addr(&mut self, port_addr: PortAddr) {
754 self.port_addr = port_addr;
755 }
756}
757
758impl<M> TryFrom<&OncePortRef<M>> for OncePortRefRepr {
759 type Error = serde_multipart::Error;
760
761 fn try_from(port_ref: &OncePortRef<M>) -> serde_multipart::Result<Self> {
762 Ok(Self {
763 port_addr: port_ref.port_addr.clone(),
764 reducer_spec: port_ref.reducer_spec.clone(),
765 return_undeliverable: port_ref.return_undeliverable,
766 unsplit: port_ref.unsplit,
767 })
768 }
769}
770
771impl<M> TryFrom<OncePortRefRepr> for OncePortRef<M> {
772 type Error = serde_multipart::Error;
773
774 fn try_from(repr: OncePortRefRepr) -> serde_multipart::Result<Self> {
775 Ok(Self {
776 port_addr: repr.port_addr,
777 reducer_spec: repr.reducer_spec,
778 return_undeliverable: repr.return_undeliverable,
779 unsplit: repr.unsplit,
780 phantom: PhantomData,
781 })
782 }
783}
784
785serde_multipart::part_codec! {
786 impl<M> OncePortRef<M>
787 {
788 type Repr = OncePortRefRepr;
789 }
790}
791
792impl<M: RemoteMessage> OncePortRef<M> {
793 pub(crate) fn attest(port_addr: PortAddr) -> Self {
794 Self {
795 port_addr,
796 reducer_spec: None,
797 return_undeliverable: true,
798 unsplit: false,
799 phantom: PhantomData,
800 }
801 }
802
803 pub fn attest_reducible(port_addr: PortAddr, reducer_spec: Option<ReducerSpec>) -> Self {
806 Self {
807 port_addr,
808 reducer_spec,
809 return_undeliverable: true,
810 unsplit: false,
811 phantom: PhantomData,
812 }
813 }
814
815 pub fn unsplit(mut self) -> Self {
817 self.unsplit = true;
818 self
819 }
820
821 pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
823 &self.reducer_spec
824 }
825
826 pub fn port_addr(&self) -> &PortAddr {
828 &self.port_addr
829 }
830
831 pub fn into_port_addr(self) -> PortAddr {
833 self.port_addr
834 }
835
836 pub fn get_return_undeliverable(&self) -> bool {
839 self.return_undeliverable
840 }
841
842 pub fn return_undeliverable(&mut self, return_undeliverable: bool) {
845 self.return_undeliverable = return_undeliverable;
846 }
847}
848
849impl<M> Endpoint<M> for OncePortRef<M>
850where
851 M: RemoteMessage,
852{
853 fn endpoint_location(&self) -> EndpointLocation {
854 EndpointLocation::Port(self.port_addr.clone())
855 }
856
857 fn post<C>(self, cx: &C, message: M)
858 where
859 C: context::Actor,
860 {
861 RemoteEndpoint::post_with_headers(self, cx, Flattrs::new(), message)
862 }
863}
864
865impl<M> RemoteEndpoint<M> for OncePortRef<M>
866where
867 M: RemoteMessage,
868{
869 fn post_with_headers<C>(self, cx: &C, mut headers: Flattrs, message: M)
870 where
871 C: context::Actor,
872 {
873 crate::mailbox::headers::set_send_timestamp(&mut headers);
874 let serialized = match wirevalue::Any::serialize(&message).map_err(|err| {
875 MailboxSenderError::new_bound(
876 self.port_addr.clone(),
877 MailboxSenderErrorKind::Serialize(err.into()),
878 )
879 }) {
880 Ok(serialized) => serialized,
881 Err(err) => {
882 cx.instance()
883 .report_delivery_failure(DeliveryFailureReport::from_send_error::<M>(
884 cx.mailbox().actor_addr().clone(),
885 self.endpoint_location(),
886 &err,
887 ));
888 return;
889 }
890 };
891 cx.post(
892 self.port_addr.clone(),
893 headers,
894 serialized,
895 self.return_undeliverable,
896 context::SeqInfoPolicy::AssignNew,
897 );
898 }
899}
900
901impl<M: RemoteMessage> Clone for OncePortRef<M> {
902 fn clone(&self) -> Self {
903 Self {
904 port_addr: self.port_addr.clone(),
905 reducer_spec: self.reducer_spec.clone(),
906 return_undeliverable: self.return_undeliverable,
907 unsplit: self.unsplit,
908 phantom: PhantomData,
909 }
910 }
911}
912
913impl<M: RemoteMessage> fmt::Display for OncePortRef<M> {
914 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
915 fmt::Display::fmt(&self.port_addr, f)
916 }
917}
918
919impl<M: RemoteMessage> Named for OncePortRef<M> {
920 fn typename() -> &'static str {
921 wirevalue::intern_typename!(Self, "hyperactor::mailbox::OncePortRef<{}>", M)
922 }
923}
924
925#[cfg(test)]
926mod tests {
927 use std::time::Duration;
928
929 use hyperactor_config::NonZeroUsize;
930 use serde::Deserialize;
931 use serde::Serialize;
932 use serde_multipart::PartCodec;
933 use typeuri::Named;
934
935 use super::*;
936 use crate::channel::ChannelAddr;
937 use crate::id::ActorId;
938 use crate::id::Label;
939 use crate::id::PortId;
940 use crate::id::ProcId;
941
942 fn test_port_ref() -> PortRef<String> {
943 let proc_id = ProcId::singleton(Label::new("proc").unwrap());
944 let actor_id = ActorId::singleton(Label::new("actor").unwrap(), proc_id);
945 let port_id = PortId::new(actor_id, Port::from(7));
946 let port_addr = PortAddr::new(port_id, ChannelAddr::Local(42).into());
947 let mut port_ref = PortRef::<String>::attest(port_addr).unsplit();
948 port_ref.return_undeliverable(false);
949 port_ref
950 }
951
952 fn test_once_port_ref() -> OncePortRef<String> {
953 let proc_id = ProcId::singleton(Label::new("proc").unwrap());
954 let actor_id = ActorId::singleton(Label::new("actor").unwrap(), proc_id);
955 let port_id = PortId::new(actor_id, Port::from(8));
956 let port_addr = PortAddr::new(port_id, ChannelAddr::Local(43).into());
957 let mut once_port_ref = OncePortRef::<String>::attest(port_addr).unsplit();
958 once_port_ref.return_undeliverable(false);
959 once_port_ref
960 }
961
962 fn test_idle_flush_port_ref() -> IdleFlushPortRef<String> {
963 let proc_id = ProcId::singleton(Label::new("proc").unwrap());
964 let actor_id = ActorId::singleton(Label::new("actor").unwrap(), proc_id);
965 let port_id = PortId::new(actor_id, Port::from(9));
966 let port_addr = PortAddr::new(port_id, ChannelAddr::Local(44).into());
967 let mut port_ref = PortRef::<String>::attest_reducible(
968 port_addr,
969 Some(ReducerSpec {
970 typehash: 123,
971 builder_params: None,
972 }),
973 StreamingReducerOpts {
974 max_update_interval: Some(Duration::from_millis(250)),
975 initial_update_interval: Some(Duration::from_millis(5)),
976 },
977 )
978 .unsplit()
979 .into_idle_flush(IdleFlushReducerOpts {
980 idle_timeout: Duration::from_millis(50),
981 abandon_timeout: Duration::from_secs(30),
982 expected_updates_per_destination: NonZeroUsize::new(2).expect("2 is non-zero"),
983 });
984 port_ref.return_undeliverable(false);
985 port_ref
986 }
987
988 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
989 struct PortRefEnvelope {
990 port: PortRef<String>,
991 seq: u64,
992 }
993
994 #[derive(Debug, PartialEq, Serialize, Deserialize)]
995 struct IdleFlushPortRefEnvelope {
996 port: IdleFlushPortRef<String>,
997 seq: u64,
998 }
999
1000 #[derive(Debug, PartialEq, Serialize, Deserialize)]
1001 struct OncePortRefEnvelope {
1002 port: OncePortRef<String>,
1003 seq: u64,
1004 }
1005
1006 fn assert_same_port_ref(actual: &PortRef<String>, expected: &PortRef<String>) {
1007 let actual = actual.to_repr().unwrap();
1008 let expected = expected.to_repr().unwrap();
1009 assert_eq!(actual.port_addr, expected.port_addr);
1010 assert_eq!(actual.reducer_spec, expected.reducer_spec);
1011 assert_eq!(actual.streaming_opts, expected.streaming_opts);
1012 assert_eq!(actual.return_undeliverable, expected.return_undeliverable);
1013 assert_eq!(actual.unsplit, expected.unsplit);
1014 }
1015
1016 fn assert_same_once_port_ref(actual: &OncePortRef<String>, expected: &OncePortRef<String>) {
1017 let actual = actual.to_repr().unwrap();
1018 let expected = expected.to_repr().unwrap();
1019 assert_eq!(actual.port_addr, expected.port_addr);
1020 assert_eq!(actual.reducer_spec, expected.reducer_spec);
1021 assert_eq!(actual.return_undeliverable, expected.return_undeliverable);
1022 assert_eq!(actual.unsplit, expected.unsplit);
1023 }
1024
1025 fn assert_same_idle_flush_port_ref(
1026 actual: &IdleFlushPortRef<String>,
1027 expected: &IdleFlushPortRef<String>,
1028 ) {
1029 let actual = actual.to_repr().unwrap();
1030 let expected = expected.to_repr().unwrap();
1031 assert_eq!(actual.port_addr, expected.port_addr);
1032 assert_eq!(actual.reducer_spec, expected.reducer_spec);
1033 assert_eq!(actual.streaming_opts, expected.streaming_opts);
1034 assert_eq!(actual.reducer_opts, expected.reducer_opts);
1035 assert_eq!(actual.return_undeliverable, expected.return_undeliverable);
1036 assert_eq!(actual.unsplit, expected.unsplit);
1037 }
1038
1039 #[test]
1040 fn test_port_ref_serde_multipart_part_codec() {
1041 let value = PortRefEnvelope {
1042 port: test_port_ref(),
1043 seq: 123,
1044 };
1045
1046 let message = serde_multipart::serialize_bincode(&value).unwrap();
1047 assert_eq!(message.num_parts(), 1);
1048 assert_eq!(message.parts()[0].typehash(), Some(PortRefRepr::typehash()));
1049
1050 let repr = message.parts()[0].deserialized::<PortRefRepr>().unwrap();
1051 assert_eq!(repr.port_addr, value.port.port_addr().clone());
1052 assert!(!repr.return_undeliverable);
1053 assert!(repr.unsplit);
1054
1055 let deserialized: PortRefEnvelope = serde_multipart::deserialize_bincode(message).unwrap();
1056 assert_eq!(deserialized.seq, value.seq);
1057 assert_same_port_ref(&deserialized.port, &value.port);
1058 }
1059
1060 #[test]
1061 fn test_idle_flush_port_ref_serde_multipart_part_codec() {
1062 let value = IdleFlushPortRefEnvelope {
1063 port: test_idle_flush_port_ref(),
1064 seq: 789,
1065 };
1066
1067 let message = serde_multipart::serialize_bincode(&value).unwrap();
1068 assert_eq!(message.num_parts(), 1);
1069 assert_eq!(
1070 message.parts()[0].typehash(),
1071 Some(IdleFlushPortRefRepr::typehash())
1072 );
1073
1074 let repr = message.parts()[0]
1075 .deserialized::<IdleFlushPortRefRepr>()
1076 .unwrap();
1077 let expected = value.port.to_repr().unwrap();
1078 assert_eq!(repr.port_addr, expected.port_addr);
1079 assert_eq!(repr.reducer_spec, expected.reducer_spec);
1080 assert_eq!(repr.streaming_opts, expected.streaming_opts);
1081 assert_eq!(repr.reducer_opts, expected.reducer_opts);
1082 assert_eq!(repr.return_undeliverable, expected.return_undeliverable);
1083 assert_eq!(repr.unsplit, expected.unsplit);
1084
1085 let deserialized: IdleFlushPortRefEnvelope =
1086 serde_multipart::deserialize_bincode(message).unwrap();
1087 assert_eq!(deserialized.seq, value.seq);
1088 assert_same_idle_flush_port_ref(&deserialized.port, &value.port);
1089 }
1090
1091 #[test]
1092 fn test_once_port_ref_serde_multipart_part_codec() {
1093 let value = OncePortRefEnvelope {
1094 port: test_once_port_ref(),
1095 seq: 789,
1096 };
1097
1098 let message = serde_multipart::serialize_bincode(&value).unwrap();
1099 assert_eq!(message.num_parts(), 1);
1100 assert_eq!(
1101 message.parts()[0].typehash(),
1102 Some(OncePortRefRepr::typehash())
1103 );
1104
1105 let repr = message.parts()[0]
1106 .deserialized::<OncePortRefRepr>()
1107 .unwrap();
1108 assert_eq!(repr.port_addr, value.port.port_addr().clone());
1109 assert!(!repr.return_undeliverable);
1110 assert!(repr.unsplit);
1111
1112 let deserialized: OncePortRefEnvelope =
1113 serde_multipart::deserialize_bincode(message).unwrap();
1114 assert_eq!(deserialized.seq, value.seq);
1115 assert_same_once_port_ref(&deserialized.port, &value.port);
1116 }
1117
1118 #[test]
1119 fn test_port_ref_regular_serde_uses_repr() {
1120 let value = PortRefEnvelope {
1121 port: test_port_ref(),
1122 seq: 456,
1123 };
1124
1125 let encoded = bincode::serde::encode_to_vec(&value, bincode::config::standard()).unwrap();
1126 let (deserialized, len): (PortRefEnvelope, usize) =
1127 bincode::serde::decode_from_slice(&encoded, bincode::config::standard()).unwrap();
1128
1129 assert_eq!(len, encoded.len());
1130 assert_eq!(deserialized.seq, value.seq);
1131 assert_same_port_ref(&deserialized.port, &value.port);
1132 }
1133
1134 #[test]
1135 fn test_once_port_ref_regular_serde_uses_repr() {
1136 let value = OncePortRefEnvelope {
1137 port: test_once_port_ref(),
1138 seq: 1011,
1139 };
1140
1141 let encoded = bincode::serde::encode_to_vec(&value, bincode::config::standard()).unwrap();
1142 let (deserialized, len): (OncePortRefEnvelope, usize) =
1143 bincode::serde::decode_from_slice(&encoded, bincode::config::standard()).unwrap();
1144
1145 assert_eq!(len, encoded.len());
1146 assert_eq!(deserialized.seq, value.seq);
1147 assert_same_once_port_ref(&deserialized.port, &value.port);
1148 }
1149}