Skip to main content

atomr_core/actor/
path.rs

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