1use crate::error::MonikerError;
6use cm_types::{BorrowedLongName, BorrowedName, LongName, Name};
7use flyweights::FlyStr;
8use std::borrow::Borrow;
9use std::cmp::Ordering;
10use std::fmt;
11use std::hash::{Hash, Hasher};
12use std::str::FromStr;
13
14#[derive(PartialEq, Eq, Clone)]
19pub struct ChildName {
20 rep: FlyStr,
21}
22
23impl ChildName {
24 pub fn new(name: LongName, collection: Option<Name>) -> Self {
25 match collection {
26 Some(collection) => Self { rep: format!("{collection}:{name}").into() },
27 None => Self { rep: format!("{name}").into() },
28 }
29 }
30
31 pub fn try_new<S>(name: S, collection: Option<S>) -> Result<Self, MonikerError>
32 where
33 S: AsRef<str> + Into<String>,
34 {
35 let name = name.as_ref();
36 let rep = match collection {
37 Some(collection) => Self { rep: format!("{}:{name}", collection.as_ref()).into() },
38 None => Self { rep: format!("{name}").into() },
39 };
40 Self::parse(rep)
41 }
42
43 pub fn parse<T: AsRef<str>>(rep: T) -> Result<Self, MonikerError> {
47 validate_child_name(rep.as_ref())?;
48 Ok(Self { rep: rep.as_ref().into() })
49 }
50
51 pub fn name(&self) -> &BorrowedLongName {
52 match self.rep.find(':') {
53 Some(i) => {
54 BorrowedLongName::new(&self.rep[i + 1..]).expect("name guaranteed to be valid")
55 }
56 None => BorrowedLongName::new(&self.rep).expect("name guaranteed to be valid"),
57 }
58 }
59
60 pub fn collection(&self) -> Option<&BorrowedName> {
61 self.rep
62 .find(':')
63 .map(|i| BorrowedName::new(&self.rep[0..i]).expect("collection guaranteed to be valid"))
64 }
65}
66
67impl TryFrom<&str> for ChildName {
68 type Error = MonikerError;
69
70 #[inline]
71 fn try_from(rep: &str) -> Result<Self, Self::Error> {
72 Self::parse(rep)
73 }
74}
75
76impl FromStr for ChildName {
77 type Err = MonikerError;
78
79 #[inline]
80 fn from_str(rep: &str) -> Result<Self, Self::Err> {
81 Self::parse(rep)
82 }
83}
84
85impl From<cm_rust::ChildRef> for ChildName {
86 fn from(child_ref: cm_rust::ChildRef) -> Self {
87 Self::new(child_ref.name, child_ref.collection)
88 }
89}
90
91impl From<&BorrowedChildName> for ChildName {
92 fn from(o: &BorrowedChildName) -> Self {
93 Self { rep: o.rep.into() }
94 }
95}
96
97impl From<ChildName> for cm_rust::ChildRef {
98 fn from(child_name: ChildName) -> Self {
99 Self { name: child_name.name().into(), collection: child_name.collection().map(Into::into) }
100 }
101}
102
103impl AsRef<str> for ChildName {
104 #[inline]
105 fn as_ref(&self) -> &str {
106 self.rep.as_str()
107 }
108}
109
110impl AsRef<BorrowedChildName> for ChildName {
111 #[inline]
112 fn as_ref(&self) -> &BorrowedChildName {
113 BorrowedChildName::new_unchecked(self)
114 }
115}
116
117impl Borrow<BorrowedChildName> for ChildName {
118 #[inline]
119 fn borrow(&self) -> &BorrowedChildName {
120 &BorrowedChildName::new_unchecked(self)
121 }
122}
123
124impl Borrow<str> for ChildName {
125 #[inline]
126 fn borrow(&self) -> &str {
127 &self.rep
128 }
129}
130
131impl std::ops::Deref for ChildName {
132 type Target = BorrowedChildName;
133
134 #[inline]
135 fn deref(&self) -> &BorrowedChildName {
136 BorrowedChildName::new_unchecked(self.rep.as_str())
137 }
138}
139
140impl PartialEq<&str> for ChildName {
141 #[inline]
142 fn eq(&self, o: &&str) -> bool {
143 &*self.rep == *o
144 }
145}
146
147impl PartialEq<String> for ChildName {
148 #[inline]
149 fn eq(&self, o: &String) -> bool {
150 &*self.rep == *o
151 }
152}
153
154impl PartialEq<BorrowedChildName> for ChildName {
155 #[inline]
156 fn eq(&self, o: &BorrowedChildName) -> bool {
157 &self.rep == &o.rep
158 }
159}
160
161impl Ord for ChildName {
162 #[inline]
163 fn cmp(&self, other: &Self) -> Ordering {
164 (self.collection(), self.name()).cmp(&(other.collection(), other.name()))
165 }
166}
167
168impl PartialOrd for ChildName {
169 #[inline]
170 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
171 Some(self.cmp(other))
172 }
173}
174
175impl Hash for ChildName {
176 #[inline]
177 fn hash<H: Hasher>(&self, state: &mut H) {
178 self.rep.as_str().hash(state)
179 }
180}
181
182impl fmt::Display for ChildName {
183 #[inline]
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 write!(f, "{}", self.rep)
186 }
187}
188
189impl fmt::Debug for ChildName {
190 #[inline]
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 write!(f, "{self}")
193 }
194}
195
196#[derive(Eq, PartialEq)]
199#[repr(transparent)]
200pub struct BorrowedChildName {
201 rep: str,
202}
203
204impl BorrowedChildName {
205 pub fn parse<S: AsRef<str> + ?Sized>(s: &S) -> Result<&Self, MonikerError> {
209 validate_child_name(s.as_ref())?;
210 Ok(Self::new_unchecked(s))
211 }
212
213 pub(crate) fn new_unchecked<S: AsRef<str> + ?Sized>(s: &S) -> &Self {
216 unsafe { &*(s.as_ref() as *const str as *const Self) }
217 }
218
219 pub fn name(&self) -> &BorrowedLongName {
220 match self.rep.find(':') {
221 Some(i) => {
222 BorrowedLongName::new(&self.rep[i + 1..]).expect("name guaranteed to be valid")
223 }
224 None => BorrowedLongName::new(&self.rep).expect("name guaranteed to be valid"),
225 }
226 }
227
228 pub fn collection(&self) -> Option<&BorrowedName> {
229 self.rep
230 .find(':')
231 .map(|i| BorrowedName::new(&self.rep[0..i]).expect("collection guaranteed to be valid"))
232 }
233}
234
235impl From<&BorrowedChildName> for cm_rust::ChildRef {
236 fn from(child_name: &BorrowedChildName) -> Self {
237 Self { name: child_name.name().into(), collection: child_name.collection().map(Into::into) }
238 }
239}
240
241impl AsRef<str> for BorrowedChildName {
242 #[inline]
243 fn as_ref(&self) -> &str {
244 &self.rep
245 }
246}
247
248impl Borrow<str> for BorrowedChildName {
249 #[inline]
250 fn borrow(&self) -> &str {
251 &self.rep
252 }
253}
254
255impl Borrow<str> for &BorrowedChildName {
256 #[inline]
257 fn borrow(&self) -> &str {
258 &self.rep
259 }
260}
261
262impl PartialEq<&str> for BorrowedChildName {
263 #[inline]
264 fn eq(&self, o: &&str) -> bool {
265 &self.rep == *o
266 }
267}
268
269impl PartialEq<String> for BorrowedChildName {
270 #[inline]
271 fn eq(&self, o: &String) -> bool {
272 &self.rep == &*o
273 }
274}
275
276impl PartialEq<ChildName> for BorrowedChildName {
277 #[inline]
278 fn eq(&self, o: &ChildName) -> bool {
279 self.rep == *o.rep
280 }
281}
282
283impl Ord for BorrowedChildName {
284 #[inline]
285 fn cmp(&self, other: &Self) -> Ordering {
286 (self.collection(), self.name()).cmp(&(other.collection(), other.name()))
287 }
288}
289
290impl PartialOrd for BorrowedChildName {
291 #[inline]
292 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
293 Some(self.cmp(other))
294 }
295}
296
297impl Hash for BorrowedChildName {
298 #[inline]
299 fn hash<H: Hasher>(&self, state: &mut H) {
300 self.rep.hash(state)
301 }
302}
303
304impl fmt::Display for BorrowedChildName {
305 #[inline]
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 write!(f, "{}", &self.rep)
308 }
309}
310
311impl fmt::Debug for BorrowedChildName {
312 #[inline]
313 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314 write!(f, "{self}")
315 }
316}
317
318fn validate_child_name(name: &str) -> Result<(), MonikerError> {
319 match name.find(':') {
320 Some(i) => {
321 let collection = &name[0..i];
322 let name = &name[i + 1..];
323 let _ = BorrowedName::new(collection)?;
324 let _ = BorrowedLongName::new(name)?;
325 }
326 None => {
327 let _ = BorrowedLongName::new(name)?;
328 }
329 }
330 Ok(())
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
336 use cm_types::{MAX_LONG_NAME_LENGTH, MAX_NAME_LENGTH};
337 use std::collections::HashSet;
338 use std::iter::repeat;
339
340 #[test]
341 fn child_monikers() {
342 let m = ChildName::try_new("test", None).unwrap();
343 assert_eq!("test", m.name().as_str());
344 assert_eq!(None, m.collection());
345 assert_eq!("test", format!("{}", m));
346 assert_eq!(m, ChildName::try_from("test").unwrap());
347
348 let m = ChildName::try_new("test", Some("coll")).unwrap();
349 assert_eq!("test", m.name().as_str());
350 assert_eq!(Some(BorrowedName::new("coll").unwrap()), m.collection());
351 assert_eq!("coll:test", format!("{}", m));
352 assert_eq!(m, ChildName::parse("coll:test").unwrap());
353
354 let max_coll_length_part = "f".repeat(MAX_NAME_LENGTH);
355 let max_name_length_part = "f".repeat(MAX_LONG_NAME_LENGTH);
356 let max_moniker_length = format!("{}:{}", max_coll_length_part, max_name_length_part);
357 let m = ChildName::parse(max_moniker_length).expect("valid moniker");
358 assert_eq!(&max_name_length_part, m.name().as_str());
359 assert_eq!(Some(BorrowedName::new(&max_coll_length_part).unwrap()), m.collection());
360
361 assert!(ChildName::parse("").is_err(), "cannot be empty");
362 assert!(ChildName::parse(":").is_err(), "cannot be empty with colon");
363 assert!(ChildName::parse("f:").is_err(), "second part cannot be empty with colon");
364 assert!(ChildName::parse(":f").is_err(), "first part cannot be empty with colon");
365 assert!(ChildName::parse("f:f:f").is_err(), "multiple colons not allowed");
366 assert!(ChildName::parse("@").is_err(), "invalid character in name");
367 assert!(ChildName::parse("@:f").is_err(), "invalid character in collection");
368 assert!(ChildName::parse("f:@").is_err(), "invalid character in name with collection");
369 assert!(
370 ChildName::parse(&format!("f:{}", "x".repeat(MAX_LONG_NAME_LENGTH + 1))).is_err(),
371 "name too long"
372 );
373 assert!(
374 ChildName::parse(&format!("{}:x", "f".repeat(MAX_NAME_LENGTH + 1))).is_err(),
375 "collection too long"
376 );
377 }
378
379 #[test]
380 fn child_moniker_compare() {
381 let a = ChildName::try_new("a", None).unwrap();
382 let aa = ChildName::try_new("a", Some("a")).unwrap();
383 let ab = ChildName::try_new("a", Some("b")).unwrap();
384 let ba = ChildName::try_new("b", Some("a")).unwrap();
385 let bb = ChildName::try_new("b", Some("b")).unwrap();
386 let aa_same = ChildName::try_new("a", Some("a")).unwrap();
387
388 assert_eq!(Ordering::Less, a.cmp(&aa));
389 assert_eq!(Ordering::Greater, aa.cmp(&a));
390 assert_eq!(Ordering::Less, a.cmp(&ab));
391 assert_eq!(Ordering::Greater, ab.cmp(&a));
392 assert_eq!(Ordering::Less, a.cmp(&ba));
393 assert_eq!(Ordering::Greater, ba.cmp(&a));
394 assert_eq!(Ordering::Less, a.cmp(&bb));
395 assert_eq!(Ordering::Greater, bb.cmp(&a));
396
397 assert_eq!(Ordering::Less, aa.cmp(&ab));
398 assert_eq!(Ordering::Greater, ab.cmp(&aa));
399 assert_eq!(Ordering::Less, aa.cmp(&ba));
400 assert_eq!(Ordering::Greater, ba.cmp(&aa));
401 assert_eq!(Ordering::Less, aa.cmp(&bb));
402 assert_eq!(Ordering::Greater, bb.cmp(&aa));
403 assert_eq!(Ordering::Equal, aa.cmp(&aa_same));
404 assert_eq!(Ordering::Equal, aa_same.cmp(&aa));
405
406 assert_eq!(Ordering::Greater, ab.cmp(&ba));
407 assert_eq!(Ordering::Less, ba.cmp(&ab));
408 assert_eq!(Ordering::Less, ab.cmp(&bb));
409 assert_eq!(Ordering::Greater, bb.cmp(&ab));
410
411 assert_eq!(Ordering::Less, ba.cmp(&bb));
412 assert_eq!(Ordering::Greater, bb.cmp(&ba));
413 }
414
415 #[test]
416 fn hash() {
417 {
418 let n1 = ChildName::new("a".parse().unwrap(), None);
419 let s_b = repeat("b").take(1024).collect::<String>();
420 let n2 = ChildName::new(s_b.parse().unwrap(), None);
421 let b1 = BorrowedChildName::parse("a").unwrap();
422 let b2 = BorrowedChildName::parse(&s_b).unwrap();
423
424 let mut set = HashSet::new();
425 set.insert(n1.clone());
426 assert!(set.contains(&n1));
427 assert!(set.contains(b1));
428 assert!(!set.contains(&n2));
429 assert!(!set.contains(b2));
430 set.insert(n2.clone());
431 assert!(set.contains(&n1));
432 assert!(set.contains(b1));
433 assert!(set.contains(&n2));
434 assert!(set.contains(b2));
435 }
436 {
437 let n1 = ChildName::new("a".parse().unwrap(), Some("c".parse().unwrap()));
438 let s_b = repeat("b").take(1024).collect::<String>();
439 let s_c = repeat("c").take(255).collect::<String>();
440 let n2 = ChildName::new(s_b.parse().unwrap(), Some(s_c.parse().unwrap()));
441 let b1 = BorrowedChildName::parse("c:a").unwrap();
442 let s_c_b = &format!("{s_c}:{s_b}");
443 let b2 = BorrowedChildName::parse(&s_c_b).unwrap();
444
445 let mut set = HashSet::new();
446 set.insert(n1.clone());
447 assert!(set.contains(&n1));
448 assert!(set.contains(b1));
449 assert!(!set.contains(&n2));
450 assert!(!set.contains(b2));
451 set.insert(n2.clone());
452 assert!(set.contains(&n1));
453 assert!(set.contains(b1));
454 assert!(set.contains(&n2));
455 assert!(set.contains(b2));
456 }
457 }
458}