1use 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#[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 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 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 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 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> {
93 self.path.split_last().map(|(_, parent)| Self::new(parent))
94 }
95
96 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 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 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 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}