1use borsh::{BorshDeserialize, BorshSerialize};
4
5use serde::{Deserialize, Serialize};
6
7use std::cmp::Ordering;
8use std::fmt::{Error, Formatter};
9
10#[cfg(feature = "openapi")]
11use utoipa::ToSchema;
12
13#[cfg(feature = "typescript")]
14use ts_rs::TS;
15
16#[derive(
18 Clone,
19 Hash,
20 Eq,
21 PartialEq,
22 PartialOrd,
23 Ord,
24 Serialize,
25 Deserialize,
26 BorshDeserialize,
27 BorshSerialize,
28)]
29#[cfg_attr(feature = "openapi", derive(ToSchema))]
30#[cfg_attr(feature = "typescript", derive(TS))]
31#[cfg_attr(feature = "typescript", ts(export))]
32pub struct Namespace(Vec<String>);
33
34impl Namespace {
35 pub const fn new() -> Self {
37 Self(Vec::new())
38 }
39
40 pub fn check(&self) -> bool {
42 !self
43 .0
44 .iter()
45 .any(|x| x.trim().is_empty() || x.len() > 100 || x != x.trim())
46 }
47
48 pub fn add(&mut self, name: &str) {
50 let name = name.trim();
51
52 if !name.is_empty() {
53 self.0.push(name.to_owned())
54 }
55 }
56
57 pub fn root(&self) -> Self {
59 if self.0.len() == 1 {
60 self.clone()
61 } else if !self.0.is_empty() {
62 Self(self.0.iter().take(1).cloned().collect())
63 } else {
64 Self(Vec::new())
65 }
66 }
67
68 pub fn parent(&self) -> Self {
70 if self.0.len() > 1 {
71 let mut tokens = self.0.clone();
72 tokens.truncate(tokens.len() - 1);
73 Self(tokens)
74 } else {
75 Self(Vec::new())
76 }
77 }
78
79 pub fn key(&self) -> String {
81 self.0.last().cloned().unwrap_or_else(|| "".to_string())
82 }
83
84 pub const fn level(&self) -> usize {
86 self.0.len()
87 }
88
89 pub fn at_level(&self, level: usize) -> Self {
91 if level == 0 || level > self.level() {
92 self.clone()
93 } else {
94 let mut tokens = self.0.clone();
95 tokens.truncate(level);
96 Self(tokens)
97 }
98 }
99
100 pub const fn is_empty(&self) -> bool {
102 self.0.is_empty()
103 }
104
105 pub fn is_ancestor_of(&self, other: &Self) -> bool {
107 let me = format!("{}.", self);
108 other.to_string().as_str().starts_with(me.as_str()) || self.is_empty()
109 }
110
111 pub fn is_ancestor_or_equal_of(&self, other: &Self) -> bool {
113 let me = format!("{}.", self);
114 other.to_string().as_str().starts_with(me.as_str())
115 || self.is_empty()
116 || self == other
117 }
118
119 pub fn is_descendant_of(&self, other: &Self) -> bool {
121 let me = self.to_string();
122 me.as_str().starts_with(format!("{}.", other).as_str())
123 }
124
125 pub fn is_parent_of(&self, other: &Self) -> bool {
127 *self == other.parent()
128 }
129
130 pub fn is_child_of(&self, other: &Self) -> bool {
132 self.parent() == *other
133 }
134
135 pub const fn is_top_level(&self) -> bool {
137 self.0.len() == 1
138 }
139}
140
141impl std::fmt::Display for Namespace {
142 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
143 match self.level().cmp(&1) {
144 Ordering::Less => write!(f, ""),
145 Ordering::Equal => write!(f, "{}", self.0[0]),
146 Ordering::Greater => write!(f, "{}", self.0.join(".")),
147 }
148 }
149}
150
151impl std::fmt::Debug for Namespace {
152 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
153 match self.level().cmp(&1) {
154 Ordering::Less => {
155 write!(f, "")
156 }
157 Ordering::Equal => write!(f, "{}", self.0[0]),
158 Ordering::Greater => write!(f, "{}", self.0.join(".")),
159 }
160 }
161}
162
163impl Default for Namespace {
164 fn default() -> Self {
165 Self::new()
166 }
167}
168
169impl From<&str> for Namespace {
170 fn from(str: &str) -> Self {
171 let tokens: Vec<String> = str
172 .split('.')
173 .filter(|x| !x.trim().is_empty())
174 .map(|s| s.trim().to_string())
175 .collect();
176
177 Self(tokens)
178 }
179}
180
181impl From<String> for Namespace {
182 fn from(str: String) -> Self {
183 Self::from(str.as_str())
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_namespace() {
193 let ns = Namespace::from("a.b.c");
194 assert_eq!(ns.level(), 3);
195 assert_eq!(ns.key(), "c");
196 assert_eq!(ns.root().to_string(), "a");
197 assert_eq!(ns.parent().to_string(), "a.b");
198 assert_eq!(ns.at_level(1).to_string(), "a");
199 assert_eq!(ns.at_level(2).to_string(), "a.b");
200 assert_eq!(ns.at_level(3).to_string(), "a.b.c");
201 assert!(!ns.is_empty());
202 assert!(ns.is_ancestor_of(&Namespace::from("a.b.c.d")));
203 assert!(ns.is_descendant_of(&Namespace::from("a.b")));
204 assert!(ns.is_parent_of(&Namespace::from("a.b.c.d")));
205 assert!(ns.is_child_of(&Namespace::from("a.b")));
206 assert!(!ns.is_top_level());
207 assert!(Namespace::new().is_ancestor_of(&Namespace::from("a.b.c.d")));
208 }
209}