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