ave_common/
namespace.rs

1//! # Namespace model.
2//!
3
4use 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/// This is the name space for a `Subject`.
15///
16#[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
31/// `Namespace` implementation.
32impl Namespace {
33    /// Create a new `Namespace`.
34    ///
35    /// # Returns
36    ///
37    /// A new `Namespace`.
38    ///
39    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    /// Add a name to the `Namespace`.
48    ///
49    /// # Arguments
50    ///
51    /// * `name` - The name to add.
52    ///
53    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    /// Root name of the `Namespace`.
62    ///
63    /// # Returns
64    ///
65    /// The root name of the `Namespace`.
66    ///
67    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    /// Returns the parent of the name space.
78    ///
79    /// # Returns
80    ///
81    /// Returns the parent of the name space.
82    ///
83    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    /// Returns the key of the name space.
94    ///
95    /// # Returns
96    ///
97    /// Returns the key of the path.
98    ///
99    pub fn key(&self) -> String {
100        self.0.last().cloned().unwrap_or_else(|| "".to_string())
101    }
102
103    /// Returns the levels size of the name space.
104    ///
105    /// # Returns
106    ///
107    /// Returns the levels size of the name space.
108    ///
109    pub fn level(&self) -> usize {
110        self.0.len()
111    }
112
113    /// Returns the name space at a specific level.
114    ///
115    /// # Arguments
116    ///
117    /// * `level` - The level to return the name space at.
118    ///
119    /// # Returns
120    ///
121    /// Returns the name space at a specific level.
122    ///
123    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    /// Returns if the name space is empty.
134    ///
135    /// # Returns
136    ///
137    /// Returns `true` if the name space is empty.
138    ///
139    pub fn is_empty(&self) -> bool {
140        self.0.is_empty()
141    }
142
143    /// Returns if the name space is an ancestor of another name space.
144    ///
145    /// # Arguments
146    ///
147    /// * `other` - The other name space to check.
148    ///
149    /// # Returns
150    ///
151    /// Returns `true` if the name space is an ancestor of the other name space.
152    ///
153    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    /// Returns if the name space is an ancestor or equal of another name space.
159    ///
160    /// # Arguments
161    ///
162    /// * `other` - The other name space to check.
163    ///
164    /// # Returns
165    ///
166    /// Returns `true` if the name space is an ancestor of the other name space.
167    ///
168    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    /// Returns if the name space is a descendant of another name space.
174    ///
175    /// # Arguments
176    ///
177    /// * `other` - The other name space to check.
178    ///
179    /// # Returns
180    ///
181    /// Returns `true` if the name space is a descendant of the other name space.
182    ///
183    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    /// Returns if the name space is a parent of another name space.
189    ///
190    /// # Arguments
191    ///
192    /// * `other` - The other name space to check.
193    ///
194    /// # Returns
195    ///
196    /// Returns `true` if the name space is a parent of the other name space.
197    ///
198    pub fn is_parent_of(&self, other: &Namespace) -> bool {
199        *self == other.parent()
200    }
201
202    /// Returns if the name space is a child of another name space.
203    ///
204    /// # Arguments
205    ///
206    /// * `other` - The other name space to check.
207    ///
208    /// # Returns
209    ///
210    /// Returns `true` if the name space is a child of the other name space.
211    ///
212    pub fn is_child_of(&self, other: &Namespace) -> bool {
213        self.parent() == *other
214    }
215
216    /// Returns if the name space is top level.
217    ///
218    /// # Returns
219    ///
220    /// Returns `true` if the name space is top level.
221    ///
222    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}