behavior/actor/
addressing.rs1use core::marker::PhantomData;
4
5use crate::Behavior;
6
7pub 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#[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
57pub 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 #[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 #[doc(hidden)]
100 pub fn is_child(self, expected: <B::Addr as Address>::Nonce) -> bool {
101 matches!(self.route, Route::Child(nonce) if nonce == expected)
102 }
103
104 const fn from_route(route: Route<B::Addr>) -> Self {
105 Self {
106 route,
107 protocol: PhantomData,
108 }
109 }
110}
111
112impl<B: Behavior> PartialEq for Recipient<B> {
113 fn eq(&self, other: &Self) -> bool {
114 self.route == other.route
115 }
116}
117
118impl<B: Behavior> Eq for Recipient<B> {}
119
120impl<B: Behavior> core::fmt::Debug for Recipient<B>
121where
122 B::Addr: core::fmt::Debug,
123 <B::Addr as Address>::Nonce: core::fmt::Debug,
124{
125 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
126 self.route.fmt(f)
127 }
128}
129
130pub struct Delivery<B: Behavior> {
208 pub to: Recipient<B>,
209 pub message: B::Msg,
210}
211
212impl<B: Behavior> Delivery<B> {
213 #[must_use]
214 pub fn new(to: Recipient<B>, message: B::Msg) -> Self {
215 Self { to, message }
216 }
217}
218
219impl<B> Clone for Delivery<B>
220where
221 B: Behavior,
222 B::Msg: Clone,
223{
224 fn clone(&self) -> Self {
225 Self::new(self.to, self.message.clone())
226 }
227}
228
229impl<B> PartialEq for Delivery<B>
230where
231 B: Behavior,
232 B::Msg: PartialEq,
233{
234 fn eq(&self, other: &Self) -> bool {
235 self.to == other.to && self.message == other.message
236 }
237}
238
239impl<B> Eq for Delivery<B>
240where
241 B: Behavior,
242 B::Msg: Eq,
243{
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249 use crate::{Actions, Never, NoBirths, User};
250
251 struct Inbox;
252
253 impl Behavior for Inbox {
254 type Addr = MailAddr;
255 type Msg = u8;
256 type Event = User<MailAddr, u8>;
257 type Sends = Vec<Never>;
258 type Ph = Never;
259 type Error = Never;
260 type Birth = NoBirths;
261
262 fn init(&mut self, _: crate::InitializationTurn) -> crate::BehaviorActed<Self> {
263 Ok(Actions::cont())
264 }
265
266 fn transition(
267 &mut self,
268 _: crate::ActiveTurn,
269 _: Self::Event,
270 ) -> crate::BehaviorActed<Self> {
271 Ok(Actions::cont())
272 }
273 }
274
275 #[test]
276 fn mail_address_conversion_preserves_nonzero_value() {
277 assert_eq!(u64::from(MailAddr(41)), 41);
278 }
279
280 #[test]
281 fn recipient_value_contract_distinguishes_routes() {
282 let global = Recipient::<Inbox>::global(MailAddr(7));
283 let same_global = Recipient::<Inbox>::global(MailAddr(7));
284 let other_global = Recipient::<Inbox>::global(MailAddr(8));
285 let child = Recipient::<Inbox>::child(3);
286 let other_child = Recipient::<Inbox>::child(4);
287
288 assert_eq!(global, same_global);
289 assert_ne!(global, other_global);
290 assert_ne!(global, child);
291 assert_ne!(child, other_child);
292 assert!(child.is_child(3));
293 assert!(!child.is_child(4));
294 assert!(!global.is_child(3));
295 assert_eq!(format!("{global:?}"), "Global(MailAddr(7))");
296 assert_eq!(format!("{child:?}"), "Child(3)");
297 }
298
299 #[test]
300 fn delivery_equality_requires_both_destination_and_message() {
301 let value = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 5);
302 let same = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 5);
303 let other_destination = Delivery::<Inbox>::new(Recipient::global(MailAddr(2)), 5);
304 let other_message = Delivery::<Inbox>::new(Recipient::global(MailAddr(1)), 6);
305 let both_different = Delivery::<Inbox>::new(Recipient::global(MailAddr(2)), 6);
306
307 assert!(value == same);
308 assert!(value != other_destination);
309 assert!(value != other_message);
310 assert!(value != both_different);
311 }
312}