miden_protocol/account/storage/slot/
slot_name.rs1use alloc::string::{String, ToString};
2use alloc::sync::Arc;
3use core::fmt::Display;
4use core::str::FromStr;
5
6use crate::account::name_validation::{self, NameValidationError};
7use crate::account::storage::slot::StorageSlotId;
8use crate::errors::StorageSlotNameError;
9use crate::utils::serde::{
10 ByteReader,
11 ByteWriter,
12 Deserializable,
13 DeserializationError,
14 Serializable,
15};
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
45pub struct StorageSlotName {
46 name: Arc<str>,
47 id: StorageSlotId,
48}
49
50impl StorageSlotName {
51 pub(crate) const MIN_NUM_COMPONENTS: usize = name_validation::MIN_NUM_COMPONENTS;
56
57 pub(crate) const MAX_LENGTH: usize = name_validation::MAX_LENGTH;
59
60 pub fn new(name: impl Into<Arc<str>>) -> Result<Self, StorageSlotNameError> {
70 let name: Arc<str> = name.into();
71 Self::validate(&name)?;
72 let id = StorageSlotId::from_str(&name);
73 Ok(Self { name, id })
74 }
75
76 pub fn as_str(&self) -> &str {
81 &self.name
82 }
83
84 #[allow(clippy::len_without_is_empty)]
88 pub fn len(&self) -> u8 {
89 debug_assert!(self.name.len() <= Self::MAX_LENGTH);
91 self.name.len() as u8
92 }
93
94 pub fn id(&self) -> StorageSlotId {
96 self.id
97 }
98
99 const fn validate(name: &str) -> Result<(), StorageSlotNameError> {
104 match name_validation::validate(name) {
105 Ok(()) => Ok(()),
106 Err(NameValidationError::TooShort) => Err(StorageSlotNameError::TooShort),
107 Err(NameValidationError::TooLong) => Err(StorageSlotNameError::TooLong),
108 Err(NameValidationError::UnexpectedColon) => Err(StorageSlotNameError::UnexpectedColon),
109 Err(NameValidationError::UnexpectedUnderscore) => {
110 Err(StorageSlotNameError::UnexpectedUnderscore)
111 },
112 Err(NameValidationError::InvalidCharacter) => {
113 Err(StorageSlotNameError::InvalidCharacter)
114 },
115 }
116 }
117}
118
119impl Ord for StorageSlotName {
120 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
121 self.id().cmp(&other.id())
122 }
123}
124
125impl PartialOrd for StorageSlotName {
126 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
127 Some(self.cmp(other))
128 }
129}
130
131impl Display for StorageSlotName {
132 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
133 f.write_str(self.as_str())
134 }
135}
136
137impl FromStr for StorageSlotName {
138 type Err = StorageSlotNameError;
139
140 fn from_str(string: &str) -> Result<Self, Self::Err> {
141 StorageSlotName::new(string)
142 }
143}
144
145impl TryFrom<&str> for StorageSlotName {
146 type Error = StorageSlotNameError;
147
148 fn try_from(value: &str) -> Result<Self, Self::Error> {
149 value.parse()
150 }
151}
152
153impl TryFrom<String> for StorageSlotName {
154 type Error = StorageSlotNameError;
155
156 fn try_from(value: String) -> Result<Self, Self::Error> {
157 value.parse()
158 }
159}
160
161impl From<StorageSlotName> for String {
162 fn from(slot_name: StorageSlotName) -> Self {
163 slot_name.name.to_string()
164 }
165}
166
167impl Serializable for StorageSlotName {
168 fn write_into<W: ByteWriter>(&self, target: &mut W) {
169 target.write_u8(self.len());
170 target.write_many(self.as_str().as_bytes())
171 }
172
173 fn get_size_hint(&self) -> usize {
174 1 + self.as_str().len()
176 }
177}
178
179impl Deserializable for StorageSlotName {
180 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
181 let len = source.read_u8()?;
182 let name = source.read_many_iter(len as usize)?.collect::<Result<_, _>>()?;
183 String::from_utf8(name)
184 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
185 .and_then(|name| {
186 Self::new(name).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
187 })
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
196
197 #[test]
201 fn serde_slot_name() -> anyhow::Result<()> {
202 let slot_name = StorageSlotName::new("miden::faucet0::fungible_1::b4sic::metadata")?;
203 assert_eq!(slot_name, StorageSlotName::read_from_bytes(&slot_name.to_bytes())?);
204 Ok(())
205 }
206
207 #[test]
208 fn serde_max_length_slot_name() -> anyhow::Result<()> {
209 let slot_name = StorageSlotName::new(name_validation::tests::get_max_length_name())?;
210 assert_eq!(slot_name, StorageSlotName::read_from_bytes(&slot_name.to_bytes())?);
211 Ok(())
212 }
213}