moniker/
moniker.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// [Moniker] describes the identity of a component instance in terms of its path relative to the
15/// root of the component instance tree.
16///
17/// Display notation: ".", "name1", "name1/name2", ...
18#[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        // Optionally strip a prefix of "/" or "./".
84        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    /// Concatenates other onto the end of this moniker.
103    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    /// Indicates whether this moniker is prefixed by prefix.
115    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    /// Returns the last child of this moniker if this is not the root moniker.
134    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    /// Creates a new moniker with the last child removed. Returns `None` if this is the root
151    /// moniker.
152    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    /// Creates a new Moniker with `child` added to the end of this moniker.
164    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    /// Splits off the last child of this moniker returning the parent as a moniker and the child.
173    /// Returns `None` if this is the root moniker.
174    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    /// Strips the moniker parts in prefix from the beginning of this moniker.
191    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        // This is used in routing::capability_source::CapabilitySource, and the FIDL version of
213        // this should only be generated in-process from already valid monikers.
214        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}