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