acktor-ipc 1.0.10

Interprocess communication support for the acktor actor framework
Documentation
use std::num::NonZeroU64;
use std::sync::{Arc, Weak};

use futures_util::{FutureExt, TryFutureExt};
use tokio::{runtime, time::Duration};

use acktor::{
    Address,
    address::{DoSendResult, DoSendResultFuture, EmptyFuture},
};

use super::Session;
use crate::codec::{DecodeContext, EncodeContext, EncodeError};
use crate::remote::{BinaryMessage, RemoteMailbox, RemoteMailboxRegistry, RemoteProxy};

pub struct Proxy {
    session: Address<Session>,
    registry: RemoteMailboxRegistry,
    runtime: runtime::Handle,
    me: Weak<Self>,
}

impl Proxy {
    #[inline]
    pub fn new(session: Address<Session>, registry: RemoteMailboxRegistry) -> Arc<Self> {
        Arc::new_cyclic(|me| Self {
            session,
            registry,
            runtime: runtime::Handle::current(),
            me: me.clone(),
        })
    }
}

impl RemoteProxy for Proxy {
    #[inline]
    fn runtime(&self) -> runtime::Handle {
        self.runtime.clone()
    }

    #[inline]
    fn encode_context(&self) -> Option<&dyn EncodeContext> {
        Some(self)
    }

    #[inline]
    fn decode_context(&self) -> Option<&dyn DecodeContext> {
        Some(self)
    }

    #[inline]
    fn index(&self) -> NonZeroU64 {
        NonZeroU64::new(self.session.index().as_local())
            .expect("session index is always non-zero since it can only be created by a node")
    }

    #[inline]
    fn closed(&self) -> EmptyFuture<'_> {
        self.session.closed().boxed()
    }

    #[inline]
    fn is_closed(&self) -> bool {
        self.session.is_closed()
    }

    #[inline]
    fn capacity(&self) -> usize {
        self.session.capacity()
    }

    #[inline]
    fn do_send(&self, msg: BinaryMessage) -> DoSendResultFuture<'_, ()> {
        self.session
            .do_send(msg)
            .map_err(|e| e.without_msg())
            .boxed()
    }

    #[inline]
    fn try_do_send(&self, msg: BinaryMessage) -> DoSendResult<()> {
        self.session.try_do_send(msg).map_err(|e| e.without_msg())
    }

    #[inline]
    fn do_send_timeout(&self, msg: BinaryMessage, timeout: Duration) -> DoSendResultFuture<'_, ()> {
        self.session
            .do_send_timeout(msg, timeout)
            .map_err(|e| e.without_msg())
            .boxed()
    }

    #[inline]
    fn blocking_do_send(&self, msg: BinaryMessage) -> DoSendResult<()> {
        self.session
            .blocking_do_send(msg)
            .map_err(|e| e.without_msg())
    }
}

impl EncodeContext for Proxy {
    #[inline]
    fn register(&self, actor: RemoteMailbox) -> Result<(), EncodeError> {
        self.registry.insert(actor);

        Ok(())
    }
}

impl DecodeContext for Proxy {
    #[inline]
    fn remote_proxy(&self) -> Option<Arc<dyn RemoteProxy + Send + Sync>> {
        self.me
            .upgrade()
            .map(|proxy| proxy as Arc<dyn RemoteProxy + Send + Sync>)
    }
}