behavior/actor/addressing.rs
1//! Protocol-indexed actor recipients and deliveries.
2
3use core::marker::PhantomData;
4
5use crate::Behavior;
6
7/// A pure actor-address namespace.
8pub trait Address: Copy + Eq {
9 type Nonce: Copy + Eq;
10
11 #[must_use]
12 fn birth(self, nonce: Self::Nonce) -> Self;
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub struct MailAddr(pub u64);
17
18impl From<u64> for MailAddr {
19 fn from(value: u64) -> Self {
20 Self(value)
21 }
22}
23
24impl From<MailAddr> for u64 {
25 fn from(value: MailAddr) -> Self {
26 value.0
27 }
28}
29
30impl Address for MailAddr {
31 type Nonce = u64;
32
33 fn birth(self, nonce: u64) -> Self {
34 Self(self.0 ^ nonce.wrapping_mul(0x9E37_79B9_7F4A_7C15))
35 }
36}
37
38/// Internal representation of pure routing intent.
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub(crate) enum Route<A: Address> {
41 Global(A),
42 Child(A::Nonce),
43}
44
45impl<A: Address> Route<A> {
46 #[must_use]
47 pub(crate) const fn global(address: A) -> Self {
48 Self::Global(address)
49 }
50
51 #[must_use]
52 pub(crate) const fn child(nonce: A::Nonce) -> Self {
53 Self::Child(nonce)
54 }
55}
56
57/// Pure routing intent for one concrete destination behavior protocol.
58///
59/// The destination behavior is part of the type even when two protocols share
60/// the same address namespace and message type. The value contains no mailbox,
61/// endpoint, registry entry, or other interpreter-owned capability.
62pub struct Recipient<B: Behavior> {
63 route: Route<B::Addr>,
64 protocol: PhantomData<fn() -> B>,
65}
66
67impl<B: Behavior> Copy for Recipient<B> {}
68
69impl<B: Behavior> Clone for Recipient<B> {
70 fn clone(&self) -> Self {
71 *self
72 }
73}
74
75impl<B: Behavior> Recipient<B> {
76 #[must_use]
77 pub fn global(address: B::Addr) -> Self {
78 Self::from_route(Route::global(address))
79 }
80
81 #[must_use]
82 pub fn child(nonce: <B::Addr as Address>::Nonce) -> Self {
83 Self::from_route(Route::child(nonce))
84 }
85
86 /// Resolve this intent in the address namespace of the sending actor.
87 ///
88 /// Global recipients ignore `parent`; child recipients derive their
89 /// address from it. The route representation remains private so runtimes
90 /// cannot couple endpoint tables to Behaviorpass internals.
91 #[must_use]
92 pub fn resolve(self, parent: B::Addr) -> B::Addr {
93 match self.route {
94 Route::Global(address) => address,
95 Route::Child(nonce) => parent.birth(nonce),
96 }
97 }
98
99 pub(crate) fn is_child(self, expected: <B::Addr as Address>::Nonce) -> bool {
100 matches!(self.route, Route::Child(nonce) if nonce == expected)
101 }
102
103 const fn from_route(route: Route<B::Addr>) -> Self {
104 Self {
105 route,
106 protocol: PhantomData,
107 }
108 }
109}
110
111impl<B: Behavior> PartialEq for Recipient<B> {
112 fn eq(&self, other: &Self) -> bool {
113 self.route == other.route
114 }
115}
116
117impl<B: Behavior> Eq for Recipient<B> {}
118
119impl<B: Behavior> core::fmt::Debug for Recipient<B>
120where
121 B::Addr: core::fmt::Debug,
122 <B::Addr as Address>::Nonce: core::fmt::Debug,
123{
124 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
125 self.route.fmt(f)
126 }
127}
128
129/// One pure communication addressed to a concrete behavior protocol.
130///
131/// Protocol identity is not inferred from the payload. Consequently, two
132/// behaviors accepting the same address and message types still have distinct
133/// delivery types.
134///
135/// ```compile_fail
136/// use behavior::{Actions, Behavior, Delivery, MailAddr, Never, NoBirths, Recipient, User};
137///
138/// struct Queue;
139/// struct Worker;
140/// macro_rules! inert {
141/// ($actor:ty) => {
142/// impl Behavior for $actor {
143/// type Addr = MailAddr;
144/// type Msg = u8;
145/// type Event = User<MailAddr, u8>;
146/// type Sends = Vec<Never>;
147/// type Ph = Never;
148/// type Error = Never;
149/// type Birth = NoBirths;
150/// fn init(&mut self) -> behavior::BehaviorActed<Self> { Ok(Actions::cont()) }
151/// fn transition(&mut self, _: Self::Event) -> behavior::BehaviorActed<Self> {
152/// Ok(Actions::cont())
153/// }
154/// }
155/// };
156/// }
157/// inert!(Queue);
158/// inert!(Worker);
159///
160/// let worker = Recipient::<Worker>::global(MailAddr(1));
161/// let _: Delivery<Queue> = Delivery::new(worker, 7);
162/// ```
163///
164/// A destination also fixes its message and address namespaces:
165///
166/// ```compile_fail
167/// use behavior::{Actions, Address, Behavior, Delivery, MailAddr, Never, NoBirths, Recipient, User};
168/// #[derive(Clone, Copy, PartialEq, Eq)]
169/// struct OtherAddr(u64);
170/// impl Address for OtherAddr {
171/// type Nonce = u64;
172/// fn birth(self, nonce: u64) -> Self { Self(self.0 ^ nonce) }
173/// }
174/// struct Worker;
175/// impl Behavior for Worker {
176/// type Addr = MailAddr;
177/// type Msg = u8;
178/// type Event = User<MailAddr, u8>;
179/// type Sends = Vec<Never>;
180/// type Ph = Never;
181/// type Error = Never;
182/// type Birth = NoBirths;
183/// fn init(&mut self) -> behavior::BehaviorActed<Self> { Ok(Actions::cont()) }
184/// fn transition(&mut self, _: Self::Event) -> behavior::BehaviorActed<Self> { Ok(Actions::cont()) }
185/// }
186/// let _ = Recipient::<Worker>::global(OtherAddr(1));
187/// ```
188///
189/// ```compile_fail
190/// # use behavior::{Actions, Behavior, Delivery, MailAddr, Never, NoBirths, Recipient, User};
191/// # struct Worker;
192/// # impl Behavior for Worker {
193/// # type Addr = MailAddr;
194/// # type Msg = u8;
195/// # type Event = User<MailAddr, u8>;
196/// # type Sends = Vec<Never>;
197/// # type Ph = Never;
198/// # type Error = Never;
199/// # type Birth = NoBirths;
200/// # fn init(&mut self) -> behavior::BehaviorActed<Self> { Ok(Actions::cont()) }
201/// # fn transition(&mut self, _: Self::Event) -> behavior::BehaviorActed<Self> { Ok(Actions::cont()) }
202/// # }
203/// let worker = Recipient::<Worker>::global(MailAddr(1));
204/// let _ = Delivery::<Worker>::new(worker, "wrong payload");
205/// ```
206pub struct Delivery<B: Behavior> {
207 pub to: Recipient<B>,
208 pub message: B::Msg,
209}
210
211impl<B: Behavior> Delivery<B> {
212 #[must_use]
213 pub fn new(to: Recipient<B>, message: B::Msg) -> Self {
214 Self { to, message }
215 }
216}
217
218impl<B> Clone for Delivery<B>
219where
220 B: Behavior,
221 B::Msg: Clone,
222{
223 fn clone(&self) -> Self {
224 Self::new(self.to, self.message.clone())
225 }
226}
227
228impl<B> PartialEq for Delivery<B>
229where
230 B: Behavior,
231 B::Msg: PartialEq,
232{
233 fn eq(&self, other: &Self) -> bool {
234 self.to == other.to && self.message == other.message
235 }
236}
237
238impl<B> Eq for Delivery<B>
239where
240 B: Behavior,
241 B::Msg: Eq,
242{
243}