Skip to main content

palladium_actor/
handle.rs

1use crate::envelope::Envelope;
2use crate::errors::{AskError, SendError};
3use crate::message::{Message, MessagePayload};
4use crate::path::AddrHash;
5use std::fmt;
6use std::future::Future;
7use std::pin::Pin;
8use std::sync::{Arc, Weak};
9
10pub type SendFn<M> = Arc<dyn Fn(M) -> Result<(), SendError> + Send + Sync>;
11pub type AskFuture<M> =
12    Pin<Box<dyn Future<Output = Result<<M as Message>::Response, AskError>> + Send>>;
13pub type AskFn<M> = Arc<dyn Fn(M) -> AskFuture<M> + Send + Sync>;
14
15pub(crate) struct AddrInner<M: Message> {
16    pub(crate) target: AddrHash,
17    pub(crate) send_fn: Option<SendFn<M>>,
18    pub(crate) ask_fn: Option<AskFn<M>>,
19}
20
21/// A typed, unforgeable capability handle granting the right to send messages
22/// of type `M` to a specific actor.
23///
24/// Cannot be constructed by user code — only the runtime grants `Addr<M>`
25/// instances (at spawn time or via supervisor delegation).
26pub struct Addr<M: Message> {
27    pub(crate) inner: Arc<AddrInner<M>>,
28}
29
30impl<M: Message> Clone for Addr<M> {
31    fn clone(&self) -> Self {
32        Self {
33            inner: self.inner.clone(),
34        }
35    }
36}
37
38impl<M: Message> fmt::Debug for Addr<M> {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.debug_struct("Addr")
41            .field("target", &self.inner.target)
42            .finish()
43    }
44}
45
46impl<M: Message> Addr<M> {
47    /// Create a typed capability handle with send and ask backends.
48    ///
49    /// Called by the runtime when spawning actors; not intended for direct
50    /// use in application code.
51    pub fn with_handlers(target: AddrHash, send_fn: SendFn<M>, ask_fn: AskFn<M>) -> Self {
52        Self {
53            inner: Arc::new(AddrInner {
54                target,
55                send_fn: Some(send_fn),
56                ask_fn: Some(ask_fn),
57            }),
58        }
59    }
60
61    /// Create an unbound handle (no send/ask backend).  Useful for holding
62    /// an address reference before the actor is live.
63    pub fn unbound(target: AddrHash) -> Self {
64        Self {
65            inner: Arc::new(AddrInner {
66                target,
67                send_fn: None,
68                ask_fn: None,
69            }),
70        }
71    }
72
73    pub fn target(&self) -> AddrHash {
74        self.inner.target
75    }
76
77    /// Non-blocking fire-and-forget send.  Returns `SendError::MailboxFull`
78    /// immediately if the mailbox is at capacity.
79    pub fn send(&self, msg: M) -> Result<(), SendError> {
80        match &self.inner.send_fn {
81            Some(f) => f(msg),
82            None => Err(SendError::Unbound),
83        }
84    }
85
86    /// Request/response send.  Returns a future that resolves to the response.
87    pub async fn ask(&self, msg: M) -> Result<M::Response, AskError> {
88        match &self.inner.ask_fn {
89            Some(f) => f(msg).await,
90            None => Err(AskError::Unbound),
91        }
92    }
93
94    pub fn downgrade(&self) -> WeakAddr<M> {
95        WeakAddr {
96            inner: Arc::downgrade(&self.inner),
97        }
98    }
99}
100
101/// A non-owning capability reference.  Does not extend the target actor's
102/// lifetime.  `upgrade()` returns `None` after the actor stops.
103pub struct WeakAddr<M: Message> {
104    pub(crate) inner: Weak<AddrInner<M>>,
105}
106
107impl<M: Message> Clone for WeakAddr<M> {
108    fn clone(&self) -> Self {
109        Self {
110            inner: self.inner.clone(),
111        }
112    }
113}
114
115impl<M: Message> fmt::Debug for WeakAddr<M> {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        f.debug_struct("WeakAddr").finish_non_exhaustive()
118    }
119}
120
121impl<M: Message> WeakAddr<M> {
122    pub fn upgrade(&self) -> Option<Addr<M>> {
123        self.inner.upgrade().map(|inner| Addr { inner })
124    }
125}
126
127// ── AnyAddr ───────────────────────────────────────────────────────────────────
128
129pub type RouteFn = Arc<dyn Fn(Envelope, MessagePayload) -> Result<(), SendError> + Send + Sync>;
130
131/// A type-erased capability handle for routing pre-built envelopes without
132/// knowing the message type.  Used internally by the transport and routing
133/// layers.
134pub struct AnyAddr {
135    pub(crate) target: AddrHash,
136    pub(crate) route_fn: Option<RouteFn>,
137}
138
139impl AnyAddr {
140    pub fn with_route(target: AddrHash, route_fn: RouteFn) -> Self {
141        Self {
142            target,
143            route_fn: Some(route_fn),
144        }
145    }
146
147    pub fn unbound(target: AddrHash) -> Self {
148        Self {
149            target,
150            route_fn: None,
151        }
152    }
153
154    pub fn target(&self) -> AddrHash {
155        self.target
156    }
157
158    /// Route a pre-built envelope and payload.
159    pub fn route(&self, envelope: Envelope, payload: MessagePayload) -> Result<(), SendError> {
160        match &self.route_fn {
161            Some(f) => f(envelope, payload),
162            None => Err(SendError::Unbound),
163        }
164    }
165}
166
167impl fmt::Debug for AnyAddr {
168    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169        f.debug_struct("AnyAddr")
170            .field("target", &self.target)
171            .finish_non_exhaustive()
172    }
173}