abstract_std/objects/
namespace.rs1use 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#[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 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 pub fn validate(&self) -> AbstractResult<()> {
31 validate_name(&self.0)?;
32 Ok(())
33 }
34 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}