use alloc::string::{String, ToString};
use miden_crypto::merkle::SimpleSmt;
use vm_core::{
utils::{Deserializable, Serializable},
Word, EMPTY_WORD,
};
use vm_processor::DeserializationError;
use super::{map::EMPTY_STORAGE_MAP_ROOT, Felt, STORAGE_TREE_DEPTH};
const MAX_VALUE_ARITY: u8 = u8::MAX - 1;
const MIN_ARRAY_DEPTH: u8 = 2;
const MAX_ARRAY_DEPTH: u8 = 64;
const DEFAULT_SLOT_TYPE: StorageSlotType = StorageSlotType::Value { value_arity: 0 };
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum StorageSlotType {
Value { value_arity: u8 },
Map { value_arity: u8 },
Array { depth: u8, value_arity: u8 },
}
impl StorageSlotType {
pub fn is_valid(&self) -> bool {
match self {
StorageSlotType::Value { value_arity } => *value_arity <= MAX_VALUE_ARITY,
StorageSlotType::Map { value_arity } => *value_arity <= MAX_VALUE_ARITY,
StorageSlotType::Array { depth, value_arity } => {
*value_arity < MAX_VALUE_ARITY
&& *depth >= MIN_ARRAY_DEPTH
&& *depth <= MAX_ARRAY_DEPTH
},
}
}
pub fn is_default(&self) -> bool {
match self {
StorageSlotType::Value { value_arity } => *value_arity == 0,
_ => false,
}
}
pub fn default_word(&self) -> Word {
match self {
StorageSlotType::Value { .. } => SimpleSmt::<STORAGE_TREE_DEPTH>::EMPTY_VALUE,
StorageSlotType::Map { .. } => EMPTY_STORAGE_MAP_ROOT,
StorageSlotType::Array { .. } => EMPTY_WORD,
}
}
}
impl Default for StorageSlotType {
fn default() -> Self {
DEFAULT_SLOT_TYPE
}
}
impl TryFrom<u16> for StorageSlotType {
type Error = String;
fn try_from(value: u16) -> Result<Self, Self::Error> {
let data_type = value as u8;
let value_arity = (value >> 8) as u8;
if value_arity > MAX_VALUE_ARITY {
return Err("Invalid value arity".to_string());
}
match data_type {
0 => Ok(StorageSlotType::Value { value_arity }),
1 => Ok(StorageSlotType::Map { value_arity }),
2..=MAX_ARRAY_DEPTH => Ok(StorageSlotType::Array { depth: data_type, value_arity }),
_ => Err("invalid slot data type".to_string()),
}
}
}
impl From<StorageSlotType> for u16 {
fn from(slot_type: StorageSlotType) -> Self {
match slot_type {
StorageSlotType::Value { value_arity } => (value_arity as u16) << 8,
StorageSlotType::Map { value_arity } => ((value_arity as u16) << 8) | 1_u16,
StorageSlotType::Array { depth, value_arity } => {
((value_arity as u16) << 8) | (depth as u16)
},
}
}
}
impl From<&StorageSlotType> for u16 {
fn from(value: &StorageSlotType) -> Self {
Self::from(*value)
}
}
impl From<StorageSlotType> for Felt {
fn from(slot_type: StorageSlotType) -> Self {
match slot_type {
StorageSlotType::Value { value_arity } => {
let type_value = (value_arity as u64) << 32;
Felt::new(type_value)
},
StorageSlotType::Map { value_arity } => {
let type_value = ((value_arity as u64) << 32) | 1_u64;
Felt::new(type_value)
},
StorageSlotType::Array { depth, value_arity } => {
let type_value = ((value_arity as u64) << 32) | (depth as u64);
Felt::new(type_value)
},
}
}
}
impl From<&StorageSlotType> for Felt {
fn from(value: &StorageSlotType) -> Self {
Self::from(*value)
}
}
impl Serializable for StorageSlotType {
fn write_into<W: vm_core::utils::ByteWriter>(&self, target: &mut W) {
target.write_u16(self.into());
}
}
impl Deserializable for StorageSlotType {
fn read_from<R: vm_core::utils::ByteReader>(
source: &mut R,
) -> Result<Self, vm_processor::DeserializationError> {
let encoded = source.read_u16()?;
StorageSlotType::try_from(encoded).map_err(DeserializationError::InvalidValue)
}
}