miden_objects/account/component/template/storage/
placeholder.rs1use alloc::boxed::Box;
2use alloc::collections::BTreeMap;
3use alloc::string::{String, ToString};
4use core::error::Error;
5use core::fmt::{self, Display};
6
7use miden_core::utils::{ByteReader, ByteWriter, Deserializable, Serializable};
8use miden_core::{Felt, Word};
9use miden_crypto::dsa::rpo_falcon512::{self};
10use miden_processor::DeserializationError;
11use thiserror::Error;
12
13use crate::asset::TokenSymbol;
14use crate::utils::sync::LazyLock;
15
16pub static TEMPLATE_REGISTRY: LazyLock<TemplateRegistry> = LazyLock::new(|| {
21 let mut registry = TemplateRegistry::new();
22 registry.register_felt_type::<u8>();
23 registry.register_felt_type::<u16>();
24 registry.register_felt_type::<u32>();
25 registry.register_felt_type::<Felt>();
26 registry.register_felt_type::<TokenSymbol>();
27 registry.register_word_type::<Word>();
28 registry.register_word_type::<rpo_falcon512::PublicKey>();
29 registry
30});
31
32#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq)]
46#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
47#[cfg_attr(feature = "std", serde(transparent))]
48pub struct StorageValueName {
49 fully_qualified_name: String,
50}
51
52impl StorageValueName {
53 pub fn new(base: impl Into<String>) -> Result<Self, StorageValueNameError> {
68 let base: String = base.into();
69 for segment in base.split('.') {
70 Self::validate_segment(segment)?;
71 }
72 Ok(Self { fully_qualified_name: base })
73 }
74
75 pub(crate) fn empty() -> Self {
77 StorageValueName { fully_qualified_name: String::default() }
78 }
79
80 #[must_use]
82 pub fn with_suffix(self, suffix: &StorageValueName) -> StorageValueName {
83 let mut key = self;
84 if !suffix.as_str().is_empty() {
85 if !key.as_str().is_empty() {
86 key.fully_qualified_name.push('.');
87 }
88 key.fully_qualified_name.push_str(suffix.as_str());
89 }
90
91 key
92 }
93
94 pub fn as_str(&self) -> &str {
96 &self.fully_qualified_name
97 }
98
99 fn validate_segment(segment: &str) -> Result<(), StorageValueNameError> {
100 if segment.is_empty() {
101 return Err(StorageValueNameError::EmptySegment);
102 }
103 if let Some(offending_char) =
104 segment.chars().find(|&c| !(c.is_ascii_alphanumeric() || c == '_' || c == '-'))
105 {
106 return Err(StorageValueNameError::InvalidCharacter {
107 part: segment.to_string(),
108 character: offending_char,
109 });
110 }
111
112 Ok(())
113 }
114}
115
116impl Display for StorageValueName {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 f.write_str(self.as_str())
119 }
120}
121
122impl Serializable for StorageValueName {
123 fn write_into<W: ByteWriter>(&self, target: &mut W) {
124 target.write(&self.fully_qualified_name);
125 }
126}
127
128impl Deserializable for StorageValueName {
129 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
130 let key: String = source.read()?;
131 Ok(StorageValueName { fully_qualified_name: key })
132 }
133}
134
135#[derive(Debug, Error)]
136pub enum StorageValueNameError {
137 #[error("key segment is empty")]
138 EmptySegment,
139 #[error("key segment '{part}' contains invalid character '{character}'")]
140 InvalidCharacter { part: String, character: char },
141}
142
143#[derive(Debug, Error)]
151pub enum TemplateTypeError {
152 #[error("conversion error: {0}")]
153 ConversionError(String),
154 #[error("felt type ` {0}` not found in the type registry")]
155 FeltTypeNotFound(TemplateType),
156 #[error("invalid type name `{0}`: {1}")]
157 InvalidTypeName(String, String),
158 #[error("failed to parse input `{input}` as `{template_type}`")]
159 ParseError {
160 input: String,
161 template_type: TemplateType,
162 source: Box<dyn Error + Send + Sync + 'static>,
163 },
164 #[error("word type ` {0}` not found in the type registry")]
165 WordTypeNotFound(TemplateType),
166}
167
168impl TemplateTypeError {
169 pub fn parse(
171 input: impl Into<String>,
172 template_type: TemplateType,
173 source: impl Error + Send + Sync + 'static,
174 ) -> Self {
175 TemplateTypeError::ParseError {
176 input: input.into(),
177 template_type,
178 source: Box::new(source),
179 }
180 }
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
188#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
189#[cfg_attr(feature = "std", serde(transparent))]
190pub struct TemplateType(String);
191
192impl TemplateType {
193 pub fn new(s: impl Into<String>) -> Result<Self, TemplateTypeError> {
205 let s = s.into();
206 if s.is_empty() {
207 return Err(TemplateTypeError::InvalidTypeName(
208 s.clone(),
209 "template type identifier is empty".to_string(),
210 ));
211 }
212 for segment in s.split("::") {
213 if segment.is_empty() {
214 return Err(TemplateTypeError::InvalidTypeName(
215 s.clone(),
216 "empty segment in template type identifier".to_string(),
217 ));
218 }
219 if !segment.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
220 return Err(TemplateTypeError::InvalidTypeName(
221 s.clone(),
222 format!("segment '{segment}' contains invalid characters"),
223 ));
224 }
225 }
226 Ok(Self(s))
227 }
228
229 pub fn native_felt() -> TemplateType {
231 TemplateType::new("felt").expect("type is well formed")
232 }
233
234 pub fn native_word() -> TemplateType {
236 TemplateType::new("word").expect("type is well formed")
237 }
238
239 pub fn storage_map() -> TemplateType {
241 TemplateType::new("map").expect("type is well formed")
242 }
243
244 pub fn as_str(&self) -> &str {
246 &self.0
247 }
248}
249
250impl Display for TemplateType {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 f.write_str(self.as_str())
253 }
254}
255
256impl Serializable for TemplateType {
257 fn write_into<W: ByteWriter>(&self, target: &mut W) {
258 target.write(self.0.clone())
259 }
260}
261
262impl Deserializable for TemplateType {
263 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
264 let id: String = source.read()?;
265
266 TemplateType::new(id).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
267 }
268}
269
270#[derive(Debug)]
279pub struct PlaceholderTypeRequirement {
280 pub r#type: TemplateType,
282 pub description: Option<String>,
284}
285
286pub trait TemplateFelt {
291 fn type_name() -> TemplateType;
293 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError>;
295}
296
297pub trait TemplateWord {
299 fn type_name() -> TemplateType;
301 fn parse_word(input: &str) -> Result<Word, TemplateTypeError>;
303}
304
305impl TemplateFelt for u8 {
309 fn type_name() -> TemplateType {
310 TemplateType::new("u8").expect("type is well formed")
311 }
312
313 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
314 let native: u8 = input
315 .parse()
316 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
317 Ok(Felt::from(native))
318 }
319}
320
321impl TemplateFelt for u16 {
322 fn type_name() -> TemplateType {
323 TemplateType::new("u16").expect("type is well formed")
324 }
325
326 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
327 let native: u16 = input
328 .parse()
329 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
330 Ok(Felt::from(native))
331 }
332}
333
334impl TemplateFelt for u32 {
335 fn type_name() -> TemplateType {
336 TemplateType::new("u32").expect("type is well formed")
337 }
338
339 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
340 let native: u32 = input
341 .parse()
342 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
343 Ok(Felt::from(native))
344 }
345}
346
347impl TemplateFelt for Felt {
348 fn type_name() -> TemplateType {
349 TemplateType::new("felt").expect("type is well formed")
350 }
351
352 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
353 let n = if let Some(hex) = input.strip_prefix("0x").or_else(|| input.strip_prefix("0X")) {
354 u64::from_str_radix(hex, 16)
355 } else {
356 input.parse::<u64>()
357 }
358 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
359 Felt::try_from(n).map_err(|_| TemplateTypeError::ConversionError(input.to_string()))
360 }
361}
362
363impl TemplateFelt for TokenSymbol {
364 fn type_name() -> TemplateType {
365 TemplateType::new("token_symbol").expect("type is well formed")
366 }
367 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
368 let token = TokenSymbol::new(input)
369 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
370 Ok(Felt::from(token))
371 }
372}
373
374#[derive(Debug, Error)]
378#[error("error parsing word: {0}")]
379struct WordParseError(String);
380
381fn pad_hex_string(input: &str) -> String {
386 if input.starts_with("0x") && input.len() < 66 {
387 let hex_part = &input[2..];
389 let padding = "0".repeat(64 - hex_part.len());
390 format!("0x{}{}", padding, hex_part)
391 } else {
392 input.to_string()
393 }
394}
395
396impl TemplateWord for Word {
397 fn type_name() -> TemplateType {
398 TemplateType::native_word()
399 }
400 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
401 let padded_input = pad_hex_string(input);
402
403 Word::try_from(padded_input.as_str()).map_err(|err| {
404 TemplateTypeError::parse(
405 input.to_string(), Self::type_name(),
407 WordParseError(err.to_string()),
408 )
409 })
410 }
411}
412
413impl TemplateWord for rpo_falcon512::PublicKey {
414 fn type_name() -> TemplateType {
415 TemplateType::new("auth::rpo_falcon512::pub_key").expect("type is well formed")
416 }
417 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
418 let padded_input = pad_hex_string(input);
419
420 Word::try_from(padded_input.as_str()).map_err(|err| {
421 TemplateTypeError::parse(
422 input.to_string(), Self::type_name(),
424 WordParseError(err.to_string()),
425 )
426 })
427 }
428}
429
430type TemplateFeltConverter = fn(&str) -> Result<Felt, TemplateTypeError>;
435
436type TemplateWordConverter = fn(&str) -> Result<Word, TemplateTypeError>;
438
439#[derive(Clone, Debug, Default)]
450pub struct TemplateRegistry {
451 felt: BTreeMap<TemplateType, TemplateFeltConverter>,
452 word: BTreeMap<TemplateType, TemplateWordConverter>,
453}
454
455impl TemplateRegistry {
456 pub fn new() -> Self {
461 Self { ..Default::default() }
462 }
463
464 pub fn register_felt_type<T: TemplateFelt + 'static>(&mut self) {
466 let key = T::type_name();
467 self.felt.insert(key, T::parse_felt);
468 }
469
470 pub fn register_word_type<T: TemplateWord + 'static>(&mut self) {
472 let key = T::type_name();
473 self.word.insert(key, T::parse_word);
474 }
475
476 pub fn try_parse_felt(
488 &self,
489 type_name: &TemplateType,
490 value: &str,
491 ) -> Result<Felt, TemplateTypeError> {
492 let converter = self
493 .felt
494 .get(type_name)
495 .ok_or(TemplateTypeError::FeltTypeNotFound(type_name.clone()))?;
496 converter(value)
497 }
498
499 pub fn try_parse_word(
511 &self,
512 type_name: &TemplateType,
513 value: &str,
514 ) -> Result<Word, TemplateTypeError> {
515 let converter = self
516 .word
517 .get(type_name)
518 .ok_or(TemplateTypeError::WordTypeNotFound(type_name.clone()))?;
519 converter(value)
520 }
521
522 pub fn contains_felt_type(&self, type_name: &TemplateType) -> bool {
524 self.felt.contains_key(type_name)
525 }
526
527 pub fn contains_word_type(&self, type_name: &TemplateType) -> bool {
529 self.word.contains_key(type_name)
530 }
531}