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::ChildName;
6use crate::error::MonikerError;
7use cm_rust::{FidlIntoNative, NativeIntoFidl};
8use core::cmp::{self, Ordering, PartialEq};
9use std::fmt;
10use std::hash::Hash;
11use std::sync::Arc;
12
13/// [Moniker] describes the identity of a component instance in terms of its path relative to the
14/// root of the component instance tree.
15///
16/// Display notation: ".", "name1", "name1/name2", ...
17#[derive(Eq, PartialEq, Clone, Hash, Default)]
18pub struct Moniker {
19    path: Arc<[ChildName]>,
20}
21
22impl Moniker {
23    pub fn new(path: &[ChildName]) -> Self {
24        Self { path: path.into() }
25    }
26
27    pub fn path(&self) -> &[ChildName] {
28        &self.path
29    }
30
31    pub fn parse<T: AsRef<str>>(path: &[T]) -> Result<Self, MonikerError> {
32        let path = path
33            .iter()
34            .map(ChildName::parse)
35            .collect::<Result<Arc<[ChildName]>, MonikerError>>()?;
36        Ok(Self { path })
37    }
38
39    pub fn parse_str(input: &str) -> Result<Self, MonikerError> {
40        if input.is_empty() {
41            return Err(MonikerError::invalid_moniker(input));
42        }
43        if input == "/" || input == "." || input == "./" {
44            return Ok(Self::root());
45        }
46
47        // Optionally strip a prefix of "/" or "./".
48        let stripped = match input.strip_prefix("/") {
49            Some(s) => s,
50            None => match input.strip_prefix("./") {
51                Some(s) => s,
52                None => input,
53            },
54        };
55        let path = stripped
56            .split('/')
57            .map(ChildName::parse)
58            .collect::<Result<Arc<[ChildName]>, MonikerError>>()?;
59        Ok(Self { path })
60    }
61
62    /// Concatenates other onto the end of this moniker.
63    pub fn concat(&self, other: &Moniker) -> Self {
64        let path = self.path.iter().chain(other.path.iter()).cloned().collect::<Arc<[ChildName]>>();
65        Self { path }
66    }
67
68    /// Indicates whether this moniker is prefixed by prefix.
69    pub fn has_prefix(&self, prefix: &Moniker) -> bool {
70        if self.path().len() < prefix.path().len() {
71            return false;
72        }
73
74        self.path[..prefix.path.len()] == *prefix.path
75    }
76
77    pub fn root() -> Self {
78        Self::new(&[])
79    }
80
81    /// Returns the last child of this moniker if this is not the root moniker.
82    pub fn leaf(&self) -> Option<&ChildName> {
83        self.path().last()
84    }
85
86    pub fn is_root(&self) -> bool {
87        self.path().is_empty()
88    }
89
90    /// Creates a new moniker with the last child removed. Returns `None` if this is the root
91    /// moniker.
92    pub fn parent(&self) -> Option<Self> {
93        self.path.split_last().map(|(_, parent)| Self::new(parent))
94    }
95
96    /// Creates a new Moniker with `child` added to the end of this moniker.
97    pub fn child(&self, child: ChildName) -> Self {
98        let path =
99            self.path.iter().cloned().chain(std::iter::once(child)).collect::<Arc<[ChildName]>>();
100        Self { path }
101    }
102
103    /// Splits off the last child of this moniker returning the parent as a moniker and the child.
104    /// Returns `None` if this is the root moniker.
105    pub fn split_leaf(&self) -> Option<(Self, ChildName)> {
106        self.path.split_last().map(|(child, parent_path)| (Self::new(parent_path), child.clone()))
107    }
108
109    /// Strips the moniker parts in prefix from the beginning of this moniker.
110    pub fn strip_prefix(&self, prefix: &Moniker) -> Result<Self, MonikerError> {
111        if !self.has_prefix(prefix) {
112            return Err(MonikerError::MonikerDoesNotHavePrefix {
113                moniker: self.to_string(),
114                prefix: prefix.to_string(),
115            });
116        }
117
118        let prefix_len = prefix.path().len();
119        Ok(Self::new(&self.path[prefix_len..]))
120    }
121}
122
123impl FidlIntoNative<Moniker> for String {
124    fn fidl_into_native(self) -> Moniker {
125        // This is used in routing::capability_source::CapabilitySource, and the FIDL version of
126        // this should only be generated in-process from already valid monikers.
127        self.parse().unwrap()
128    }
129}
130
131impl NativeIntoFidl<String> for Moniker {
132    fn native_into_fidl(self) -> String {
133        self.to_string()
134    }
135}
136
137impl TryFrom<&[&str]> for Moniker {
138    type Error = MonikerError;
139
140    fn try_from(rep: &[&str]) -> Result<Self, MonikerError> {
141        Self::parse(rep)
142    }
143}
144
145impl<const N: usize> TryFrom<[&str; N]> for Moniker {
146    type Error = MonikerError;
147
148    fn try_from(rep: [&str; N]) -> Result<Self, MonikerError> {
149        Self::parse(&rep)
150    }
151}
152
153impl TryFrom<&str> for Moniker {
154    type Error = MonikerError;
155
156    fn try_from(input: &str) -> Result<Self, MonikerError> {
157        Self::parse_str(input)
158    }
159}
160
161impl std::str::FromStr for Moniker {
162    type Err = MonikerError;
163    fn from_str(s: &str) -> Result<Self, Self::Err> {
164        Self::parse_str(s)
165    }
166}
167
168impl cmp::Ord for Moniker {
169    fn cmp(&self, other: &Self) -> cmp::Ordering {
170        let min_size = cmp::min(self.path().len(), other.path().len());
171        for i in 0..min_size {
172            if self.path()[i] < other.path()[i] {
173                return cmp::Ordering::Less;
174            } else if self.path()[i] > other.path()[i] {
175                return cmp::Ordering::Greater;
176            }
177        }
178        if self.path().len() > other.path().len() {
179            return cmp::Ordering::Greater;
180        } else if self.path().len() < other.path().len() {
181            return cmp::Ordering::Less;
182        }
183
184        cmp::Ordering::Equal
185    }
186}
187
188impl PartialOrd for Moniker {
189    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
190        Some(self.cmp(other))
191    }
192}
193
194impl fmt::Display for Moniker {
195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196        if self.path().is_empty() {
197            write!(f, ".")?;
198        } else {
199            write!(f, "{}", self.path()[0])?;
200            for segment in self.path()[1..].iter() {
201                write!(f, "/{}", segment)?;
202            }
203        }
204        Ok(())
205    }
206}
207
208impl fmt::Debug for Moniker {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        write!(f, "{self}")
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217    use cm_types::Name;
218
219    #[test]
220    fn monikers() {
221        let root = Moniker::root();
222        assert_eq!(true, root.is_root());
223        assert_eq!(".", format!("{}", root));
224        assert_eq!(root, Moniker::new(&[]));
225        assert_eq!(root, Moniker::try_from([]).unwrap());
226
227        let m = Moniker::new(&[
228            ChildName::try_new("a", None).unwrap(),
229            ChildName::try_new("b", Some("coll")).unwrap(),
230        ]);
231        assert_eq!(false, m.is_root());
232        assert_eq!("a/coll:b", format!("{}", m));
233        assert_eq!(m, Moniker::try_from(["a", "coll:b"]).unwrap());
234        assert_eq!(m.leaf().map(|m| m.collection()).flatten(), Some(&Name::new("coll").unwrap()));
235        assert_eq!(m.leaf().map(|m| m.name().as_str()), Some("b"));
236        assert_eq!(m.leaf(), Some(&ChildName::try_from("coll:b").unwrap()));
237    }
238
239    #[test]
240    fn moniker_parent() {
241        let root = Moniker::root();
242        assert_eq!(true, root.is_root());
243        assert_eq!(None, root.parent());
244
245        let m = Moniker::new(&[
246            ChildName::try_new("a", None).unwrap(),
247            ChildName::try_new("b", None).unwrap(),
248        ]);
249        assert_eq!("a/b", format!("{}", m));
250        assert_eq!("a", format!("{}", m.parent().unwrap()));
251        assert_eq!(".", format!("{}", m.parent().unwrap().parent().unwrap()));
252        assert_eq!(None, m.parent().unwrap().parent().unwrap().parent());
253        assert_eq!(m.leaf(), Some(&ChildName::try_from("b").unwrap()));
254    }
255
256    #[test]
257    fn moniker_concat() {
258        let scope_root: Moniker = ["a:test1", "b:test2"].try_into().unwrap();
259
260        let relative: Moniker = ["c:test3", "d:test4"].try_into().unwrap();
261        let descendant = scope_root.concat(&relative);
262        assert_eq!("a:test1/b:test2/c:test3/d:test4", format!("{}", descendant));
263
264        let relative: Moniker = [].try_into().unwrap();
265        let descendant = scope_root.concat(&relative);
266        assert_eq!("a:test1/b:test2", format!("{}", descendant));
267    }
268
269    #[test]
270    fn moniker_parse_str() {
271        assert_eq!(Moniker::try_from("/foo").unwrap(), Moniker::try_from(["foo"]).unwrap());
272        assert_eq!(Moniker::try_from("./foo").unwrap(), Moniker::try_from(["foo"]).unwrap());
273        assert_eq!(Moniker::try_from("foo").unwrap(), Moniker::try_from(["foo"]).unwrap());
274        assert_eq!(Moniker::try_from("/").unwrap(), Moniker::try_from([]).unwrap());
275        assert_eq!(Moniker::try_from("./").unwrap(), Moniker::try_from([]).unwrap());
276
277        assert!(Moniker::try_from("//foo").is_err());
278        assert!(Moniker::try_from(".//foo").is_err());
279        assert!(Moniker::try_from("/./foo").is_err());
280        assert!(Moniker::try_from("../foo").is_err());
281        assert!(Moniker::try_from(".foo").is_err());
282    }
283
284    #[test]
285    fn moniker_has_prefix() {
286        assert!(Moniker::parse_str("a").unwrap().has_prefix(&Moniker::parse_str("a").unwrap()));
287        assert!(Moniker::parse_str("a/b").unwrap().has_prefix(&Moniker::parse_str("a").unwrap()));
288        assert!(Moniker::parse_str("a/b:test")
289            .unwrap()
290            .has_prefix(&Moniker::parse_str("a").unwrap()));
291        assert!(Moniker::parse_str("a/b/c/d")
292            .unwrap()
293            .has_prefix(&Moniker::parse_str("a/b/c").unwrap()));
294        assert!(!Moniker::parse_str("a/b")
295            .unwrap()
296            .has_prefix(&Moniker::parse_str("a/b/c").unwrap()));
297        assert!(!Moniker::parse_str("a/c")
298            .unwrap()
299            .has_prefix(&Moniker::parse_str("a/b/c").unwrap()));
300        assert!(!Moniker::root().has_prefix(&Moniker::parse_str("a").unwrap()));
301        assert!(!Moniker::parse_str("a/b:test")
302            .unwrap()
303            .has_prefix(&Moniker::parse_str("a/b").unwrap()));
304    }
305
306    #[test]
307    fn moniker_child() {
308        assert_eq!(
309            Moniker::root().child(ChildName::try_from("a").unwrap()),
310            Moniker::parse_str("a").unwrap()
311        );
312        assert_eq!(
313            Moniker::parse_str("a").unwrap().child(ChildName::try_from("b").unwrap()),
314            Moniker::parse_str("a/b").unwrap()
315        );
316        assert_eq!(
317            Moniker::parse_str("a:test").unwrap().child(ChildName::try_from("b").unwrap()),
318            Moniker::parse_str("a:test/b").unwrap()
319        );
320        assert_eq!(
321            Moniker::parse_str("a").unwrap().child(ChildName::try_from("b:test").unwrap()),
322            Moniker::parse_str("a/b:test").unwrap()
323        );
324    }
325
326    #[test]
327    fn moniker_split_leaf() {
328        assert_eq!(Moniker::root().split_leaf(), None);
329        assert_eq!(
330            Moniker::parse_str("a/b:test").unwrap().split_leaf(),
331            Some((Moniker::parse_str("a").unwrap(), ChildName::try_from("b:test").unwrap()))
332        );
333    }
334
335    #[test]
336    fn moniker_strip_prefix() {
337        assert_eq!(
338            Moniker::parse_str("a").unwrap().strip_prefix(&Moniker::parse_str("a").unwrap()),
339            Ok(Moniker::root())
340        );
341        assert_eq!(
342            Moniker::parse_str("a/b").unwrap().strip_prefix(&Moniker::parse_str("a").unwrap()),
343            Ok(Moniker::parse_str("b").unwrap())
344        );
345        assert!(Moniker::parse_str("a/b")
346            .unwrap()
347            .strip_prefix(&Moniker::parse_str("b").unwrap())
348            .is_err());
349        assert!(Moniker::root().strip_prefix(&Moniker::parse_str("b").unwrap()).is_err());
350    }
351}