Skip to main content

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#[cfg(feature = "typescript")]
15use ts_rs::TS;
16
17/// This is the name space for a `Subject`.
18///
19#[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
36/// `Namespace` implementation.
37impl Namespace {
38    /// Create a new `Namespace`.
39    ///
40    /// # Returns
41    ///
42    /// A new `Namespace`.
43    ///
44    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    /// Add a name to the `Namespace`.
53    ///
54    /// # Arguments
55    ///
56    /// * `name` - The name to add.
57    ///
58    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    /// Root name of the `Namespace`.
67    ///
68    /// # Returns
69    ///
70    /// The root name of the `Namespace`.
71    ///
72    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    /// Returns the parent of the name space.
83    ///
84    /// # Returns
85    ///
86    /// Returns the parent of the name space.
87    ///
88    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    /// Returns the key of the name space.
99    ///
100    /// # Returns
101    ///
102    /// Returns the key of the path.
103    ///
104    pub fn key(&self) -> String {
105        self.0.last().cloned().unwrap_or_else(|| "".to_string())
106    }
107
108    /// Returns the levels size of the name space.
109    ///
110    /// # Returns
111    ///
112    /// Returns the levels size of the name space.
113    ///
114    pub fn level(&self) -> usize {
115        self.0.len()
116    }
117
118    /// Returns the name space at a specific level.
119    ///
120    /// # Arguments
121    ///
122    /// * `level` - The level to return the name space at.
123    ///
124    /// # Returns
125    ///
126    /// Returns the name space at a specific level.
127    ///
128    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    /// Returns if the name space is empty.
139    ///
140    /// # Returns
141    ///
142    /// Returns `true` if the name space is empty.
143    ///
144    pub fn is_empty(&self) -> bool {
145        self.0.is_empty()
146    }
147
148    /// Returns if the name space is an ancestor of another name space.
149    ///
150    /// # Arguments
151    ///
152    /// * `other` - The other name space to check.
153    ///
154    /// # Returns
155    ///
156    /// Returns `true` if the name space is an ancestor of the other name space.
157    ///
158    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    /// Returns if the name space is an ancestor or equal of another name space.
164    ///
165    /// # Arguments
166    ///
167    /// * `other` - The other name space to check.
168    ///
169    /// # Returns
170    ///
171    /// Returns `true` if the name space is an ancestor of the other name space.
172    ///
173    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    /// Returns if the name space is a descendant of another name space.
181    ///
182    /// # Arguments
183    ///
184    /// * `other` - The other name space to check.
185    ///
186    /// # Returns
187    ///
188    /// Returns `true` if the name space is a descendant of the other name space.
189    ///
190    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    /// Returns if the name space is a parent of another name space.
196    ///
197    /// # Arguments
198    ///
199    /// * `other` - The other name space to check.
200    ///
201    /// # Returns
202    ///
203    /// Returns `true` if the name space is a parent of the other name space.
204    ///
205    pub fn is_parent_of(&self, other: &Namespace) -> bool {
206        *self == other.parent()
207    }
208
209    /// Returns if the name space is a child of another name space.
210    ///
211    /// # Arguments
212    ///
213    /// * `other` - The other name space to check.
214    ///
215    /// # Returns
216    ///
217    /// Returns `true` if the name space is a child of the other name space.
218    ///
219    pub fn is_child_of(&self, other: &Namespace) -> bool {
220        self.parent() == *other
221    }
222
223    /// Returns if the name space is top level.
224    ///
225    /// # Returns
226    ///
227    /// Returns `true` if the name space is top level.
228    ///
229    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}