Skip to main content

hyperactor/
ref_.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9//! Typed capability references for Hyperactor actors and ports.
10
11use 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::ReducerSpec;
35use crate::accum::StreamingReducerOpts;
36use crate::actor::Binds;
37use crate::actor::Referable;
38use crate::context;
39use crate::context::MailboxExt;
40use crate::mailbox::DeliveryFailureReport;
41use crate::mailbox::MailboxSenderError;
42use crate::mailbox::MailboxSenderErrorKind;
43use crate::mailbox::PortSink;
44use crate::port::Port;
45
46/// ActorRefs are typed references to actors.
47#[derive(typeuri::Named)]
48pub struct ActorRef<A: Referable> {
49    pub(crate) actor_addr: ActorAddr,
50    // fn() -> A so that the struct remains Send
51    phantom: PhantomData<fn() -> A>,
52}
53
54impl<A: Referable> ActorRef<A> {
55    /// Get the remote port for message type [`M`] for the referenced actor.
56    pub fn port<M: RemoteMessage>(&self) -> PortRef<M>
57    where
58        A: RemoteHandles<M>,
59    {
60        PortRef::attest(self.actor_addr.port_addr(Port::handler::<M>()))
61    }
62
63    /// The caller guarantees that the provided actor ID is also a valid,
64    /// typed reference.  This is usually invoked to provide a guarantee
65    /// that an externally-provided actor ID (e.g., through a command
66    /// line argument) is a valid reference.
67    pub fn attest(actor_addr: ActorAddr) -> Self {
68        Self {
69            actor_addr,
70            phantom: PhantomData,
71        }
72    }
73
74    /// The actor address corresponding with this reference.
75    pub fn actor_addr(&self) -> &ActorAddr {
76        &self.actor_addr
77    }
78
79    /// Convert this actor reference into its corresponding actor address.
80    pub fn into_actor_addr(self) -> ActorAddr {
81        self.actor_addr
82    }
83
84    /// Attempt to downcast this reference into a (local) actor handle.
85    /// This will only succeed when the referenced actor is in the same
86    /// proc as the caller.
87    pub fn downcast_handle(&self, cx: &impl context::Actor) -> Option<ActorHandle<A>>
88    where
89        A: Actor,
90    {
91        cx.instance().proc().resolve_actor_ref(self)
92    }
93}
94
95impl<A, B> From<&ActorRef<A>> for ActorRef<B>
96where
97    A: Actor + Referable,
98    B: Binds<A>,
99{
100    fn from(value: &ActorRef<A>) -> Self {
101        ActorRef::attest(value.actor_addr().clone())
102    }
103}
104
105impl<A, M> Endpoint<M> for &ActorRef<A>
106where
107    A: Referable + RemoteHandles<M>,
108    M: RemoteMessage,
109{
110    fn endpoint_location(&self) -> EndpointLocation {
111        EndpointLocation::Actor(self.actor_addr.clone())
112    }
113
114    fn post<C>(self, cx: &C, message: M)
115    where
116        C: context::Actor,
117    {
118        RemoteEndpoint::post_with_headers(self, cx, Flattrs::new(), message)
119    }
120}
121
122impl<A, M> RemoteEndpoint<M> for &ActorRef<A>
123where
124    A: Referable + RemoteHandles<M>,
125    M: RemoteMessage,
126{
127    fn post_with_headers<C>(self, cx: &C, headers: Flattrs, message: M)
128    where
129        C: context::Actor,
130    {
131        RemoteEndpoint::post_with_headers(&self.port(), cx, headers, message)
132    }
133}
134
135// Implement Serialize manually, without requiring A: Serialize
136impl<A: Referable> Serialize for ActorRef<A> {
137    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
138    where
139        S: Serializer,
140    {
141        // Serialize only the fields that don't depend on A
142        self.actor_addr.serialize(serializer)
143    }
144}
145
146// Implement Deserialize manually, without requiring A: Deserialize
147impl<'de, A: Referable> Deserialize<'de> for ActorRef<A> {
148    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
149    where
150        D: Deserializer<'de>,
151    {
152        let actor_addr = <ActorAddr>::deserialize(deserializer)?;
153        Ok(ActorRef {
154            actor_addr,
155            phantom: PhantomData,
156        })
157    }
158}
159
160// Implement Debug manually, without requiring A: Debug
161impl<A: Referable> fmt::Debug for ActorRef<A> {
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163        f.debug_struct("ActorRef")
164            .field("actor_addr", &self.actor_addr)
165            .field("type", &std::any::type_name::<A>())
166            .finish()
167    }
168}
169
170impl<A: Referable> fmt::Display for ActorRef<A> {
171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172        fmt::Display::fmt(&self.actor_addr, f)?;
173        write!(f, "<{}>", std::any::type_name::<A>())
174    }
175}
176
177// We implement Clone manually to avoid imposing A: Clone.
178impl<A: Referable> Clone for ActorRef<A> {
179    fn clone(&self) -> Self {
180        Self {
181            actor_addr: self.actor_addr.clone(),
182            phantom: PhantomData,
183        }
184    }
185}
186
187impl<A: Referable> PartialEq for ActorRef<A> {
188    fn eq(&self, other: &Self) -> bool {
189        self.actor_addr == other.actor_addr
190    }
191}
192
193impl<A: Referable> Eq for ActorRef<A> {}
194
195impl<A: Referable> PartialOrd for ActorRef<A> {
196    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
197        Some(self.cmp(other))
198    }
199}
200
201impl<A: Referable> Ord for ActorRef<A> {
202    fn cmp(&self, other: &Self) -> Ordering {
203        self.actor_addr.cmp(&other.actor_addr)
204    }
205}
206
207impl<A: Referable> Hash for ActorRef<A> {
208    fn hash<H: Hasher>(&self, state: &mut H) {
209        self.actor_addr.hash(state);
210    }
211}
212
213/// A reference to a remote port. All messages passed through
214/// PortRefs will be serialized. PortRefs are always streaming.
215#[derive(Debug, Derivative, typeuri::Named)]
216#[derivative(PartialEq, Eq, PartialOrd, Hash, Ord)]
217pub struct PortRef<M> {
218    port_addr: PortAddr,
219    #[derivative(
220        PartialEq = "ignore",
221        PartialOrd = "ignore",
222        Ord = "ignore",
223        Hash = "ignore"
224    )]
225    reducer_spec: Option<ReducerSpec>,
226    #[derivative(
227        PartialEq = "ignore",
228        PartialOrd = "ignore",
229        Ord = "ignore",
230        Hash = "ignore"
231    )]
232    streaming_opts: StreamingReducerOpts,
233    phantom: PhantomData<M>,
234    return_undeliverable: bool,
235    #[derivative(
236        PartialEq = "ignore",
237        PartialOrd = "ignore",
238        Ord = "ignore",
239        Hash = "ignore"
240    )]
241    unsplit: bool,
242}
243
244#[doc(hidden)]
245#[derive(Debug, Clone, Serialize, Deserialize, typeuri::Named)]
246pub struct PortRefRepr {
247    port_addr: PortAddr,
248    reducer_spec: Option<ReducerSpec>,
249    streaming_opts: StreamingReducerOpts,
250    return_undeliverable: bool,
251    unsplit: bool,
252}
253
254impl PortRefRepr {
255    /// This port's address.
256    pub fn port_addr(&self) -> &PortAddr {
257        &self.port_addr
258    }
259
260    /// The typehash of this port's reducer, if any.
261    pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
262        &self.reducer_spec
263    }
264
265    /// This port's streaming reducer options.
266    pub fn streaming_opts(&self) -> &StreamingReducerOpts {
267        &self.streaming_opts
268    }
269
270    /// Get whether undeliverable messages should be returned to the sender.
271    pub fn get_return_undeliverable(&self) -> bool {
272        self.return_undeliverable
273    }
274
275    /// Whether the port must not be split.
276    pub fn unsplit(&self) -> bool {
277        self.unsplit
278    }
279
280    /// Update this port's address.
281    pub fn update_port_addr(&mut self, port_addr: PortAddr) {
282        self.port_addr = port_addr;
283    }
284}
285
286impl<M> TryFrom<&PortRef<M>> for PortRefRepr {
287    type Error = serde_multipart::Error;
288
289    fn try_from(port_ref: &PortRef<M>) -> serde_multipart::Result<Self> {
290        Ok(Self {
291            port_addr: port_ref.port_addr.clone(),
292            reducer_spec: port_ref.reducer_spec.clone(),
293            streaming_opts: port_ref.streaming_opts.clone(),
294            return_undeliverable: port_ref.return_undeliverable,
295            unsplit: port_ref.unsplit,
296        })
297    }
298}
299
300impl<M> TryFrom<PortRefRepr> for PortRef<M> {
301    type Error = serde_multipart::Error;
302
303    fn try_from(repr: PortRefRepr) -> serde_multipart::Result<Self> {
304        Ok(Self {
305            port_addr: repr.port_addr,
306            reducer_spec: repr.reducer_spec,
307            streaming_opts: repr.streaming_opts,
308            phantom: PhantomData,
309            return_undeliverable: repr.return_undeliverable,
310            unsplit: repr.unsplit,
311        })
312    }
313}
314
315serde_multipart::part_codec! {
316    impl<M> PortRef<M>
317    {
318        type Repr = PortRefRepr;
319    }
320}
321
322impl<M: RemoteMessage> PortRef<M> {
323    /// The caller attests that the provided port address identifies a
324    /// reachable typed port for message type `M`.
325    pub fn attest(port_addr: PortAddr) -> Self {
326        Self {
327            port_addr,
328            reducer_spec: None,
329            streaming_opts: StreamingReducerOpts::default(),
330            phantom: PhantomData,
331            return_undeliverable: true,
332            unsplit: false,
333        }
334    }
335
336    /// The caller attests that the provided port address identifies a
337    /// reachable typed port for message type `M`.
338    pub fn attest_reducible(
339        port_addr: PortAddr,
340        reducer_spec: Option<ReducerSpec>,
341        streaming_opts: StreamingReducerOpts,
342    ) -> Self {
343        Self {
344            port_addr,
345            reducer_spec,
346            streaming_opts,
347            phantom: PhantomData,
348            return_undeliverable: true,
349            unsplit: false,
350        }
351    }
352
353    /// Prevents the port from being split.
354    pub fn unsplit(mut self) -> Self {
355        self.unsplit = true;
356        self
357    }
358
359    /// The caller attests that the provided actor exposes a reachable handler
360    /// port for message type `M`.
361    pub fn attest_handler_port(actor: &ActorAddr) -> Self {
362        PortRef::<M>::attest(actor.port_addr(Port::handler::<M>()))
363    }
364
365    /// The typehash of this port's reducer, if any. Reducers
366    /// may be used to coalesce messages sent to a port.
367    pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
368        &self.reducer_spec
369    }
370
371    /// This port's address.
372    pub fn port_addr(&self) -> &PortAddr {
373        &self.port_addr
374    }
375
376    /// Convert this PortRef into its corresponding port address.
377    pub fn into_port_addr(self) -> PortAddr {
378        self.port_addr
379    }
380
381    /// coerce it into OncePortRef so we can send messages to this port from
382    /// APIs requires OncePortRef.
383    pub fn into_once(self) -> OncePortRef<M> {
384        let return_undeliverable = self.return_undeliverable;
385        let unsplit = self.unsplit;
386        let mut once = OncePortRef::attest(self.into_port_addr());
387        once.return_undeliverable = return_undeliverable;
388        once.unsplit = unsplit;
389        once
390    }
391
392    /// Post a serialized message to this port, provided a sending capability, such as
393    /// [`crate::actor::Instance`].
394    pub fn post_serialized(
395        &self,
396        cx: &impl context::Actor,
397        mut headers: Flattrs,
398        message: wirevalue::Any,
399    ) {
400        crate::mailbox::headers::set_send_timestamp(&mut headers);
401        crate::mailbox::headers::set_rust_message_type::<M>(&mut headers);
402        cx.post(
403            self.port_addr.clone(),
404            headers,
405            message,
406            self.return_undeliverable,
407            context::SeqInfoPolicy::AssignNew,
408        );
409    }
410
411    /// Convert this port into a sink that can be used to send messages using the given capability.
412    pub fn into_sink<C: context::Actor>(self, cx: C) -> PortSink<C, M> {
413        PortSink::new(cx, self)
414    }
415
416    /// Get whether or not messages sent to this port that are undeliverable should
417    /// be returned to the sender.
418    pub fn get_return_undeliverable(&self) -> bool {
419        self.return_undeliverable
420    }
421
422    /// Set whether or not messages sent to this port that are undeliverable
423    /// should be returned to the sender.
424    pub fn return_undeliverable(&mut self, return_undeliverable: bool) {
425        self.return_undeliverable = return_undeliverable;
426    }
427}
428
429impl<M> Endpoint<M> for &PortRef<M>
430where
431    M: RemoteMessage,
432{
433    fn endpoint_location(&self) -> EndpointLocation {
434        EndpointLocation::Port(self.port_addr.clone())
435    }
436
437    fn post<C>(self, cx: &C, message: M)
438    where
439        C: context::Actor,
440    {
441        RemoteEndpoint::post_with_headers(self, cx, Flattrs::new(), message)
442    }
443}
444
445impl<M> RemoteEndpoint<M> for &PortRef<M>
446where
447    M: RemoteMessage,
448{
449    fn post_with_headers<C>(self, cx: &C, headers: Flattrs, message: M)
450    where
451        C: context::Actor,
452    {
453        let serialized = match wirevalue::Any::serialize(&message).map_err(|err| {
454            MailboxSenderError::new_bound(
455                self.port_addr.clone(),
456                MailboxSenderErrorKind::Serialize(err.into()),
457            )
458        }) {
459            Ok(serialized) => serialized,
460            Err(err) => {
461                cx.instance()
462                    .report_delivery_failure(DeliveryFailureReport::from_send_error::<M>(
463                        cx.mailbox().actor_addr().clone(),
464                        self.endpoint_location(),
465                        &err,
466                    ));
467                return;
468            }
469        };
470        self.post_serialized(cx, headers, serialized);
471    }
472}
473
474impl<M: RemoteMessage> Clone for PortRef<M> {
475    fn clone(&self) -> Self {
476        Self {
477            port_addr: self.port_addr.clone(),
478            reducer_spec: self.reducer_spec.clone(),
479            streaming_opts: self.streaming_opts.clone(),
480            phantom: PhantomData,
481            return_undeliverable: self.return_undeliverable,
482            unsplit: self.unsplit,
483        }
484    }
485}
486
487impl<M: RemoteMessage> fmt::Display for PortRef<M> {
488    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489        fmt::Display::fmt(&self.port_addr, f)
490    }
491}
492
493/// A remote reference to a [`OncePort`]. References are serializable
494/// and may be passed to remote actors, which can then use it to send
495/// a message to this port.
496#[derive(Debug, PartialEq)]
497pub struct OncePortRef<M> {
498    port_addr: PortAddr,
499    reducer_spec: Option<ReducerSpec>,
500    return_undeliverable: bool,
501    unsplit: bool,
502    phantom: PhantomData<M>,
503}
504
505#[doc(hidden)]
506#[derive(Debug, Clone, Serialize, Deserialize, typeuri::Named)]
507pub struct OncePortRefRepr {
508    port_addr: PortAddr,
509    reducer_spec: Option<ReducerSpec>,
510    return_undeliverable: bool,
511    unsplit: bool,
512}
513
514impl OncePortRefRepr {
515    /// This port's address.
516    pub fn port_addr(&self) -> &PortAddr {
517        &self.port_addr
518    }
519
520    /// The typehash of this port's reducer, if any.
521    pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
522        &self.reducer_spec
523    }
524
525    /// Get whether undeliverable messages should be returned to the sender.
526    pub fn get_return_undeliverable(&self) -> bool {
527        self.return_undeliverable
528    }
529
530    /// Whether the port must not be split.
531    pub fn unsplit(&self) -> bool {
532        self.unsplit
533    }
534
535    /// Update this port's address.
536    pub fn update_port_addr(&mut self, port_addr: PortAddr) {
537        self.port_addr = port_addr;
538    }
539}
540
541impl<M> TryFrom<&OncePortRef<M>> for OncePortRefRepr {
542    type Error = serde_multipart::Error;
543
544    fn try_from(port_ref: &OncePortRef<M>) -> serde_multipart::Result<Self> {
545        Ok(Self {
546            port_addr: port_ref.port_addr.clone(),
547            reducer_spec: port_ref.reducer_spec.clone(),
548            return_undeliverable: port_ref.return_undeliverable,
549            unsplit: port_ref.unsplit,
550        })
551    }
552}
553
554impl<M> TryFrom<OncePortRefRepr> for OncePortRef<M> {
555    type Error = serde_multipart::Error;
556
557    fn try_from(repr: OncePortRefRepr) -> serde_multipart::Result<Self> {
558        Ok(Self {
559            port_addr: repr.port_addr,
560            reducer_spec: repr.reducer_spec,
561            return_undeliverable: repr.return_undeliverable,
562            unsplit: repr.unsplit,
563            phantom: PhantomData,
564        })
565    }
566}
567
568serde_multipart::part_codec! {
569    impl<M> OncePortRef<M>
570    {
571        type Repr = OncePortRefRepr;
572    }
573}
574
575impl<M: RemoteMessage> OncePortRef<M> {
576    pub(crate) fn attest(port_addr: PortAddr) -> Self {
577        Self {
578            port_addr,
579            reducer_spec: None,
580            return_undeliverable: true,
581            unsplit: false,
582            phantom: PhantomData,
583        }
584    }
585
586    /// The caller attests that the provided PortId can be
587    /// converted to a reachable, typed once port reference.
588    pub fn attest_reducible(port_addr: PortAddr, reducer_spec: Option<ReducerSpec>) -> Self {
589        Self {
590            port_addr,
591            reducer_spec,
592            return_undeliverable: true,
593            unsplit: false,
594            phantom: PhantomData,
595        }
596    }
597
598    /// Prevents the port from being split.
599    pub fn unsplit(mut self) -> Self {
600        self.unsplit = true;
601        self
602    }
603
604    /// The typehash of this port's reducer, if any.
605    pub fn reducer_spec(&self) -> &Option<ReducerSpec> {
606        &self.reducer_spec
607    }
608
609    /// This port's address.
610    pub fn port_addr(&self) -> &PortAddr {
611        &self.port_addr
612    }
613
614    /// Convert this OncePortRef into its corresponding port address.
615    pub fn into_port_addr(self) -> PortAddr {
616        self.port_addr
617    }
618
619    /// Get whether or not messages sent to this port that are undeliverable should
620    /// be returned to the sender.
621    pub fn get_return_undeliverable(&self) -> bool {
622        self.return_undeliverable
623    }
624
625    /// Set whether or not messages sent to this port that are undeliverable
626    /// should be returned to the sender.
627    pub fn return_undeliverable(&mut self, return_undeliverable: bool) {
628        self.return_undeliverable = return_undeliverable;
629    }
630}
631
632impl<M> Endpoint<M> for OncePortRef<M>
633where
634    M: RemoteMessage,
635{
636    fn endpoint_location(&self) -> EndpointLocation {
637        EndpointLocation::Port(self.port_addr.clone())
638    }
639
640    fn post<C>(self, cx: &C, message: M)
641    where
642        C: context::Actor,
643    {
644        RemoteEndpoint::post_with_headers(self, cx, Flattrs::new(), message)
645    }
646}
647
648impl<M> RemoteEndpoint<M> for OncePortRef<M>
649where
650    M: RemoteMessage,
651{
652    fn post_with_headers<C>(self, cx: &C, mut headers: Flattrs, message: M)
653    where
654        C: context::Actor,
655    {
656        crate::mailbox::headers::set_send_timestamp(&mut headers);
657        let serialized = match wirevalue::Any::serialize(&message).map_err(|err| {
658            MailboxSenderError::new_bound(
659                self.port_addr.clone(),
660                MailboxSenderErrorKind::Serialize(err.into()),
661            )
662        }) {
663            Ok(serialized) => serialized,
664            Err(err) => {
665                cx.instance()
666                    .report_delivery_failure(DeliveryFailureReport::from_send_error::<M>(
667                        cx.mailbox().actor_addr().clone(),
668                        self.endpoint_location(),
669                        &err,
670                    ));
671                return;
672            }
673        };
674        cx.post(
675            self.port_addr.clone(),
676            headers,
677            serialized,
678            self.return_undeliverable,
679            context::SeqInfoPolicy::AssignNew,
680        );
681    }
682}
683
684impl<M: RemoteMessage> Clone for OncePortRef<M> {
685    fn clone(&self) -> Self {
686        Self {
687            port_addr: self.port_addr.clone(),
688            reducer_spec: self.reducer_spec.clone(),
689            return_undeliverable: self.return_undeliverable,
690            unsplit: self.unsplit,
691            phantom: PhantomData,
692        }
693    }
694}
695
696impl<M: RemoteMessage> fmt::Display for OncePortRef<M> {
697    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
698        fmt::Display::fmt(&self.port_addr, f)
699    }
700}
701
702impl<M: RemoteMessage> Named for OncePortRef<M> {
703    fn typename() -> &'static str {
704        wirevalue::intern_typename!(Self, "hyperactor::mailbox::OncePortRef<{}>", M)
705    }
706}
707
708#[cfg(test)]
709mod tests {
710    use serde::Deserialize;
711    use serde::Serialize;
712    use serde_multipart::PartCodec;
713    use typeuri::Named;
714
715    use super::*;
716    use crate::channel::ChannelAddr;
717    use crate::id::ActorId;
718    use crate::id::Label;
719    use crate::id::PortId;
720    use crate::id::ProcId;
721
722    fn test_port_ref() -> PortRef<String> {
723        let proc_id = ProcId::singleton(Label::new("proc").unwrap());
724        let actor_id = ActorId::singleton(Label::new("actor").unwrap(), proc_id);
725        let port_id = PortId::new(actor_id, Port::from(7));
726        let port_addr = PortAddr::new(port_id, ChannelAddr::Local(42).into());
727        let mut port_ref = PortRef::<String>::attest(port_addr).unsplit();
728        port_ref.return_undeliverable(false);
729        port_ref
730    }
731
732    fn test_once_port_ref() -> OncePortRef<String> {
733        let proc_id = ProcId::singleton(Label::new("proc").unwrap());
734        let actor_id = ActorId::singleton(Label::new("actor").unwrap(), proc_id);
735        let port_id = PortId::new(actor_id, Port::from(8));
736        let port_addr = PortAddr::new(port_id, ChannelAddr::Local(43).into());
737        let mut once_port_ref = OncePortRef::<String>::attest(port_addr).unsplit();
738        once_port_ref.return_undeliverable(false);
739        once_port_ref
740    }
741
742    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
743    struct PortRefEnvelope {
744        port: PortRef<String>,
745        seq: u64,
746    }
747
748    #[derive(Debug, PartialEq, Serialize, Deserialize)]
749    struct OncePortRefEnvelope {
750        port: OncePortRef<String>,
751        seq: u64,
752    }
753
754    fn assert_same_port_ref(actual: &PortRef<String>, expected: &PortRef<String>) {
755        let actual = actual.to_repr().unwrap();
756        let expected = expected.to_repr().unwrap();
757        assert_eq!(actual.port_addr, expected.port_addr);
758        assert_eq!(actual.reducer_spec, expected.reducer_spec);
759        assert_eq!(actual.streaming_opts, expected.streaming_opts);
760        assert_eq!(actual.return_undeliverable, expected.return_undeliverable);
761        assert_eq!(actual.unsplit, expected.unsplit);
762    }
763
764    fn assert_same_once_port_ref(actual: &OncePortRef<String>, expected: &OncePortRef<String>) {
765        let actual = actual.to_repr().unwrap();
766        let expected = expected.to_repr().unwrap();
767        assert_eq!(actual.port_addr, expected.port_addr);
768        assert_eq!(actual.reducer_spec, expected.reducer_spec);
769        assert_eq!(actual.return_undeliverable, expected.return_undeliverable);
770        assert_eq!(actual.unsplit, expected.unsplit);
771    }
772
773    #[test]
774    fn test_port_ref_serde_multipart_part_codec() {
775        let value = PortRefEnvelope {
776            port: test_port_ref(),
777            seq: 123,
778        };
779
780        let message = serde_multipart::serialize_bincode(&value).unwrap();
781        assert_eq!(message.num_parts(), 1);
782        assert_eq!(message.parts()[0].typehash(), Some(PortRefRepr::typehash()));
783
784        let repr = message.parts()[0].deserialized::<PortRefRepr>().unwrap();
785        assert_eq!(repr.port_addr, value.port.port_addr().clone());
786        assert!(!repr.return_undeliverable);
787        assert!(repr.unsplit);
788
789        let deserialized: PortRefEnvelope = serde_multipart::deserialize_bincode(message).unwrap();
790        assert_eq!(deserialized.seq, value.seq);
791        assert_same_port_ref(&deserialized.port, &value.port);
792    }
793
794    #[test]
795    fn test_once_port_ref_serde_multipart_part_codec() {
796        let value = OncePortRefEnvelope {
797            port: test_once_port_ref(),
798            seq: 789,
799        };
800
801        let message = serde_multipart::serialize_bincode(&value).unwrap();
802        assert_eq!(message.num_parts(), 1);
803        assert_eq!(
804            message.parts()[0].typehash(),
805            Some(OncePortRefRepr::typehash())
806        );
807
808        let repr = message.parts()[0]
809            .deserialized::<OncePortRefRepr>()
810            .unwrap();
811        assert_eq!(repr.port_addr, value.port.port_addr().clone());
812        assert!(!repr.return_undeliverable);
813        assert!(repr.unsplit);
814
815        let deserialized: OncePortRefEnvelope =
816            serde_multipart::deserialize_bincode(message).unwrap();
817        assert_eq!(deserialized.seq, value.seq);
818        assert_same_once_port_ref(&deserialized.port, &value.port);
819    }
820
821    #[test]
822    fn test_port_ref_regular_serde_uses_repr() {
823        let value = PortRefEnvelope {
824            port: test_port_ref(),
825            seq: 456,
826        };
827
828        let encoded = bincode::serde::encode_to_vec(&value, bincode::config::standard()).unwrap();
829        let (deserialized, len): (PortRefEnvelope, usize) =
830            bincode::serde::decode_from_slice(&encoded, bincode::config::standard()).unwrap();
831
832        assert_eq!(len, encoded.len());
833        assert_eq!(deserialized.seq, value.seq);
834        assert_same_port_ref(&deserialized.port, &value.port);
835    }
836
837    #[test]
838    fn test_once_port_ref_regular_serde_uses_repr() {
839        let value = OncePortRefEnvelope {
840            port: test_once_port_ref(),
841            seq: 1011,
842        };
843
844        let encoded = bincode::serde::encode_to_vec(&value, bincode::config::standard()).unwrap();
845        let (deserialized, len): (OncePortRefEnvelope, usize) =
846            bincode::serde::decode_from_slice(&encoded, bincode::config::standard()).unwrap();
847
848        assert_eq!(len, encoded.len());
849        assert_eq!(deserialized.seq, value.seq);
850        assert_same_once_port_ref(&deserialized.port, &value.port);
851    }
852}