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::{ecdsa_k256_keccak, rpo_falcon512};
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.register_word_type::<ecdsa_k256_keccak::PublicKey>();
30 registry
31});
32
33#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq)]
47#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
48#[cfg_attr(feature = "std", serde(transparent))]
49pub struct StorageValueName {
50 fully_qualified_name: String,
51}
52
53impl StorageValueName {
54 pub fn new(base: impl Into<String>) -> Result<Self, StorageValueNameError> {
69 let base: String = base.into();
70 for segment in base.split('.') {
71 Self::validate_segment(segment)?;
72 }
73 Ok(Self { fully_qualified_name: base })
74 }
75
76 pub(crate) fn empty() -> Self {
78 StorageValueName { fully_qualified_name: String::default() }
79 }
80
81 #[must_use]
83 pub fn with_suffix(self, suffix: &StorageValueName) -> StorageValueName {
84 let mut key = self;
85 if !suffix.as_str().is_empty() {
86 if !key.as_str().is_empty() {
87 key.fully_qualified_name.push('.');
88 }
89 key.fully_qualified_name.push_str(suffix.as_str());
90 }
91
92 key
93 }
94
95 pub fn as_str(&self) -> &str {
97 &self.fully_qualified_name
98 }
99
100 fn validate_segment(segment: &str) -> Result<(), StorageValueNameError> {
101 if segment.is_empty() {
102 return Err(StorageValueNameError::EmptySegment);
103 }
104 if let Some(offending_char) =
105 segment.chars().find(|&c| !(c.is_ascii_alphanumeric() || c == '_' || c == '-'))
106 {
107 return Err(StorageValueNameError::InvalidCharacter {
108 part: segment.to_string(),
109 character: offending_char,
110 });
111 }
112
113 Ok(())
114 }
115}
116
117impl Display for StorageValueName {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.write_str(self.as_str())
120 }
121}
122
123impl Serializable for StorageValueName {
124 fn write_into<W: ByteWriter>(&self, target: &mut W) {
125 target.write(&self.fully_qualified_name);
126 }
127}
128
129impl Deserializable for StorageValueName {
130 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
131 let key: String = source.read()?;
132 Ok(StorageValueName { fully_qualified_name: key })
133 }
134}
135
136#[derive(Debug, Error)]
137pub enum StorageValueNameError {
138 #[error("key segment is empty")]
139 EmptySegment,
140 #[error("key segment '{part}' contains invalid character '{character}'")]
141 InvalidCharacter { part: String, character: char },
142}
143
144#[derive(Debug, Error)]
152pub enum TemplateTypeError {
153 #[error("conversion error: {0}")]
154 ConversionError(String),
155 #[error("felt type ` {0}` not found in the type registry")]
156 FeltTypeNotFound(TemplateType),
157 #[error("invalid type name `{0}`: {1}")]
158 InvalidTypeName(String, String),
159 #[error("failed to parse input `{input}` as `{template_type}`")]
160 ParseError {
161 input: String,
162 template_type: TemplateType,
163 source: Box<dyn Error + Send + Sync + 'static>,
164 },
165 #[error("word type ` {0}` not found in the type registry")]
166 WordTypeNotFound(TemplateType),
167}
168
169impl TemplateTypeError {
170 pub fn parse(
172 input: impl Into<String>,
173 template_type: TemplateType,
174 source: impl Error + Send + Sync + 'static,
175 ) -> Self {
176 TemplateTypeError::ParseError {
177 input: input.into(),
178 template_type,
179 source: Box::new(source),
180 }
181 }
182}
183
184#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
189#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
190#[cfg_attr(feature = "std", serde(transparent))]
191pub struct TemplateType(String);
192
193impl TemplateType {
194 pub fn new(s: impl Into<String>) -> Result<Self, TemplateTypeError> {
206 let s = s.into();
207 if s.is_empty() {
208 return Err(TemplateTypeError::InvalidTypeName(
209 s.clone(),
210 "template type identifier is empty".to_string(),
211 ));
212 }
213 for segment in s.split("::") {
214 if segment.is_empty() {
215 return Err(TemplateTypeError::InvalidTypeName(
216 s.clone(),
217 "empty segment in template type identifier".to_string(),
218 ));
219 }
220 if !segment.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
221 return Err(TemplateTypeError::InvalidTypeName(
222 s.clone(),
223 format!("segment '{segment}' contains invalid characters"),
224 ));
225 }
226 }
227 Ok(Self(s))
228 }
229
230 pub fn native_felt() -> TemplateType {
232 TemplateType::new("felt").expect("type is well formed")
233 }
234
235 pub fn native_word() -> TemplateType {
237 TemplateType::new("word").expect("type is well formed")
238 }
239
240 pub fn storage_map() -> TemplateType {
242 TemplateType::new("map").expect("type is well formed")
243 }
244
245 pub fn as_str(&self) -> &str {
247 &self.0
248 }
249}
250
251impl Display for TemplateType {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 f.write_str(self.as_str())
254 }
255}
256
257impl Serializable for TemplateType {
258 fn write_into<W: ByteWriter>(&self, target: &mut W) {
259 target.write(self.0.clone())
260 }
261}
262
263impl Deserializable for TemplateType {
264 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
265 let id: String = source.read()?;
266
267 TemplateType::new(id).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
268 }
269}
270
271#[derive(Debug)]
280pub struct PlaceholderTypeRequirement {
281 pub r#type: TemplateType,
283 pub description: Option<String>,
285}
286
287pub trait TemplateFelt {
292 fn type_name() -> TemplateType;
294 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError>;
296}
297
298pub trait TemplateWord {
300 fn type_name() -> TemplateType;
302 fn parse_word(input: &str) -> Result<Word, TemplateTypeError>;
304}
305
306impl TemplateFelt for u8 {
310 fn type_name() -> TemplateType {
311 TemplateType::new("u8").expect("type is well formed")
312 }
313
314 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
315 let native: u8 = input
316 .parse()
317 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
318 Ok(Felt::from(native))
319 }
320}
321
322impl TemplateFelt for u16 {
323 fn type_name() -> TemplateType {
324 TemplateType::new("u16").expect("type is well formed")
325 }
326
327 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
328 let native: u16 = input
329 .parse()
330 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
331 Ok(Felt::from(native))
332 }
333}
334
335impl TemplateFelt for u32 {
336 fn type_name() -> TemplateType {
337 TemplateType::new("u32").expect("type is well formed")
338 }
339
340 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
341 let native: u32 = input
342 .parse()
343 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
344 Ok(Felt::from(native))
345 }
346}
347
348impl TemplateFelt for Felt {
349 fn type_name() -> TemplateType {
350 TemplateType::new("felt").expect("type is well formed")
351 }
352
353 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
354 let n = if let Some(hex) = input.strip_prefix("0x").or_else(|| input.strip_prefix("0X")) {
355 u64::from_str_radix(hex, 16)
356 } else {
357 input.parse::<u64>()
358 }
359 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
360 Felt::try_from(n).map_err(|_| TemplateTypeError::ConversionError(input.to_string()))
361 }
362}
363
364impl TemplateFelt for TokenSymbol {
365 fn type_name() -> TemplateType {
366 TemplateType::new("token_symbol").expect("type is well formed")
367 }
368 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
369 let token = TokenSymbol::new(input)
370 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
371 Ok(Felt::from(token))
372 }
373}
374
375#[derive(Debug, Error)]
379#[error("error parsing word: {0}")]
380struct WordParseError(String);
381
382fn pad_hex_string(input: &str) -> String {
387 if input.starts_with("0x") && input.len() < 66 {
388 let hex_part = &input[2..];
390 let padding = "0".repeat(64 - hex_part.len());
391 format!("0x{}{}", padding, hex_part)
392 } else {
393 input.to_string()
394 }
395}
396
397impl TemplateWord for Word {
398 fn type_name() -> TemplateType {
399 TemplateType::native_word()
400 }
401 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
402 let padded_input = pad_hex_string(input);
403
404 Word::try_from(padded_input.as_str()).map_err(|err| {
405 TemplateTypeError::parse(
406 input.to_string(), Self::type_name(),
408 WordParseError(err.to_string()),
409 )
410 })
411 }
412}
413
414impl TemplateWord for rpo_falcon512::PublicKey {
415 fn type_name() -> TemplateType {
416 TemplateType::new("auth::rpo_falcon512::pub_key").expect("type is well formed")
417 }
418 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
419 let padded_input = pad_hex_string(input);
420
421 Word::try_from(padded_input.as_str()).map_err(|err| {
422 TemplateTypeError::parse(
423 input.to_string(), Self::type_name(),
425 WordParseError(err.to_string()),
426 )
427 })
428 }
429}
430
431impl TemplateWord for ecdsa_k256_keccak::PublicKey {
432 fn type_name() -> TemplateType {
433 TemplateType::new("auth::ecdsa_k256_keccak::pub_key").expect("type is well formed")
434 }
435 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
436 let padded_input = pad_hex_string(input);
437
438 Word::try_from(padded_input.as_str()).map_err(|err| {
439 TemplateTypeError::parse(
440 input.to_string(),
441 Self::type_name(),
442 WordParseError(err.to_string()),
443 )
444 })
445 }
446}
447
448type TemplateFeltConverter = fn(&str) -> Result<Felt, TemplateTypeError>;
453
454type TemplateWordConverter = fn(&str) -> Result<Word, TemplateTypeError>;
456
457#[derive(Clone, Debug, Default)]
468pub struct TemplateRegistry {
469 felt: BTreeMap<TemplateType, TemplateFeltConverter>,
470 word: BTreeMap<TemplateType, TemplateWordConverter>,
471}
472
473impl TemplateRegistry {
474 pub fn new() -> Self {
479 Self { ..Default::default() }
480 }
481
482 pub fn register_felt_type<T: TemplateFelt + 'static>(&mut self) {
484 let key = T::type_name();
485 self.felt.insert(key, T::parse_felt);
486 }
487
488 pub fn register_word_type<T: TemplateWord + 'static>(&mut self) {
490 let key = T::type_name();
491 self.word.insert(key, T::parse_word);
492 }
493
494 pub fn try_parse_felt(
506 &self,
507 type_name: &TemplateType,
508 value: &str,
509 ) -> Result<Felt, TemplateTypeError> {
510 let converter = self
511 .felt
512 .get(type_name)
513 .ok_or(TemplateTypeError::FeltTypeNotFound(type_name.clone()))?;
514 converter(value)
515 }
516
517 pub fn try_parse_word(
529 &self,
530 type_name: &TemplateType,
531 value: &str,
532 ) -> Result<Word, TemplateTypeError> {
533 let converter = self
534 .word
535 .get(type_name)
536 .ok_or(TemplateTypeError::WordTypeNotFound(type_name.clone()))?;
537 converter(value)
538 }
539
540 pub fn contains_felt_type(&self, type_name: &TemplateType) -> bool {
542 self.felt.contains_key(type_name)
543 }
544
545 pub fn contains_word_type(&self, type_name: &TemplateType) -> bool {
547 self.word.contains_key(type_name)
548 }
549}