1use 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}