1use crate::child_name::{BorrowedChildName, ChildName};
6use crate::error::MonikerError;
7use cm_rust::{FidlIntoNative, NativeIntoFidl};
8use core::cmp::{self, Ordering, PartialEq};
9use flyweights::FlyStr;
10use std::fmt;
11use std::hash::Hash;
12use std::iter::{IntoIterator, Iterator};
13
14#[derive(Eq, PartialEq, Clone, Hash)]
19pub struct Moniker {
20 rep: FlyStr,
21}
22
23impl Moniker {
24 pub fn new(path: &[ChildName]) -> Self {
25 if path.is_empty() {
26 Self::root()
27 } else {
28 Self { rep: path.iter().map(|s| s.as_ref()).collect::<Box<[&str]>>().join("/").into() }
29 }
30 }
31
32 fn new_unchecked<S: AsRef<str> + ?Sized>(rep: &S) -> Self {
33 Self { rep: rep.as_ref().into() }
34 }
35
36 pub fn new_from_borrowed(path: &[&BorrowedChildName]) -> Self {
37 if path.is_empty() {
38 Self::root()
39 } else {
40 Self {
41 rep: path.iter().map(|s| (*s).as_ref()).collect::<Box<[&str]>>().join("/").into(),
42 }
43 }
44 }
45
46 pub fn path(&self) -> Box<[&BorrowedChildName]> {
47 if self.is_root() {
48 Box::new([])
49 } else {
50 self.rep.split('/').map(|s| BorrowedChildName::new_unchecked(s)).collect()
51 }
52 }
53
54 pub fn parse<T: AsRef<str>>(path: &[T]) -> Result<Self, MonikerError> {
55 if path.is_empty() {
56 return Ok(Self::root());
57 }
58 let path = path
59 .iter()
60 .map(|n| {
61 let _ = BorrowedChildName::parse(n.as_ref())?;
62 Ok(n.as_ref())
63 })
64 .collect::<Result<Box<[&str]>, MonikerError>>()?;
65 Ok(Self::new_unchecked(&path.join("/")))
66 }
67
68 pub fn parse_str(input: &str) -> Result<Self, MonikerError> {
69 if input.is_empty() {
70 return Err(MonikerError::invalid_moniker(input));
71 }
72 if input == "/" || input == "." || input == "./" {
73 return Ok(Self::root());
74 }
75
76 let stripped = match input.strip_prefix("/") {
78 Some(s) => s,
79 None => match input.strip_prefix("./") {
80 Some(s) => s,
81 None => input,
82 },
83 };
84 stripped
85 .split('/')
86 .into_iter()
87 .map(|s| {
88 let _ = BorrowedChildName::parse(s)?;
89 Ok::<(), MonikerError>(())
90 })
91 .collect::<Result<(), _>>()?;
92 Ok(Self::new_unchecked(stripped))
93 }
94
95 pub fn concat(&self, other: &Moniker) -> Self {
97 let rep = if self.is_root() {
98 other.rep.clone()
99 } else if !other.is_root() {
100 format!("{}/{}", self.rep, other.rep).into()
101 } else {
102 self.rep.clone()
103 };
104 Self::new_unchecked(&rep)
105 }
106
107 pub fn has_prefix(&self, prefix: &Moniker) -> bool {
109 if prefix.is_root() {
110 return true;
111 } else if self.path().len() < prefix.path().len() {
112 return false;
113 }
114
115 let my_segments =
116 self.rep.split('/').map(|s| BorrowedChildName::new_unchecked(s)).collect::<Box<_>>();
117 let prefix_segments =
118 prefix.rep.split('/').map(|s| BorrowedChildName::new_unchecked(s)).collect::<Box<_>>();
119 my_segments[..prefix_segments.len()] == *prefix_segments
120 }
121
122 pub fn root() -> Self {
123 Self { rep: ".".into() }
124 }
125
126 pub fn leaf(&self) -> Option<&BorrowedChildName> {
128 if self.is_root() {
129 None
130 } else {
131 let back = match self.rep.rfind('/') {
132 Some(i) => &self.rep[i + 1..],
133 None => &self.rep,
134 };
135 Some(BorrowedChildName::new_unchecked(back))
136 }
137 }
138
139 pub fn is_root(&self) -> bool {
140 self.rep == "."
141 }
142
143 pub fn parent(&self) -> Option<Self> {
146 if self.is_root() {
147 None
148 } else {
149 match self.rep.rfind('/') {
150 Some(i) => Some(Self::new_unchecked(&self.rep[0..i])),
151 None => Some(Self::root()),
152 }
153 }
154 }
155
156 pub fn child(&self, child: ChildName) -> Self {
158 if self.is_root() {
159 Self::new_unchecked(&child)
160 } else {
161 Self::new_unchecked(&format!("{self}/{child}"))
162 }
163 }
164
165 pub fn split_leaf(&self) -> Option<(Self, &BorrowedChildName)> {
168 if self.is_root() {
169 None
170 } else {
171 let (rest, back) = match self.rep.rfind('/') {
172 Some(i) => {
173 let path = Self::new_unchecked(&self.rep[0..i]);
174 let back = BorrowedChildName::new_unchecked(&self.rep[i + 1..]);
175 (path, back)
176 }
177 None => (Self::root(), BorrowedChildName::new_unchecked(&self.rep)),
178 };
179 Some((rest, back))
180 }
181 }
182
183 pub fn strip_prefix(&self, prefix: &Moniker) -> Result<Self, MonikerError> {
185 if !self.has_prefix(prefix) {
186 return Err(MonikerError::MonikerDoesNotHavePrefix {
187 moniker: self.to_string(),
188 prefix: prefix.to_string(),
189 });
190 }
191
192 if prefix.is_root() {
193 Ok(self.clone())
194 } else if self == prefix {
195 Ok(Self::root())
196 } else {
197 assert!(!self.is_root(), "strip_prefix: caught by has_prefix above");
198 Ok(Self::new_unchecked(&self.rep[prefix.rep.len() + 1..]))
199 }
200 }
201}
202
203impl FidlIntoNative<Moniker> for String {
204 fn fidl_into_native(self) -> Moniker {
205 self.parse().unwrap()
208 }
209}
210
211impl NativeIntoFidl<String> for Moniker {
212 fn native_into_fidl(self) -> String {
213 self.to_string()
214 }
215}
216
217impl Default for Moniker {
218 fn default() -> Self {
219 Self::root()
220 }
221}
222
223impl TryFrom<&[&str]> for Moniker {
224 type Error = MonikerError;
225
226 fn try_from(rep: &[&str]) -> Result<Self, MonikerError> {
227 Self::parse(rep)
228 }
229}
230
231impl<const N: usize> TryFrom<[&str; N]> for Moniker {
232 type Error = MonikerError;
233
234 fn try_from(rep: [&str; N]) -> Result<Self, MonikerError> {
235 Self::parse(&rep)
236 }
237}
238
239impl TryFrom<&str> for Moniker {
240 type Error = MonikerError;
241
242 fn try_from(input: &str) -> Result<Self, MonikerError> {
243 Self::parse_str(input)
244 }
245}
246
247impl std::str::FromStr for Moniker {
248 type Err = MonikerError;
249 fn from_str(s: &str) -> Result<Self, Self::Err> {
250 Self::parse_str(s)
251 }
252}
253
254impl cmp::Ord for Moniker {
255 fn cmp(&self, other: &Self) -> cmp::Ordering {
256 let self_path = self.path();
257 let other_path = other.path();
258 let min_size = cmp::min(self_path.len(), other_path.len());
259 for i in 0..min_size {
260 if self_path[i] < other_path[i] {
261 return cmp::Ordering::Less;
262 } else if self_path[i] > other_path[i] {
263 return cmp::Ordering::Greater;
264 }
265 }
266 if self_path.len() > other_path.len() {
267 return cmp::Ordering::Greater;
268 } else if self_path.len() < other_path.len() {
269 return cmp::Ordering::Less;
270 }
271
272 cmp::Ordering::Equal
273 }
274}
275
276impl PartialOrd for Moniker {
277 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
278 Some(self.cmp(other))
279 }
280}
281
282impl fmt::Display for Moniker {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 write!(f, "{}", self.rep)
285 }
286}
287
288impl fmt::Debug for Moniker {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 write!(f, "{self}")
291 }
292}
293
294impl AsRef<str> for Moniker {
295 fn as_ref(&self) -> &str {
296 &self.rep
297 }
298}
299
300impl<'a> IntoIterator for &'a Moniker {
301 type Item = &'a str;
302 type IntoIter = std::str::Split<'a, char>;
303
304 fn into_iter(self) -> Self::IntoIter {
305 self.rep.split('/')
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use super::*;
312 use cm_types::BorrowedName;
313
314 #[test]
315 fn monikers() {
316 let root = Moniker::root();
317 assert_eq!(true, root.is_root());
318 assert_eq!(".", format!("{}", root));
319 assert_eq!(root, Moniker::new(&[]));
320 assert_eq!(root, Moniker::try_from([]).unwrap());
321
322 let m = Moniker::new(&[
323 ChildName::try_new("a", None).unwrap(),
324 ChildName::try_new("b", Some("coll")).unwrap(),
325 ]);
326 assert_eq!(false, m.is_root());
327 assert_eq!("a/coll:b", format!("{}", m));
328 assert_eq!(m, Moniker::try_from(["a", "coll:b"]).unwrap());
329 assert_eq!(
330 m.leaf().map(|m| m.collection()).flatten(),
331 Some(BorrowedName::new("coll").unwrap())
332 );
333 assert_eq!(m.leaf().map(|m| m.name().as_str()), Some("b"));
334 assert_eq!(m.leaf(), Some(BorrowedChildName::parse("coll:b").unwrap()));
335 }
336
337 #[test]
338 fn moniker_parent() {
339 let root = Moniker::root();
340 assert_eq!(true, root.is_root());
341 assert_eq!(None, root.parent());
342
343 let m = Moniker::new(&[
344 ChildName::try_new("a", None).unwrap(),
345 ChildName::try_new("b", None).unwrap(),
346 ]);
347 assert_eq!("a/b", format!("{}", m));
348 assert_eq!("a", format!("{}", m.parent().unwrap()));
349 assert_eq!(".", format!("{}", m.parent().unwrap().parent().unwrap()));
350 assert_eq!(None, m.parent().unwrap().parent().unwrap().parent());
351 assert_eq!(m.leaf(), Some(BorrowedChildName::parse("b").unwrap()));
352 }
353
354 #[test]
355 fn moniker_concat() {
356 let scope_root: Moniker = ["a:test1", "b:test2"].try_into().unwrap();
357
358 let relative: Moniker = ["c:test3", "d:test4"].try_into().unwrap();
359 let descendant = scope_root.concat(&relative);
360 assert_eq!("a:test1/b:test2/c:test3/d:test4", format!("{}", descendant));
361
362 let relative: Moniker = [].try_into().unwrap();
363 let descendant = scope_root.concat(&relative);
364 assert_eq!("a:test1/b:test2", format!("{}", descendant));
365 }
366
367 #[test]
368 fn moniker_parse_str() {
369 assert_eq!(Moniker::try_from("/foo").unwrap(), Moniker::try_from(["foo"]).unwrap());
370 assert_eq!(Moniker::try_from("./foo").unwrap(), Moniker::try_from(["foo"]).unwrap());
371 assert_eq!(Moniker::try_from("foo").unwrap(), Moniker::try_from(["foo"]).unwrap());
372 assert_eq!(Moniker::try_from("/").unwrap(), Moniker::try_from([]).unwrap());
373 assert_eq!(Moniker::try_from("./").unwrap(), Moniker::try_from([]).unwrap());
374
375 assert!(Moniker::try_from("//foo").is_err());
376 assert!(Moniker::try_from(".//foo").is_err());
377 assert!(Moniker::try_from("/./foo").is_err());
378 assert!(Moniker::try_from("../foo").is_err());
379 assert!(Moniker::try_from(".foo").is_err());
380 }
381
382 #[test]
383 fn moniker_has_prefix() {
384 assert!(Moniker::parse_str("a").unwrap().has_prefix(&Moniker::parse_str("a").unwrap()));
385 assert!(Moniker::parse_str("a/b").unwrap().has_prefix(&Moniker::parse_str("a").unwrap()));
386 assert!(
387 Moniker::parse_str("a/b:test").unwrap().has_prefix(&Moniker::parse_str("a").unwrap())
388 );
389 assert!(
390 Moniker::parse_str("a/b/c/d")
391 .unwrap()
392 .has_prefix(&Moniker::parse_str("a/b/c").unwrap())
393 );
394 assert!(
395 !Moniker::parse_str("a/b").unwrap().has_prefix(&Moniker::parse_str("a/b/c").unwrap())
396 );
397 assert!(
398 !Moniker::parse_str("a/c").unwrap().has_prefix(&Moniker::parse_str("a/b/c").unwrap())
399 );
400 assert!(!Moniker::root().has_prefix(&Moniker::parse_str("a").unwrap()));
401 assert!(
402 !Moniker::parse_str("a/b:test")
403 .unwrap()
404 .has_prefix(&Moniker::parse_str("a/b").unwrap())
405 );
406 }
407
408 #[test]
409 fn moniker_child() {
410 assert_eq!(
411 Moniker::root().child(ChildName::try_from("a").unwrap()),
412 Moniker::parse_str("a").unwrap()
413 );
414 assert_eq!(
415 Moniker::parse_str("a").unwrap().child(ChildName::try_from("b").unwrap()),
416 Moniker::parse_str("a/b").unwrap()
417 );
418 assert_eq!(
419 Moniker::parse_str("a:test").unwrap().child(ChildName::try_from("b").unwrap()),
420 Moniker::parse_str("a:test/b").unwrap()
421 );
422 assert_eq!(
423 Moniker::parse_str("a").unwrap().child(ChildName::try_from("b:test").unwrap()),
424 Moniker::parse_str("a/b:test").unwrap()
425 );
426 }
427
428 #[test]
429 fn moniker_split_leaf() {
430 assert_eq!(Moniker::root().split_leaf(), None);
431 assert_eq!(
432 Moniker::parse_str("a/b:test").unwrap().split_leaf(),
433 Some((Moniker::parse_str("a").unwrap(), BorrowedChildName::parse("b:test").unwrap()))
434 );
435 }
436
437 #[test]
438 fn moniker_strip_prefix() {
439 assert_eq!(
440 Moniker::parse_str("a").unwrap().strip_prefix(&Moniker::parse_str("a").unwrap()),
441 Ok(Moniker::root())
442 );
443 assert_eq!(
444 Moniker::parse_str("a/b").unwrap().strip_prefix(&Moniker::parse_str("a").unwrap()),
445 Ok(Moniker::parse_str("b").unwrap())
446 );
447 assert!(
448 Moniker::parse_str("a/b")
449 .unwrap()
450 .strip_prefix(&Moniker::parse_str("b").unwrap())
451 .is_err()
452 );
453 assert!(Moniker::root().strip_prefix(&Moniker::parse_str("b").unwrap()).is_err());
454 }
455}