tiny_actor/actor/
address.rs

1use crate::*;
2use event_listener::EventListener;
3use futures::{Future, FutureExt};
4use std::{
5    fmt::Debug,
6    mem::ManuallyDrop,
7    pin::Pin,
8    sync::Arc,
9    task::{Context, Poll},
10};
11
12/// An address is a reference to the actor, used to send messages.
13///
14/// Addresses can be of two forms:
15/// * `Address<Channel<M>>`: This is the default form, which can be used to send messages of
16/// type `M`. It can be transformed into an `Address` using [Address::into_dyn].
17/// * `Address`: This form is a dynamic address, which can do everything a normal address can
18/// do, except for sending messages. It can be transformed back into an `Address<Channel<M>>` using
19/// [Address::downcast::<M>].
20///
21/// An address can be awaited which returns once the actor exits.
22#[derive(Debug)]
23pub struct Address<C = dyn AnyChannel>
24where
25    C: DynChannel + ?Sized,
26{
27    channel: Arc<C>,
28    exit_listener: Option<EventListener>,
29}
30
31impl<C> Address<C>
32where
33    C: DynChannel + ?Sized,
34{
35    /// Does not increment the address-count.
36    pub(crate) fn from_channel(channel: Arc<C>) -> Self {
37        Self {
38            channel,
39            exit_listener: None,
40        }
41    }
42
43    pub(crate) fn channel(&self) -> &Arc<C> {
44        &self.channel
45    }
46
47    fn into_parts(self) -> (Arc<C>, Option<EventListener>) {
48        let no_drop = ManuallyDrop::new(self);
49        unsafe {
50            let channel = std::ptr::read(&no_drop.channel);
51            let exit_listener = std::ptr::read(&no_drop.exit_listener);
52            (channel, exit_listener)
53        }
54    }
55
56    /// Attempt to the downcast the `Address` into an `Address<Channel<M>>`.
57    pub fn downcast<M: Send + 'static>(self) -> Result<Address<Channel<M>>, Self>
58    where
59        C: AnyChannel,
60    {
61        let (channel, exit_listener) = self.into_parts();
62        match channel.clone().into_any().downcast() {
63            Ok(channel) => Ok(Address {
64                channel,
65                exit_listener,
66            }),
67            Err(_) => Err(Self {
68                channel,
69                exit_listener,
70            }),
71        }
72    }
73
74    gen::dyn_channel_methods!();
75}
76
77impl<M> Address<Channel<M>> {
78    /// Convert the `Address<Channel<M>>` into an `Address`.
79    pub fn into_dyn(self) -> Address
80    where
81        M: Send + 'static,
82    {
83        let (channel, exit_listener) = self.into_parts();
84        Address {
85            channel,
86            exit_listener,
87        }
88    }
89
90    gen::send_methods!();
91}
92
93#[cfg(feature = "internals")]
94impl<C> Address<C>
95where
96    C: DynChannel + ?Sized,
97{
98    pub fn transform_channel<C2: DynChannel + ?Sized>(
99        self,
100        func: fn(Arc<C>) -> Arc<C2>,
101    ) -> Address<C2> {
102        let (channel, exit_listener) = self.into_parts();
103        Address {
104            channel: func(channel),
105            exit_listener,
106        }
107    }
108
109    pub fn channel_ref(&self) -> &C {
110        &self.channel
111    }
112}
113
114impl<C: DynChannel + ?Sized> Future for Address<C> {
115    type Output = ();
116
117    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
118        if self.channel.has_exited() {
119            Poll::Ready(())
120        } else {
121            if self.exit_listener.is_none() {
122                self.exit_listener = Some(self.channel.get_exit_listener())
123            }
124            if self.channel.has_exited() {
125                Poll::Ready(())
126            } else {
127                self.exit_listener.as_mut().unwrap().poll_unpin(cx)
128            }
129        }
130    }
131}
132
133impl<C: DynChannel + ?Sized> Unpin for Address<C> {}
134
135impl<C: DynChannel + ?Sized> Clone for Address<C> {
136    fn clone(&self) -> Self {
137        self.channel.add_address();
138        Self {
139            channel: self.channel.clone(),
140            exit_listener: None,
141        }
142    }
143}
144
145impl<C: DynChannel + ?Sized> Drop for Address<C> {
146    fn drop(&mut self) {
147        self.channel.remove_address();
148    }
149}