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