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#[cfg(feature = "typescript")]
15use ts_rs::TS;
16
17#[derive(
20 Clone,
21 Hash,
22 Eq,
23 PartialEq,
24 PartialOrd,
25 Ord,
26 Serialize,
27 Deserialize,
28 BorshDeserialize,
29 BorshSerialize,
30)]
31#[cfg_attr(feature = "openapi", derive(ToSchema))]
32#[cfg_attr(feature = "typescript", derive(TS))]
33#[cfg_attr(feature = "typescript", ts(export))]
34pub struct Namespace(Vec<String>);
35
36impl Namespace {
38 pub fn new() -> Self {
45 Namespace(Vec::new())
46 }
47
48 pub fn check(&self) -> bool {
49 !self.0.iter().any(|x| x.trim().is_empty() || x.len() > 100)
50 }
51
52 pub fn add(&mut self, name: &str) {
59 let name = name.trim();
60
61 if !name.is_empty() {
62 self.0.push(name.to_owned())
63 }
64 }
65
66 pub fn root(&self) -> Namespace {
73 if self.0.len() == 1 {
74 self.clone()
75 } else if !self.0.is_empty() {
76 Self(self.0.iter().take(1).cloned().collect())
77 } else {
78 Self(Vec::new())
79 }
80 }
81
82 pub fn parent(&self) -> Self {
89 if self.0.len() > 1 {
90 let mut tokens = self.0.clone();
91 tokens.truncate(tokens.len() - 1);
92 Self(tokens)
93 } else {
94 Self(Vec::new())
95 }
96 }
97
98 pub fn key(&self) -> String {
105 self.0.last().cloned().unwrap_or_else(|| "".to_string())
106 }
107
108 pub fn level(&self) -> usize {
115 self.0.len()
116 }
117
118 pub fn at_level(&self, level: usize) -> Self {
129 if level == 0 || level > self.level() {
130 self.clone()
131 } else {
132 let mut tokens = self.0.clone();
133 tokens.truncate(level);
134 Self(tokens)
135 }
136 }
137
138 pub fn is_empty(&self) -> bool {
145 self.0.is_empty()
146 }
147
148 pub fn is_ancestor_of(&self, other: &Namespace) -> bool {
159 let me = format!("{}.", self);
160 other.to_string().as_str().starts_with(me.as_str()) || self.is_empty()
161 }
162
163 pub fn is_ancestor_or_equal_of(&self, other: &Namespace) -> bool {
174 let me = format!("{}.", self);
175 other.to_string().as_str().starts_with(me.as_str())
176 || self.is_empty()
177 || self == other
178 }
179
180 pub fn is_descendant_of(&self, other: &Namespace) -> bool {
191 let me = self.to_string();
192 me.as_str().starts_with(format!("{}.", other).as_str())
193 }
194
195 pub fn is_parent_of(&self, other: &Namespace) -> bool {
206 *self == other.parent()
207 }
208
209 pub fn is_child_of(&self, other: &Namespace) -> bool {
220 self.parent() == *other
221 }
222
223 pub fn is_top_level(&self) -> bool {
230 self.0.len() == 1
231 }
232}
233
234impl std::fmt::Display for Namespace {
235 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
236 match self.level().cmp(&1) {
237 Ordering::Less => write!(f, ""),
238 Ordering::Equal => write!(f, "{}", self.0[0]),
239 Ordering::Greater => write!(f, "{}", self.0.join(".")),
240 }
241 }
242}
243
244impl std::fmt::Debug for Namespace {
245 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
246 match self.level().cmp(&1) {
247 Ordering::Less => {
248 write!(f, "")
249 }
250 Ordering::Equal => write!(f, "{}", self.0[0]),
251 Ordering::Greater => write!(f, "{}", self.0.join(".")),
252 }
253 }
254}
255
256impl Default for Namespace {
257 fn default() -> Self {
258 Namespace::new()
259 }
260}
261
262impl From<&str> for Namespace {
263 fn from(str: &str) -> Self {
264 let tokens: Vec<String> = str
265 .split('.')
266 .filter(|x| !x.trim().is_empty())
267 .map(|s| s.trim().to_string())
268 .collect();
269
270 Namespace(tokens)
271 }
272}
273
274impl From<String> for Namespace {
275 fn from(str: String) -> Self {
276 Namespace::from(str.as_str())
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283
284 #[test]
285 fn test_namespace() {
286 let ns = Namespace::from("a.b.c");
287 assert_eq!(ns.level(), 3);
288 assert_eq!(ns.key(), "c");
289 assert_eq!(ns.root().to_string(), "a");
290 assert_eq!(ns.parent().to_string(), "a.b");
291 assert_eq!(ns.at_level(1).to_string(), "a");
292 assert_eq!(ns.at_level(2).to_string(), "a.b");
293 assert_eq!(ns.at_level(3).to_string(), "a.b.c");
294 assert!(!ns.is_empty());
295 assert!(ns.is_ancestor_of(&Namespace::from("a.b.c.d")));
296 assert!(ns.is_descendant_of(&Namespace::from("a.b")));
297 assert!(ns.is_parent_of(&Namespace::from("a.b.c.d")));
298 assert!(ns.is_child_of(&Namespace::from("a.b")));
299 assert!(!ns.is_top_level());
300 assert!(Namespace::new().is_ancestor_of(&Namespace::from("a.b.c.d")));
301 }
302}