abstract_std/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 eq 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    const KEY_ELEMS: u16 = 1;
82
83    #[inline(always)]
84    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
85        Ok(Namespace(String::from_vec(value)?))
86    }
87}
88
89impl PrimaryKey<'_> for Namespace {
90    type Prefix = ();
91
92    type SubPrefix = ();
93
94    type Suffix = Self;
95
96    type SuperSuffix = Self;
97
98    fn key(&self) -> Vec<cw_storage_plus::Key> {
99        self.0.key()
100    }
101}
102
103impl Prefixer<'_> for Namespace {
104    fn prefix(&self) -> Vec<Key> {
105        self.0.prefix()
106    }
107}
108
109impl KeyDeserialize for Namespace {
110    type Output = Namespace;
111    const KEY_ELEMS: u16 = 1;
112
113    #[inline(always)]
114    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
115        Ok(Namespace(String::from_vec(value)?))
116    }
117}
118
119#[cfg(test)]
120mod test {
121    #![allow(clippy::needless_borrows_for_generic_args)]
122
123    use super::*;
124
125    #[coverage_helper::test]
126    fn test_namespace() {
127        let namespace = Namespace::new("test").unwrap();
128        assert_eq!(namespace.as_str(), "test");
129    }
130
131    #[coverage_helper::test]
132    fn test_from_string() {
133        let namespace = Namespace::try_from("test".to_string()).unwrap();
134        assert_eq!(namespace.as_str(), "test");
135    }
136
137    #[coverage_helper::test]
138    fn test_from_str() {
139        let namespace = Namespace::try_from("test").unwrap();
140        assert_eq!(namespace.as_str(), "test");
141    }
142
143    #[coverage_helper::test]
144    fn test_from_ref_string() {
145        let namespace = Namespace::try_from(&"test".to_string()).unwrap();
146        assert_eq!(namespace.as_str(), "test");
147    }
148
149    #[coverage_helper::test]
150    fn test_to_string() {
151        let namespace = Namespace::new("test").unwrap();
152        assert_eq!(namespace.to_string(), "test".to_string());
153    }
154
155    #[coverage_helper::test]
156    fn string_key_works() {
157        let k = &Namespace::new("test").unwrap();
158        let path = k.key();
159        assert_eq!(1, path.len());
160        assert_eq!(b"test", path[0].as_ref());
161
162        let joined = k.joined_key();
163        assert_eq!(joined, b"test")
164    }
165}