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_crypto::word::parse_hex_string_as_word;
11use miden_processor::DeserializationError;
12use thiserror::Error;
13
14use crate::asset::TokenSymbol;
15use crate::utils::sync::LazyLock;
16
17pub static TEMPLATE_REGISTRY: LazyLock<TemplateRegistry> = LazyLock::new(|| {
22 let mut registry = TemplateRegistry::new();
23 registry.register_felt_type::<u8>();
24 registry.register_felt_type::<u16>();
25 registry.register_felt_type::<u32>();
26 registry.register_felt_type::<Felt>();
27 registry.register_felt_type::<TokenSymbol>();
28 registry.register_word_type::<Word>();
29 registry.register_word_type::<rpo_falcon512::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 as_str(&self) -> &str {
242 &self.0
243 }
244}
245
246impl Display for TemplateType {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 f.write_str(self.as_str())
249 }
250}
251
252impl Serializable for TemplateType {
253 fn write_into<W: ByteWriter>(&self, target: &mut W) {
254 target.write(self.0.clone())
255 }
256}
257
258impl Deserializable for TemplateType {
259 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
260 let id: String = source.read()?;
261
262 TemplateType::new(id).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
263 }
264}
265
266#[derive(Debug)]
275pub struct PlaceholderTypeRequirement {
276 pub r#type: TemplateType,
278 pub description: Option<String>,
280}
281
282pub trait TemplateFelt {
287 fn type_name() -> TemplateType;
289 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError>;
291}
292
293pub trait TemplateWord {
295 fn type_name() -> TemplateType;
297 fn parse_word(input: &str) -> Result<Word, TemplateTypeError>;
299}
300
301impl TemplateFelt for u8 {
305 fn type_name() -> TemplateType {
306 TemplateType::new("u8").expect("type is well formed")
307 }
308
309 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
310 let native: u8 = input
311 .parse()
312 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
313 Ok(Felt::from(native))
314 }
315}
316
317impl TemplateFelt for u16 {
318 fn type_name() -> TemplateType {
319 TemplateType::new("u16").expect("type is well formed")
320 }
321
322 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
323 let native: u16 = input
324 .parse()
325 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
326 Ok(Felt::from(native))
327 }
328}
329
330impl TemplateFelt for u32 {
331 fn type_name() -> TemplateType {
332 TemplateType::new("u32").expect("type is well formed")
333 }
334
335 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
336 let native: u32 = input
337 .parse()
338 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
339 Ok(Felt::from(native))
340 }
341}
342
343impl TemplateFelt for Felt {
344 fn type_name() -> TemplateType {
345 TemplateType::new("felt").expect("type is well formed")
346 }
347
348 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
349 let n = if let Some(hex) = input.strip_prefix("0x").or_else(|| input.strip_prefix("0X")) {
350 u64::from_str_radix(hex, 16)
351 } else {
352 input.parse::<u64>()
353 }
354 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
355 Felt::try_from(n).map_err(|_| TemplateTypeError::ConversionError(input.to_string()))
356 }
357}
358
359impl TemplateFelt for TokenSymbol {
360 fn type_name() -> TemplateType {
361 TemplateType::new("token_symbol").expect("type is well formed")
362 }
363 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
364 let token = TokenSymbol::new(input)
365 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
366 Ok(Felt::from(token))
367 }
368}
369
370#[derive(Debug, Error)]
374#[error("error parsing word: {0}")]
375struct WordParseError(String);
376
377impl TemplateWord for Word {
378 fn type_name() -> TemplateType {
379 TemplateType::native_word()
380 }
381 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
382 parse_hex_string_as_word(input)
383 .map_err(|err| {
384 TemplateTypeError::parse(
385 Self::type_name().as_str(),
386 Self::type_name(),
387 WordParseError(err.into()),
388 )
389 })
390 .map(Word::from)
391 }
392}
393
394impl TemplateWord for rpo_falcon512::PublicKey {
395 fn type_name() -> TemplateType {
396 TemplateType::new("auth::rpo_falcon512::pub_key").expect("type is well formed")
397 }
398 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
399 parse_hex_string_as_word(input)
400 .map_err(|err| {
401 TemplateTypeError::parse(
402 input.to_string(),
403 Self::type_name(),
404 WordParseError(err.into()),
405 )
406 })
407 .map(Word::from)
408 }
409}
410
411type TemplateFeltConverter = fn(&str) -> Result<Felt, TemplateTypeError>;
416
417type TemplateWordConverter = fn(&str) -> Result<Word, TemplateTypeError>;
419
420#[derive(Clone, Debug, Default)]
431pub struct TemplateRegistry {
432 felt: BTreeMap<TemplateType, TemplateFeltConverter>,
433 word: BTreeMap<TemplateType, TemplateWordConverter>,
434}
435
436impl TemplateRegistry {
437 pub fn new() -> Self {
442 Self { ..Default::default() }
443 }
444
445 pub fn register_felt_type<T: TemplateFelt + 'static>(&mut self) {
447 let key = T::type_name();
448 self.felt.insert(key, T::parse_felt);
449 }
450
451 pub fn register_word_type<T: TemplateWord + 'static>(&mut self) {
453 let key = T::type_name();
454 self.word.insert(key, T::parse_word);
455 }
456
457 pub fn try_parse_felt(
469 &self,
470 type_name: &TemplateType,
471 value: &str,
472 ) -> Result<Felt, TemplateTypeError> {
473 let converter = self
474 .felt
475 .get(type_name)
476 .ok_or(TemplateTypeError::FeltTypeNotFound(type_name.clone()))?;
477 converter(value)
478 }
479
480 pub fn try_parse_word(
492 &self,
493 type_name: &TemplateType,
494 value: &str,
495 ) -> Result<Word, TemplateTypeError> {
496 let converter = self
497 .word
498 .get(type_name)
499 .ok_or(TemplateTypeError::WordTypeNotFound(type_name.clone()))?;
500 converter(value)
501 }
502
503 pub fn contains_felt_type(&self, type_name: &TemplateType) -> bool {
505 self.felt.contains_key(type_name)
506 }
507
508 pub fn contains_word_type(&self, type_name: &TemplateType) -> bool {
510 self.word.contains_key(type_name)
511 }
512}