miden_objects/account/component/template/storage/
placeholder.rs1use alloc::{
2 boxed::Box,
3 collections::BTreeMap,
4 string::{String, ToString},
5};
6use core::{
7 error::Error,
8 fmt::{self, Display},
9};
10
11use miden_crypto::dsa::rpo_falcon512::{self};
12use thiserror::Error;
13use vm_core::{
14 Felt, Word,
15 utils::{ByteReader, ByteWriter, Deserializable, Serializable},
16};
17use vm_processor::DeserializationError;
18
19use crate::{
20 asset::TokenSymbol,
21 utils::{parse_hex_string_as_word, sync::LazyLock},
22};
23
24pub static TEMPLATE_REGISTRY: LazyLock<TemplateRegistry> = LazyLock::new(|| {
29 let mut registry = TemplateRegistry::new();
30 registry.register_felt_type::<u8>();
31 registry.register_felt_type::<u16>();
32 registry.register_felt_type::<u32>();
33 registry.register_felt_type::<Felt>();
34 registry.register_felt_type::<TokenSymbol>();
35 registry.register_word_type::<Word>();
36 registry.register_word_type::<rpo_falcon512::PublicKey>();
37 registry
38});
39
40#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq)]
54#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
55#[cfg_attr(feature = "std", serde(transparent))]
56pub struct StorageValueName {
57 fully_qualified_name: String,
58}
59
60impl StorageValueName {
61 pub fn new(base: impl Into<String>) -> Result<Self, StorageValueNameError> {
76 let base: String = base.into();
77 for segment in base.split('.') {
78 Self::validate_segment(segment)?;
79 }
80 Ok(Self { fully_qualified_name: base })
81 }
82
83 pub(crate) fn empty() -> Self {
85 StorageValueName { fully_qualified_name: String::default() }
86 }
87
88 #[must_use]
90 pub fn with_suffix(self, suffix: &StorageValueName) -> StorageValueName {
91 let mut key = self;
92 if !suffix.as_str().is_empty() {
93 if !key.as_str().is_empty() {
94 key.fully_qualified_name.push('.');
95 }
96 key.fully_qualified_name.push_str(suffix.as_str());
97 }
98
99 key
100 }
101
102 pub fn as_str(&self) -> &str {
104 &self.fully_qualified_name
105 }
106
107 fn validate_segment(segment: &str) -> Result<(), StorageValueNameError> {
108 if segment.is_empty() {
109 return Err(StorageValueNameError::EmptySegment);
110 }
111 if let Some(offending_char) =
112 segment.chars().find(|&c| !(c.is_ascii_alphanumeric() || c == '_' || c == '-'))
113 {
114 return Err(StorageValueNameError::InvalidCharacter {
115 part: segment.to_string(),
116 character: offending_char,
117 });
118 }
119
120 Ok(())
121 }
122}
123
124impl Display for StorageValueName {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 f.write_str(self.as_str())
127 }
128}
129
130impl Serializable for StorageValueName {
131 fn write_into<W: ByteWriter>(&self, target: &mut W) {
132 target.write(&self.fully_qualified_name);
133 }
134}
135
136impl Deserializable for StorageValueName {
137 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
138 let key: String = source.read()?;
139 Ok(StorageValueName { fully_qualified_name: key })
140 }
141}
142
143#[derive(Debug, Error)]
144pub enum StorageValueNameError {
145 #[error("key segment is empty")]
146 EmptySegment,
147 #[error("key segment '{part}' contains invalid character '{character}'")]
148 InvalidCharacter { part: String, character: char },
149}
150
151#[derive(Debug, Error)]
159pub enum TemplateTypeError {
160 #[error("conversion error: {0}")]
161 ConversionError(String),
162 #[error("felt type ` {0}` not found in the type registry")]
163 FeltTypeNotFound(TemplateType),
164 #[error("invalid type name `{0}`: {1}")]
165 InvalidTypeName(String, String),
166 #[error("failed to parse input `{input}` as `{template_type}`")]
167 ParseError {
168 input: String,
169 template_type: TemplateType,
170 source: Box<dyn Error + Send + Sync + 'static>,
171 },
172 #[error("word type ` {0}` not found in the type registry")]
173 WordTypeNotFound(TemplateType),
174}
175
176impl TemplateTypeError {
177 pub fn parse(
179 input: impl Into<String>,
180 template_type: TemplateType,
181 source: impl Error + Send + Sync + 'static,
182 ) -> Self {
183 TemplateTypeError::ParseError {
184 input: input.into(),
185 template_type,
186 source: Box::new(source),
187 }
188 }
189}
190
191#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
196#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
197#[cfg_attr(feature = "std", serde(transparent))]
198pub struct TemplateType(String);
199
200impl TemplateType {
201 pub fn new(s: impl Into<String>) -> Result<Self, TemplateTypeError> {
213 let s = s.into();
214 if s.is_empty() {
215 return Err(TemplateTypeError::InvalidTypeName(
216 s.clone(),
217 "template type identifier is empty".to_string(),
218 ));
219 }
220 for segment in s.split("::") {
221 if segment.is_empty() {
222 return Err(TemplateTypeError::InvalidTypeName(
223 s.clone(),
224 "empty segment in template type identifier".to_string(),
225 ));
226 }
227 if !segment.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
228 return Err(TemplateTypeError::InvalidTypeName(
229 s.clone(),
230 format!("segment '{}' contains invalid characters", segment),
231 ));
232 }
233 }
234 Ok(Self(s))
235 }
236
237 pub fn native_felt() -> TemplateType {
239 TemplateType::new("felt").expect("type is well formed")
240 }
241
242 pub fn native_word() -> TemplateType {
244 TemplateType::new("word").expect("type is well formed")
245 }
246
247 pub fn as_str(&self) -> &str {
249 &self.0
250 }
251}
252
253impl Display for TemplateType {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 f.write_str(self.as_str())
256 }
257}
258
259impl Serializable for TemplateType {
260 fn write_into<W: ByteWriter>(&self, target: &mut W) {
261 target.write(self.0.clone())
262 }
263}
264
265impl Deserializable for TemplateType {
266 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
267 let id: String = source.read()?;
268
269 TemplateType::new(id).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
270 }
271}
272
273#[derive(Debug)]
282pub struct PlaceholderTypeRequirement {
283 pub r#type: TemplateType,
285 pub description: Option<String>,
287}
288
289pub trait TemplateFelt {
294 fn type_name() -> TemplateType;
296 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError>;
298}
299
300pub trait TemplateWord {
302 fn type_name() -> TemplateType;
304 fn parse_word(input: &str) -> Result<Word, TemplateTypeError>;
306}
307
308impl TemplateFelt for u8 {
312 fn type_name() -> TemplateType {
313 TemplateType::new("u8").expect("type is well formed")
314 }
315
316 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
317 let native: u8 = input
318 .parse()
319 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
320 Ok(Felt::from(native))
321 }
322}
323
324impl TemplateFelt for u16 {
325 fn type_name() -> TemplateType {
326 TemplateType::new("u16").expect("type is well formed")
327 }
328
329 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
330 let native: u16 = input
331 .parse()
332 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
333 Ok(Felt::from(native))
334 }
335}
336
337impl TemplateFelt for u32 {
338 fn type_name() -> TemplateType {
339 TemplateType::new("u32").expect("type is well formed")
340 }
341
342 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
343 let native: u32 = input
344 .parse()
345 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
346 Ok(Felt::from(native))
347 }
348}
349
350impl TemplateFelt for Felt {
351 fn type_name() -> TemplateType {
352 TemplateType::new("felt").expect("type is well formed")
353 }
354
355 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
356 let n = if let Some(hex) = input.strip_prefix("0x").or_else(|| input.strip_prefix("0X")) {
357 u64::from_str_radix(hex, 16)
358 } else {
359 input.parse::<u64>()
360 }
361 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
362 Felt::try_from(n).map_err(|_| TemplateTypeError::ConversionError(input.to_string()))
363 }
364}
365
366impl TemplateFelt for TokenSymbol {
367 fn type_name() -> TemplateType {
368 TemplateType::new("token_symbol").expect("type is well formed")
369 }
370 fn parse_felt(input: &str) -> Result<Felt, TemplateTypeError> {
371 let token = TokenSymbol::new(input)
372 .map_err(|err| TemplateTypeError::parse(input.to_string(), Self::type_name(), err))?;
373 Ok(Felt::from(token))
374 }
375}
376
377#[derive(Debug, Error)]
381#[error("error parsing word: {0}")]
382struct WordParseError(String);
383
384impl TemplateWord for Word {
385 fn type_name() -> TemplateType {
386 TemplateType::native_word()
387 }
388 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
389 parse_hex_string_as_word(input).map_err(|err| {
390 TemplateTypeError::parse(
391 Self::type_name().as_str(),
392 Self::type_name(),
393 WordParseError(err.into()),
394 )
395 })
396 }
397}
398
399impl TemplateWord for rpo_falcon512::PublicKey {
400 fn type_name() -> TemplateType {
401 TemplateType::new("auth::rpo_falcon512::pub_key").expect("type is well formed")
402 }
403 fn parse_word(input: &str) -> Result<Word, TemplateTypeError> {
404 parse_hex_string_as_word(input).map_err(|err| {
405 TemplateTypeError::parse(
406 input.to_string(),
407 Self::type_name(),
408 WordParseError(err.into()),
409 )
410 })
411 }
412}
413
414type TemplateFeltConverter = fn(&str) -> Result<Felt, TemplateTypeError>;
419
420type TemplateWordConverter = fn(&str) -> Result<Word, TemplateTypeError>;
422
423#[derive(Clone, Debug, Default)]
434pub struct TemplateRegistry {
435 felt: BTreeMap<TemplateType, TemplateFeltConverter>,
436 word: BTreeMap<TemplateType, TemplateWordConverter>,
437}
438
439impl TemplateRegistry {
440 pub fn new() -> Self {
445 Self { ..Default::default() }
446 }
447
448 pub fn register_felt_type<T: TemplateFelt + 'static>(&mut self) {
450 let key = T::type_name();
451 self.felt.insert(key, T::parse_felt);
452 }
453
454 pub fn register_word_type<T: TemplateWord + 'static>(&mut self) {
456 let key = T::type_name();
457 self.word.insert(key, T::parse_word);
458 }
459
460 pub fn try_parse_felt(
472 &self,
473 type_name: &TemplateType,
474 value: &str,
475 ) -> Result<Felt, TemplateTypeError> {
476 let converter = self
477 .felt
478 .get(type_name)
479 .ok_or(TemplateTypeError::FeltTypeNotFound(type_name.clone()))?;
480 converter(value)
481 }
482
483 pub fn try_parse_word(
495 &self,
496 type_name: &TemplateType,
497 value: &str,
498 ) -> Result<Word, TemplateTypeError> {
499 let converter = self
500 .word
501 .get(type_name)
502 .ok_or(TemplateTypeError::WordTypeNotFound(type_name.clone()))?;
503 converter(value)
504 }
505
506 pub fn contains_felt_type(&self, type_name: &TemplateType) -> bool {
508 self.felt.contains_key(type_name)
509 }
510
511 pub fn contains_word_type(&self, type_name: &TemplateType) -> bool {
513 self.word.contains_key(type_name)
514 }
515}