atomr_cluster/
reachability.rs1use std::collections::HashMap;
7
8use atomr_core::actor::Address;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[non_exhaustive]
13pub enum ReachabilityStatus {
14 Reachable,
15 Unreachable,
16 Terminated,
17}
18
19#[derive(Debug, Default, Clone, Serialize, Deserialize)]
20pub struct Reachability {
21 pub records: HashMap<(Address, Address), ReachabilityStatus>,
22}
23
24impl Reachability {
25 pub fn new() -> Self {
26 Self::default()
27 }
28
29 pub fn unreachable(&mut self, observer: Address, subject: Address) {
30 self.records.insert((observer, subject), ReachabilityStatus::Unreachable);
31 }
32
33 pub fn reachable(&mut self, observer: Address, subject: Address) {
34 self.records.insert((observer, subject), ReachabilityStatus::Reachable);
35 }
36
37 pub fn terminated(&mut self, observer: Address, subject: Address) {
38 self.records.insert((observer, subject), ReachabilityStatus::Terminated);
39 }
40
41 pub fn status(&self, subject: &Address) -> ReachabilityStatus {
42 let mut any_unreachable = false;
43 for ((_, s), st) in &self.records {
44 if s == subject {
45 match st {
46 ReachabilityStatus::Terminated => return ReachabilityStatus::Terminated,
47 ReachabilityStatus::Unreachable => any_unreachable = true,
48 ReachabilityStatus::Reachable => {}
49 }
50 }
51 }
52 if any_unreachable {
53 ReachabilityStatus::Unreachable
54 } else {
55 ReachabilityStatus::Reachable
56 }
57 }
58
59 pub fn is_reachable(&self, subject: &Address) -> bool {
60 matches!(self.status(subject), ReachabilityStatus::Reachable)
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn marks_unreachable_then_reachable() {
70 let mut r = Reachability::new();
71 let a = Address::local("A");
72 let b = Address::local("B");
73 r.unreachable(a.clone(), b.clone());
74 assert!(!r.is_reachable(&b));
75 r.reachable(a.clone(), b.clone());
76 assert!(r.is_reachable(&b));
77 }
78}