Skip to main content

palladium_actor/
bridge.rs

1use crate::envelope::Envelope;
2use crate::errors::SendError;
3use crate::message::MessagePayload;
4use crate::path::{ActorPath, AddrHash};
5use crate::spec::ChildSpec;
6use std::future::Future;
7use std::pin::Pin;
8use std::sync::Arc;
9use std::time::Duration;
10
11/// A cheaply cloneable, type-erased send function that delivers directly to a
12/// cached `MailboxSender`, bypassing the global `TransportRegistry`.
13///
14/// Created by [`RuntimeBridge::cached_sender`] and stored in each actor's
15/// `AddrCache` keyed by the destination `AddrHash`.
16pub type CachedSendFn =
17    Arc<dyn Fn(Envelope, MessagePayload) -> Result<(), SendError> + Send + Sync + 'static>;
18
19// ── Reactor ───────────────────────────────────────────────────────────────────
20
21/// Handle to a spawned task.
22pub trait SpawnHandle: Send + Sync + 'static {
23    fn abort(&self);
24}
25
26/// Minimal abstraction over the async runtime, provided to actors.
27pub trait Reactor: Send + Sync + 'static {
28    /// Create a clone of this reactor, boxed.
29    fn clone_box(&self) -> Box<dyn Reactor>;
30
31    /// Spawn a task local to the current thread.
32    fn spawn_local(
33        &self,
34        fut: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
35    ) -> Box<dyn SpawnHandle>;
36
37    /// Spawn a task that can run on any thread.
38    fn spawn(
39        &self,
40        fut: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
41    ) -> Box<dyn SpawnHandle>;
42
43    /// Yield execution back to the scheduler.
44    fn yield_now(&self) -> Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>>;
45
46    /// Sleep for `duration` under the current time model.
47    fn sleep(
48        &self,
49        duration: Duration,
50    ) -> Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>>;
51
52    /// Return the current instant under the current time model.
53    fn now(&self) -> std::time::Instant;
54
55    /// Measures nanoseconds elapsed since `start`.
56    fn elapsed_since(&self, start: std::time::Instant) -> u64;
57
58    /// Create a periodic interval that ticks every `duration`.
59    fn create_interval(&self, duration: Duration) -> Box<dyn Interval>;
60
61    /// Return a random u64 from the reactor's RNG.
62    fn next_u64(&self) -> u64;
63}
64
65/// A periodic timer that can be polled or awaited.
66pub trait Interval: Send + 'static {
67    /// Wait for the next tick of the interval.
68    fn tick(&mut self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
69}
70
71// ── RuntimeBridge ─────────────────────────────────────────────────────────────
72
73/// Bridge between `ActorContext` methods and the runtime event loop.
74///
75/// Implemented by `pd-runtime`; injected into each actor's context at spawn
76/// time.  Uses only types defined in `pd-actor` to avoid a circular
77/// crate dependency.
78pub trait RuntimeBridge<R: Reactor>: Reactor {
79    /// Access the underlying reactor implementation.
80    fn reactor(&self) -> &R;
81
82    /// Spawn a child actor under `parent`'s path.  Returns the child's
83    /// `AddrHash` (derived synchronously from the path); the runtime processes
84    /// the spawn asynchronously.
85    fn spawn_child(&self, spec: ChildSpec<R>, parent: &ActorPath) -> AddrHash;
86
87    /// Signal the event loop to stop this actor after the current handler
88    /// returns.
89    fn stop_self(&self);
90
91    /// Route a pre-built envelope through the local transport layer.
92    fn route(&self, envelope: Envelope, payload: MessagePayload) -> Result<(), SendError>;
93
94    /// Schedule `payload` to be sent at `envelope.destination` after `delay`.
95    fn send_after(&self, delay: Duration, envelope: Envelope, payload: MessagePayload);
96
97    /// Resolve an actor's current address by its path.
98    fn lookup_path(&self, path: &ActorPath) -> Option<AddrHash>;
99
100    /// Resolve an actor's path from its address hash.
101    ///
102    /// Used by `ActorContext::send_raw` to enforce namespace policy.
103    /// Returns `None` if the address is unknown (e.g., synthetic or external);
104    /// callers fail open in that case.
105    fn resolve_addr(&self, hash: AddrHash) -> Option<ActorPath> {
106        let _ = hash;
107        None
108    }
109
110    /// Return a direct `CachedSendFn` for `addr` if it is a local actor.
111    ///
112    /// The returned closure bypasses the global `TransportRegistry` and sends
113    /// directly to the actor's `MailboxSender`.  Returns `None` when the
114    /// destination is not local (remote / federated actors).
115    ///
116    /// Default implementation returns `None`; `RuntimeBridgeImpl` overrides
117    /// this to perform the DashMap lookup and wrap the sender.
118    fn cached_sender(&self, addr: AddrHash) -> Option<CachedSendFn> {
119        let _ = addr;
120        None
121    }
122}