abstract_core/objects/
namespace.rs

1use std::fmt::Display;
2
3use cosmwasm_std::StdResult;
4use cw_storage_plus::{Key, KeyDeserialize, Prefixer, PrimaryKey};
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8use super::module::validate_name;
9use crate::{AbstractError, AbstractResult};
10
11pub const ABSTRACT_NAMESPACE: &str = "abstract";
12
13/// Represents an Abstract namespace for modules
14#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, JsonSchema)]
15pub struct Namespace(String);
16
17impl Namespace {
18    pub fn new(namespace: &str) -> AbstractResult<Self> {
19        validate_name(namespace)?;
20        Ok(Self(namespace.to_owned()))
21    }
22    /// Create an instance without validating. Not for use in production code.
23    pub fn unchecked(namespace: impl ToString) -> Self {
24        Self(namespace.to_string())
25    }
26    pub fn as_str(&self) -> &str {
27        &self.0
28    }
29    /// Check that the namespace is valid
30    pub fn validate(&self) -> AbstractResult<()> {
31        validate_name(&self.0)?;
32        Ok(())
33    }
34    /// Get the namespace from a module's ID
35    /// Formatted as `namespace:module`
36    pub fn from_id(module_id: &str) -> AbstractResult<Self> {
37        let parts: Vec<&str> = module_id.split(':').collect();
38        if parts.len() != 2 {
39            return Err(AbstractError::FormattingError {
40                object: "module_id".to_string(),
41                expected: "namespace:module".to_string(),
42                actual: module_id.to_string(),
43            });
44        }
45        Self::new(parts[0])
46    }
47}
48
49impl TryFrom<&str> for Namespace {
50    type Error = AbstractError;
51
52    fn try_from(namespace: &str) -> AbstractResult<Self> {
53        Self::new(namespace)
54    }
55}
56
57impl TryFrom<String> for Namespace {
58    type Error = AbstractError;
59
60    fn try_from(namespace: String) -> AbstractResult<Self> {
61        Self::try_from(&namespace)
62    }
63}
64
65impl TryFrom<&String> for Namespace {
66    type Error = AbstractError;
67
68    fn try_from(namespace: &String) -> AbstractResult<Self> {
69        Self::new(namespace)
70    }
71}
72
73impl Display for Namespace {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        write!(f, "{}", self.0)
76    }
77}
78
79impl KeyDeserialize for &Namespace {
80    type Output = Namespace;
81
82    #[inline(always)]
83    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
84        Ok(Namespace(String::from_vec(value)?))
85    }
86}
87
88impl<'a> PrimaryKey<'a> for Namespace {
89    type Prefix = ();
90
91    type SubPrefix = ();
92
93    type Suffix = Self;
94
95    type SuperSuffix = Self;
96
97    fn key(&self) -> Vec<cw_storage_plus::Key> {
98        self.0.key()
99    }
100}
101
102impl<'a> Prefixer<'a> for Namespace {
103    fn prefix(&self) -> Vec<Key> {
104        self.0.prefix()
105    }
106}
107
108impl KeyDeserialize for Namespace {
109    type Output = Namespace;
110
111    #[inline(always)]
112    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
113        Ok(Namespace(String::from_vec(value)?))
114    }
115}
116
117#[cfg(test)]
118mod test {
119    use speculoos::prelude::*;
120
121    use super::*;
122
123    #[test]
124    fn test_namespace() {
125        let namespace = Namespace::new("test").unwrap();
126        assert_that!(namespace.as_str()).is_equal_to("test");
127    }
128
129    #[test]
130    fn test_from_string() {
131        let namespace = Namespace::try_from("test".to_string()).unwrap();
132        assert_that!(namespace.as_str()).is_equal_to("test");
133    }
134
135    #[test]
136    fn test_from_str() {
137        let namespace = Namespace::try_from("test").unwrap();
138        assert_that!(namespace.as_str()).is_equal_to("test");
139    }
140
141    #[test]
142    fn test_from_ref_string() {
143        let namespace = Namespace::try_from(&"test".to_string()).unwrap();
144        assert_that!(namespace.as_str()).is_equal_to("test");
145    }
146
147    #[test]
148    fn test_to_string() {
149        let namespace = Namespace::new("test").unwrap();
150        assert_that!(namespace.to_string()).is_equal_to("test".to_string());
151    }
152
153    #[test]
154    fn string_key_works() {
155        let k = &Namespace::new("test").unwrap();
156        let path = k.key();
157        assert_eq!(1, path.len());
158        assert_eq!(b"test", path[0].as_ref());
159
160        let joined = k.joined_key();
161        assert_eq!(joined, b"test")
162    }
163}