1use crate::error::MonikerError;
6use cm_types::{LongName, Name};
7use core::cmp::Ordering;
8use std::fmt;
9
10#[derive(Eq, PartialEq, Clone, Hash)]
15pub struct ChildName {
16 pub name: LongName,
17 pub collection: Option<Name>,
18}
19
20impl ChildName {
21 pub fn new(name: LongName, collection: Option<Name>) -> Self {
22 Self { name, collection }
23 }
24
25 pub fn try_new<S>(name: S, collection: Option<S>) -> Result<Self, MonikerError>
26 where
27 S: AsRef<str> + Into<String>,
28 {
29 let name = LongName::new(name)?;
30 let collection = match collection {
31 Some(coll) => {
32 let coll_name = Name::new(coll)?;
33 Some(coll_name)
34 }
35 None => None,
36 };
37 Ok(Self { name, collection })
38 }
39
40 pub fn parse<T: AsRef<str>>(rep: T) -> Result<Self, MonikerError> {
44 let rep = rep.as_ref();
45 let parts: Vec<&str> = rep.split(":").collect();
46 let (coll, name) = match parts.len() {
47 1 => (None, parts[0]),
48 2 => (Some(parts[0]), parts[1]),
49 _ => return Err(MonikerError::invalid_moniker(rep)),
50 };
51 ChildName::try_new(name, coll)
52 }
53
54 pub fn name(&self) -> &LongName {
55 &self.name
56 }
57
58 pub fn collection(&self) -> Option<&Name> {
59 self.collection.as_ref()
60 }
61}
62
63impl TryFrom<&str> for ChildName {
64 type Error = MonikerError;
65
66 fn try_from(rep: &str) -> Result<Self, MonikerError> {
67 ChildName::parse(rep)
68 }
69}
70
71impl From<cm_rust::ChildRef> for ChildName {
72 fn from(child_ref: cm_rust::ChildRef) -> Self {
73 Self { name: child_ref.name, collection: child_ref.collection }
74 }
75}
76
77impl From<ChildName> for cm_rust::ChildRef {
78 fn from(child_name: ChildName) -> Self {
79 Self { name: child_name.name, collection: child_name.collection }
80 }
81}
82
83impl Ord for ChildName {
84 fn cmp(&self, other: &Self) -> Ordering {
85 (&self.collection, &self.name).cmp(&(&other.collection, &other.name))
86 }
87}
88
89impl PartialOrd for ChildName {
90 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
91 Some(self.cmp(other))
92 }
93}
94
95impl fmt::Display for ChildName {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 if let Some(coll) = &self.collection {
98 write!(f, "{}:{}", coll, self.name)
99 } else {
100 write!(f, "{}", self.name)
101 }
102 }
103}
104
105impl fmt::Debug for ChildName {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 write!(f, "{self}")
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use cm_types::{MAX_LONG_NAME_LENGTH, MAX_NAME_LENGTH};
115
116 #[test]
117 fn child_monikers() {
118 let m = ChildName::try_new("test", None).unwrap();
119 assert_eq!("test", m.name().as_str());
120 assert_eq!(None, m.collection());
121 assert_eq!("test", format!("{}", m));
122 assert_eq!(m, ChildName::try_from("test").unwrap());
123
124 let m = ChildName::try_new("test", Some("coll")).unwrap();
125 assert_eq!("test", m.name().as_str());
126 assert_eq!(Some(&Name::new("coll").unwrap()), m.collection());
127 assert_eq!("coll:test", format!("{}", m));
128 assert_eq!(m, ChildName::try_from("coll:test").unwrap());
129
130 let max_coll_length_part = "f".repeat(MAX_NAME_LENGTH);
131 let max_name_length_part = "f".repeat(MAX_LONG_NAME_LENGTH);
132 let max_moniker_length = format!("{}:{}", max_coll_length_part, max_name_length_part);
133 let m = ChildName::parse(max_moniker_length).expect("valid moniker");
134 assert_eq!(&max_name_length_part, m.name().as_str());
135 assert_eq!(Some(&Name::new(max_coll_length_part).unwrap()), m.collection());
136
137 assert!(ChildName::parse("").is_err(), "cannot be empty");
138 assert!(ChildName::parse(":").is_err(), "cannot be empty with colon");
139 assert!(ChildName::parse("f:").is_err(), "second part cannot be empty with colon");
140 assert!(ChildName::parse(":f").is_err(), "first part cannot be empty with colon");
141 assert!(ChildName::parse("f:f:f").is_err(), "multiple colons not allowed");
142 assert!(ChildName::parse("@").is_err(), "invalid character in name");
143 assert!(ChildName::parse("@:f").is_err(), "invalid character in collection");
144 assert!(ChildName::parse("f:@").is_err(), "invalid character in name with collection");
145 assert!(
146 ChildName::parse(&format!("f:{}", "x".repeat(MAX_LONG_NAME_LENGTH + 1))).is_err(),
147 "name too long"
148 );
149 assert!(
150 ChildName::parse(&format!("{}:x", "f".repeat(MAX_NAME_LENGTH + 1))).is_err(),
151 "collection too long"
152 );
153 }
154
155 #[test]
156 fn child_moniker_compare() {
157 let a = ChildName::try_new("a", None).unwrap();
158 let aa = ChildName::try_new("a", Some("a")).unwrap();
159 let ab = ChildName::try_new("a", Some("b")).unwrap();
160 let ba = ChildName::try_new("b", Some("a")).unwrap();
161 let bb = ChildName::try_new("b", Some("b")).unwrap();
162 let aa_same = ChildName::try_new("a", Some("a")).unwrap();
163
164 assert_eq!(Ordering::Less, a.cmp(&aa));
165 assert_eq!(Ordering::Greater, aa.cmp(&a));
166 assert_eq!(Ordering::Less, a.cmp(&ab));
167 assert_eq!(Ordering::Greater, ab.cmp(&a));
168 assert_eq!(Ordering::Less, a.cmp(&ba));
169 assert_eq!(Ordering::Greater, ba.cmp(&a));
170 assert_eq!(Ordering::Less, a.cmp(&bb));
171 assert_eq!(Ordering::Greater, bb.cmp(&a));
172
173 assert_eq!(Ordering::Less, aa.cmp(&ab));
174 assert_eq!(Ordering::Greater, ab.cmp(&aa));
175 assert_eq!(Ordering::Less, aa.cmp(&ba));
176 assert_eq!(Ordering::Greater, ba.cmp(&aa));
177 assert_eq!(Ordering::Less, aa.cmp(&bb));
178 assert_eq!(Ordering::Greater, bb.cmp(&aa));
179 assert_eq!(Ordering::Equal, aa.cmp(&aa_same));
180 assert_eq!(Ordering::Equal, aa_same.cmp(&aa));
181
182 assert_eq!(Ordering::Greater, ab.cmp(&ba));
183 assert_eq!(Ordering::Less, ba.cmp(&ab));
184 assert_eq!(Ordering::Less, ab.cmp(&bb));
185 assert_eq!(Ordering::Greater, bb.cmp(&ab));
186
187 assert_eq!(Ordering::Less, ba.cmp(&bb));
188 assert_eq!(Ordering::Greater, bb.cmp(&ba));
189 }
190}