use crate::account::{
StorageMapPatch,
StorageMapPatchEntries,
StoragePatchOperation,
StorageSlotContent,
StorageSlotName,
StorageSlotType,
StorageValuePatch,
};
use crate::errors::AccountPatchError;
use crate::utils::serde::{
ByteReader,
ByteWriter,
Deserializable,
DeserializationError,
Serializable,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StorageSlotPatch {
Value(StorageValuePatch),
Map(StorageMapPatch),
}
impl StorageSlotPatch {
const VALUE: u8 = 0;
const MAP: u8 = 1;
pub fn slot_type(&self) -> StorageSlotType {
match self {
StorageSlotPatch::Value(_) => StorageSlotType::Value,
StorageSlotPatch::Map(_) => StorageSlotType::Map,
}
}
pub fn patch_op(&self) -> StoragePatchOperation {
match self {
StorageSlotPatch::Value(value_patch) => value_patch.patch_op(),
StorageSlotPatch::Map(map_patch) => map_patch.patch_op(),
}
}
pub fn is_value(&self) -> bool {
matches!(self, Self::Value(_))
}
pub fn is_map(&self) -> bool {
matches!(self, Self::Map(_))
}
pub(super) fn merge(
&mut self,
slot_name: &StorageSlotName,
other: Self,
) -> Result<MergeOutcome, AccountPatchError> {
match (self, other) {
(StorageSlotPatch::Value(current), StorageSlotPatch::Value(new)) => {
current.merge(slot_name, new)
},
(StorageSlotPatch::Map(current), StorageSlotPatch::Map(new)) => {
current.merge(slot_name, new)
},
(..) => Err(AccountPatchError::StorageSlotUsedAsDifferentTypes(slot_name.clone())),
}
}
}
impl From<StorageSlotContent> for StorageSlotPatch {
fn from(content: StorageSlotContent) -> Self {
match content {
StorageSlotContent::Value(value) => {
StorageSlotPatch::Value(StorageValuePatch::Create { value })
},
StorageSlotContent::Map(storage_map) => {
StorageSlotPatch::Map(StorageMapPatch::Create {
entries: StorageMapPatchEntries::from(storage_map),
})
},
}
}
}
impl Serializable for StorageSlotPatch {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
match self {
StorageSlotPatch::Value(value_patch) => {
target.write_u8(Self::VALUE);
target.write(value_patch);
},
StorageSlotPatch::Map(map_patch) => {
target.write_u8(Self::MAP);
target.write(map_patch);
},
}
}
fn get_size_hint(&self) -> usize {
let tag_size = 0u8.get_size_hint();
match self {
StorageSlotPatch::Value(value_patch) => tag_size + value_patch.get_size_hint(),
StorageSlotPatch::Map(map_patch) => tag_size + map_patch.get_size_hint(),
}
}
}
impl Deserializable for StorageSlotPatch {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
match source.read_u8()? {
Self::VALUE => Ok(Self::Value(source.read()?)),
Self::MAP => Ok(Self::Map(source.read()?)),
other => Err(DeserializationError::InvalidValue(format!(
"unknown storage slot patch variant {other}"
))),
}
}
}
pub(super) enum MergeOutcome {
Keep,
Remove,
}