miden-protocol 0.14.5

Core components of the Miden protocol
Documentation
use alloc::collections::BTreeMap;
use alloc::string::String;

use super::super::type_registry::{SchemaRequirement, SchemaType};
use super::super::{InitStorageData, StorageValueName};
use super::{MapSlotSchema, ValueSlotSchema, WordSchema};
use crate::account::{StorageSlot, StorageSlotName};
use crate::errors::ComponentMetadataError;
use crate::utils::serde::{
    ByteReader,
    ByteWriter,
    Deserializable,
    DeserializationError,
    Serializable,
};

// STORAGE SLOT SCHEMA
// ================================================================================================

/// Describes the schema for a storage slot.
/// Can describe either a value slot, or a map slot.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StorageSlotSchema {
    Value(ValueSlotSchema),
    Map(MapSlotSchema),
}

impl StorageSlotSchema {
    /// Creates a value slot schema with the given description and word schema.
    ///
    /// Accepts anything convertible to [`WordSchema`]: a [`SchemaType`] for simple typed slots,
    /// a `[FeltSchema; 4]` for composite slots, or a [`WordSchema`] directly.
    pub fn value(description: impl Into<String>, word: impl Into<WordSchema>) -> Self {
        Self::Value(ValueSlotSchema::new(Some(description.into()), word.into()))
    }

    /// Creates a map slot schema with the given description and simple key/value types.
    pub fn map(
        description: impl Into<String>,
        key_type: SchemaType,
        value_type: SchemaType,
    ) -> Self {
        Self::Map(MapSlotSchema::new(
            Some(description.into()),
            None,
            WordSchema::new_simple(key_type),
            WordSchema::new_simple(value_type),
        ))
    }

    pub(super) fn collect_init_value_requirements(
        &self,
        slot_name: &StorageSlotName,
        requirements: &mut BTreeMap<StorageValueName, SchemaRequirement>,
    ) -> Result<(), ComponentMetadataError> {
        let slot_name = StorageValueName::from_slot_name(slot_name);
        match self {
            StorageSlotSchema::Value(slot) => {
                slot.collect_init_value_requirements(slot_name, requirements)
            },
            StorageSlotSchema::Map(_) => Ok(()),
        }
    }

    /// Builds a [`StorageSlot`] for the specified `slot_name` using the provided initialization
    /// data.
    pub fn try_build_storage_slot(
        &self,
        slot_name: &StorageSlotName,
        init_storage_data: &InitStorageData,
    ) -> Result<StorageSlot, ComponentMetadataError> {
        match self {
            StorageSlotSchema::Value(slot) => {
                let word = slot.try_build_word(init_storage_data, slot_name)?;
                Ok(StorageSlot::with_value(slot_name.clone(), word))
            },
            StorageSlotSchema::Map(slot) => {
                let storage_map = slot.try_build_map(init_storage_data, slot_name)?;
                Ok(StorageSlot::with_map(slot_name.clone(), storage_map))
            },
        }
    }

    pub(super) fn validate(&self) -> Result<(), ComponentMetadataError> {
        match self {
            StorageSlotSchema::Value(slot) => slot.validate()?,
            StorageSlotSchema::Map(slot) => slot.validate()?,
        }

        Ok(())
    }

    pub(super) fn write_into_with_optional_defaults<W: ByteWriter>(
        &self,
        target: &mut W,
        include_defaults: bool,
    ) {
        match self {
            StorageSlotSchema::Value(slot) => {
                target.write_u8(0u8);
                slot.write_into_with_optional_defaults(target, include_defaults);
            },
            StorageSlotSchema::Map(slot) => {
                target.write_u8(1u8);
                slot.write_into_with_optional_defaults(target, include_defaults);
            },
        }
    }
}

impl Serializable for StorageSlotSchema {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        self.write_into_with_optional_defaults(target, true);
    }
}

impl Deserializable for StorageSlotSchema {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let variant_tag = source.read_u8()?;
        match variant_tag {
            0 => Ok(StorageSlotSchema::Value(ValueSlotSchema::read_from(source)?)),
            1 => Ok(StorageSlotSchema::Map(MapSlotSchema::read_from(source)?)),
            _ => Err(DeserializationError::InvalidValue(format!(
                "unknown variant tag '{variant_tag}' for StorageSlotSchema"
            ))),
        }
    }
}