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