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,
};
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StorageSlotSchema {
Value(ValueSlotSchema),
Map(MapSlotSchema),
}
impl StorageSlotSchema {
pub fn value(description: impl Into<String>, word: impl Into<WordSchema>) -> Self {
Self::Value(ValueSlotSchema::new(Some(description.into()), word.into()))
}
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(()),
}
}
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"
))),
}
}
}