1use serde::{Deserialize, Serialize};
4
5use std::cmp::Ordering;
6use std::fmt::{Error, Formatter};
7
8#[derive(
13 Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize,
14)]
15pub struct ActorPath(Vec<String>);
16
17impl ActorPath {
18 pub fn root(&self) -> Self {
20 if self.0.len() == 1 {
21 self.clone()
22 } else if !self.0.is_empty() {
23 Self(self.0.iter().take(1).cloned().collect())
24 } else {
25 Self(Vec::new())
26 }
27 }
28
29 pub fn parent(&self) -> Self {
31 if self.0.len() > 1 {
32 let mut tokens = self.0.clone();
33 tokens.truncate(tokens.len() - 1);
34 Self(tokens)
35 } else {
36 Self(Vec::new())
37 }
38 }
39
40 pub fn key(&self) -> String {
42 self.0.last().cloned().unwrap_or_else(|| "".to_string())
43 }
44
45 pub const fn level(&self) -> usize {
47 self.0.len()
48 }
49
50 pub fn at_level(&self, level: usize) -> Self {
52 if level < 1 || level >= self.level() {
53 self.clone()
54 } else if self.is_top_level() {
55 self.root()
56 } else if level == self.level() - 1 {
57 self.parent()
58 } else {
59 let mut tokens = self.0.clone();
60 tokens.truncate(level);
61 Self(tokens)
62 }
63 }
64
65 pub const fn is_empty(&self) -> bool {
67 self.0.is_empty()
68 }
69
70 pub fn is_ancestor_of(&self, other: &Self) -> bool {
72 self.0.len() < other.0.len() && other.0.starts_with(&self.0)
73 }
74
75 pub fn is_descendant_of(&self, other: &Self) -> bool {
77 other.0.len() < self.0.len() && self.0.starts_with(&other.0)
78 }
79
80 pub fn is_parent_of(&self, other: &Self) -> bool {
82 *self == other.parent()
83 }
84
85 pub fn is_child_of(&self, other: &Self) -> bool {
87 self.parent() == *other
88 }
89
90 pub const fn is_top_level(&self) -> bool {
92 self.0.len() == 1
93 }
94}
95
96impl From<&str> for ActorPath {
98 fn from(str: &str) -> Self {
99 let tokens: Vec<String> = str
100 .split('/')
101 .filter(|x| !x.trim().is_empty())
102 .map(|s| s.to_string())
103 .collect();
104 Self(tokens)
105 }
106}
107
108impl From<String> for ActorPath {
110 fn from(string: String) -> Self {
111 Self::from(string.as_str())
112 }
113}
114
115impl From<&String> for ActorPath {
116 fn from(string: &String) -> Self {
117 Self::from(string.as_str())
118 }
119}
120
121impl std::ops::Div<&str> for ActorPath {
123 type Output = Self;
124
125 fn div(self, rhs: &str) -> Self::Output {
126 let mut keys = self.0;
127 let mut tokens: Vec<String> = rhs
128 .split('/')
129 .filter(|x| !x.trim().is_empty())
130 .map(|s| s.to_string())
131 .collect();
132
133 keys.append(&mut tokens);
134 Self(keys)
135 }
136}
137
138impl std::fmt::Display for ActorPath {
139 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
140 match self.level().cmp(&1) {
141 Ordering::Less => write!(f, "/"),
142 Ordering::Equal => write!(f, "/{}", self.0[0]),
143 Ordering::Greater => write!(f, "/{}", self.0.join("/")),
144 }
145 }
146}
147
148impl std::fmt::Debug for ActorPath {
149 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
150 match self.level().cmp(&1) {
151 Ordering::Less => write!(f, "/"),
152 Ordering::Equal => write!(f, "/{}", self.0[0]),
153 Ordering::Greater => write!(f, "/{}", self.0.join("/")),
154 }
155 }
156}
157
158#[cfg(test)]
159mod tests {
160
161 use super::*;
162
163 #[test]
164 fn parse_empty_string() {
165 let path = ActorPath::from("");
166 assert_eq!(path.0, Vec::<String>::new());
167 }
168
169 #[test]
170 fn parse_single_root() {
171 let path = ActorPath::from("/acme");
172 println!("{:?}", path);
173 assert_eq!(path.0, vec!["acme"]);
174 }
175
176 #[test]
177 fn parse_two_deep() {
178 let path = ActorPath::from("/acme/building");
179 println!("{:?}", path);
180 assert_eq!(path.0, vec!["acme", "building"]);
181 }
182
183 #[test]
184 fn parse_three_deep() {
185 let path = ActorPath::from("/acme/building/room");
186 println!("{:?}", path);
187 assert_eq!(path.0, vec!["acme", "building", "room"]);
188 }
189
190 #[test]
191 fn parse_levels() {
192 let path = ActorPath::from("/acme/building/room/sensor");
193 println!("{:?}", path);
194 assert_eq!(path.level(), 4);
195 }
196
197 #[test]
198 fn test_get_key() {
199 let path = ActorPath::from("/acme/building/room/sensor");
200 println!("{:?}", path);
201 assert_eq!(path.key(), "sensor".to_string());
202 }
203
204 #[test]
205 fn parse_get_parent() {
206 let path = ActorPath::from("/acme/building/room/sensor").parent();
207 println!("{:?}", path);
208 assert_eq!(path.parent().0, vec!["acme", "building"]);
209 }
210
211 #[test]
212 fn parse_to_string() {
213 let path = ActorPath::from("/acme/building/room/sensor");
214 let string = path.to_string();
215 println!("{:?}", string);
216 assert_eq!(string, "/acme/building/room/sensor");
217 }
218
219 #[test]
220 fn parse_root_at_root() {
221 let path = ActorPath::from("/acme");
222 let string = path.root().to_string();
223 println!("{:?}", string);
224 assert_eq!(string, "/acme");
225 }
226
227 #[test]
228 fn parse_parent_at_root() {
229 let path = ActorPath::from("/acme");
230 let string = path.parent().to_string();
231 println!("{:?}", string);
232 assert_eq!(string, "/");
233 }
234
235 #[test]
236 fn parse_root_to_string() {
237 let path = ActorPath::from("/acme/building/room/sensor");
238 let string = path.root().to_string();
239 println!("{:?}", string);
240 assert_eq!(string, "/acme");
241 }
242
243 #[test]
244 fn test_if_empty() {
245 let path = ActorPath::from("/");
246 assert!(path.is_empty());
247 let not_empty = ActorPath::from("/not_empty");
248 assert!(!not_empty.is_empty());
249 }
250
251 #[test]
252 fn test_if_parent_child() {
253 let path = ActorPath::from("/acme/building/room/sensor");
254 let parent = path.parent();
255 assert!(parent.is_parent_of(&path));
256 assert!(path.is_child_of(&parent));
257 }
258
259 #[test]
260 fn test_if_descendant() {
261 let path = ActorPath::from("/acme/building/room/sensor");
262 let parent = path.parent();
263 assert!(path.is_descendant_of(&parent));
264 assert!(!path.is_descendant_of(&path));
265 }
266
267 #[test]
268 fn test_if_ancestor() {
269 let path = ActorPath::from("/acme/building/room/sensor");
270 let parent = path.parent();
271 assert!(parent.is_ancestor_of(&path));
272 assert!(!path.is_ancestor_of(&path));
273 }
274
275 #[test]
276 fn test_if_ancestor_descendant() {
277 let path = ActorPath::from("/acme/building/room/sensor");
278 let root = path.root();
279 assert!(root.is_ancestor_of(&path));
280 assert!(path.is_descendant_of(&root));
281 }
282
283 #[test]
284 fn test_root_slash_relationships() {
285 let root = ActorPath::from("/");
286 let child = ActorPath::from("/acme");
287 let grandchild = ActorPath::from("/acme/building");
288
289 assert!(root.is_ancestor_of(&child));
290 assert!(root.is_ancestor_of(&grandchild));
291 assert!(child.is_descendant_of(&root));
292 assert!(grandchild.is_descendant_of(&root));
293 assert!(!root.is_ancestor_of(&root));
294 assert!(!root.is_descendant_of(&root));
295 }
296
297 #[test]
298 fn test_if_root() {
299 let path = ActorPath::from("/acme/building/room/sensor");
300 let root = path.root();
301 println!("{:?}", path);
302 println!("{:?}", root);
303 assert!(root.is_top_level());
304 assert!(!path.is_top_level());
305 }
306
307 #[test]
308 fn test_at_level() {
309 let path = ActorPath::from("/acme/building/room/sensor");
310 assert_eq!(path.at_level(0), path);
311 assert_eq!(path.at_level(1), path.root());
312 assert_eq!(path.at_level(2), ActorPath::from("/acme/building"));
313 assert_eq!(path.at_level(3), path.parent());
314 assert_eq!(path.at_level(4), path);
315 assert_eq!(path.at_level(5), path);
316 }
317
318 #[test]
319 fn test_add_path() {
320 let path = ActorPath::from("/acme");
321 let child = path.clone() / "child";
322 println!("{}", &child);
323 assert!(path.is_parent_of(&child))
324 }
325}