1use borsh::{BorshDeserialize, BorshSerialize};
5
6use serde::{Deserialize, Serialize};
7
8use std::cmp::Ordering;
9use std::fmt::{Error, Formatter};
10
11#[cfg(feature = "openapi")]
12use utoipa::ToSchema;
13
14#[derive(
17 Clone,
18 Hash,
19 Eq,
20 PartialEq,
21 PartialOrd,
22 Ord,
23 Serialize,
24 Deserialize,
25 BorshDeserialize,
26 BorshSerialize,
27)]
28#[cfg_attr(feature = "openapi", derive(ToSchema))]
29pub struct Namespace(Vec<String>);
30
31impl Namespace {
33 pub fn new() -> Self {
40 Namespace(Vec::new())
41 }
42
43 pub fn check(&self) -> bool {
44 !self.0.iter().any(|x| x.trim().is_empty() || x.len() > 100)
45 }
46
47 pub fn add(&mut self, name: &str) {
54 let name = name.trim();
55
56 if !name.is_empty() {
57 self.0.push(name.to_owned())
58 }
59 }
60
61 pub fn root(&self) -> Namespace {
68 if self.0.len() == 1 {
69 self.clone()
70 } else if !self.0.is_empty() {
71 Self(self.0.iter().take(1).cloned().collect())
72 } else {
73 Self(Vec::new())
74 }
75 }
76
77 pub fn parent(&self) -> Self {
84 if self.0.len() > 1 {
85 let mut tokens = self.0.clone();
86 tokens.truncate(tokens.len() - 1);
87 Self(tokens)
88 } else {
89 Self(Vec::new())
90 }
91 }
92
93 pub fn key(&self) -> String {
100 self.0.last().cloned().unwrap_or_else(|| "".to_string())
101 }
102
103 pub fn level(&self) -> usize {
110 self.0.len()
111 }
112
113 pub fn at_level(&self, level: usize) -> Self {
124 if level == 0 || level > self.level() {
125 self.clone()
126 } else {
127 let mut tokens = self.0.clone();
128 tokens.truncate(level);
129 Self(tokens)
130 }
131 }
132
133 pub fn is_empty(&self) -> bool {
140 self.0.is_empty()
141 }
142
143 pub fn is_ancestor_of(&self, other: &Namespace) -> bool {
154 let me = format!("{}.", self);
155 other.to_string().as_str().starts_with(me.as_str()) || self.is_empty()
156 }
157
158 pub fn is_ancestor_or_equal_of(&self, other: &Namespace) -> bool {
169 let me = format!("{}.", self);
170 other.to_string().as_str().starts_with(me.as_str()) || self.is_empty() || self == other
171 }
172
173 pub fn is_descendant_of(&self, other: &Namespace) -> bool {
184 let me = self.to_string();
185 me.as_str().starts_with(format!("{}.", other).as_str())
186 }
187
188 pub fn is_parent_of(&self, other: &Namespace) -> bool {
199 *self == other.parent()
200 }
201
202 pub fn is_child_of(&self, other: &Namespace) -> bool {
213 self.parent() == *other
214 }
215
216 pub fn is_top_level(&self) -> bool {
223 self.0.len() == 1
224 }
225}
226
227impl std::fmt::Display for Namespace {
228 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
229 match self.level().cmp(&1) {
230 Ordering::Less => write!(f, ""),
231 Ordering::Equal => write!(f, "{}", self.0[0]),
232 Ordering::Greater => write!(f, "{}", self.0.join(".")),
233 }
234 }
235}
236
237impl std::fmt::Debug for Namespace {
238 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
239 match self.level().cmp(&1) {
240 Ordering::Less => {
241 write!(f, "")
242 }
243 Ordering::Equal => write!(f, "{}", self.0[0]),
244 Ordering::Greater => write!(f, "{}", self.0.join(".")),
245 }
246 }
247}
248
249impl Default for Namespace {
250 fn default() -> Self {
251 Namespace::new()
252 }
253}
254
255impl From<&str> for Namespace {
256 fn from(str: &str) -> Self {
257 let tokens: Vec<String> = str
258 .split('.')
259 .filter(|x| !x.trim().is_empty())
260 .map(|s| s.trim().to_string())
261 .collect();
262
263 Namespace(tokens)
264 }
265}
266
267impl From<String> for Namespace {
268 fn from(str: String) -> Self {
269 Namespace::from(str.as_str())
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn test_namespace() {
279 let ns = Namespace::from("a.b.c");
280 assert_eq!(ns.level(), 3);
281 assert_eq!(ns.key(), "c");
282 assert_eq!(ns.root().to_string(), "a");
283 assert_eq!(ns.parent().to_string(), "a.b");
284 assert_eq!(ns.at_level(1).to_string(), "a");
285 assert_eq!(ns.at_level(2).to_string(), "a.b");
286 assert_eq!(ns.at_level(3).to_string(), "a.b.c");
287 assert!(!ns.is_empty());
288 assert!(ns.is_ancestor_of(&Namespace::from("a.b.c.d")));
289 assert!(ns.is_descendant_of(&Namespace::from("a.b")));
290 assert!(ns.is_parent_of(&Namespace::from("a.b.c.d")));
291 assert!(ns.is_child_of(&Namespace::from("a.b")));
292 assert!(!ns.is_top_level());
293 assert!(Namespace::new().is_ancestor_of(&Namespace::from("a.b.c.d")));
294 }
295}