Skip to main content

atomr_core/actor/
path.rs

1//! `ActorPath` — immutable, hierarchical, string-backed path.
2//! akka.net: `Actor/ActorPath.cs`.
3
4use std::fmt;
5
6use serde::{Deserialize, Serialize};
7
8use super::address::Address;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub struct PathElement(String);
12
13impl PathElement {
14    pub fn new(s: impl Into<String>) -> Self {
15        Self(s.into())
16    }
17
18    pub fn as_str(&self) -> &str {
19        &self.0
20    }
21}
22
23impl fmt::Display for PathElement {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        f.write_str(&self.0)
26    }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
30pub struct ActorPath {
31    pub address: Address,
32    pub elements: Vec<PathElement>,
33    pub uid: u64,
34}
35
36impl ActorPath {
37    pub fn root(address: Address) -> Self {
38        Self { address, elements: vec![], uid: 0 }
39    }
40
41    pub fn child(&self, name: impl Into<String>) -> Self {
42        let mut e = self.elements.clone();
43        e.push(PathElement::new(name));
44        Self { address: self.address.clone(), elements: e, uid: 0 }
45    }
46
47    pub fn with_uid(mut self, uid: u64) -> Self {
48        self.uid = uid;
49        self
50    }
51
52    pub fn name(&self) -> &str {
53        self.elements.last().map(|e| e.as_str()).unwrap_or("/")
54    }
55
56    pub fn parent(&self) -> Option<Self> {
57        if self.elements.is_empty() {
58            return None;
59        }
60        let mut e = self.elements.clone();
61        e.pop();
62        Some(Self { address: self.address.clone(), elements: e, uid: 0 })
63    }
64
65    pub fn depth(&self) -> usize {
66        self.elements.len()
67    }
68
69    pub fn to_string_without_address(&self) -> String {
70        let mut s = String::from("/");
71        for (i, el) in self.elements.iter().enumerate() {
72            if i > 0 {
73                s.push('/');
74            }
75            s.push_str(el.as_str());
76        }
77        s
78    }
79}
80
81impl fmt::Display for ActorPath {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        write!(f, "{}{}", self.address, self.to_string_without_address())
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn builds_child_path() {
93        let root = ActorPath::root(Address::local("S"));
94        let user = root.child("user");
95        let foo = user.child("foo");
96        assert_eq!(foo.name(), "foo");
97        assert_eq!(foo.depth(), 2);
98        assert_eq!(foo.to_string(), "akka://S/user/foo");
99    }
100
101    #[test]
102    fn parent_pops_element() {
103        let root = ActorPath::root(Address::local("S")).child("user").child("a");
104        assert_eq!(root.parent().unwrap().name(), "user");
105    }
106}