Skip to content

Commit

Permalink
refactor: Simplify serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
igamigo committed Dec 12, 2024
1 parent 0518877 commit f12c492
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 69 deletions.
2 changes: 2 additions & 0 deletions objects/src/accounts/package/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ impl ComponentTemplate {
pub enum ComponentTemplateError {
#[error("component storage slots are not contiguous")]
NonContiguousSlots,
#[error("error deserializing storage entry: {0}")]
StorageEntryDeserializationError(String),
}

// SERIALIZATION
Expand Down
139 changes: 70 additions & 69 deletions objects/src/accounts/package/storage_entry/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use alloc::{string::String, vec::Vec};

use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};

mod word;
pub use word::*;

use super::ComponentTemplateError;

// STORAGE ENTRY
// ================================================================================================

Expand Down Expand Up @@ -77,14 +79,64 @@ struct RawStorageEntry {
values: Option<Vec<WordRepresentation>>,
}

impl From<StorageEntry> for RawStorageEntry {
fn from(entry: StorageEntry) -> Self {
match entry {
StorageEntry::Value { name, description, slot, value } => RawStorageEntry {
name,
description,
slot: Some(slot),
slots: None,
value: Some(value),
values: None,
},
StorageEntry::Map { .. } => todo!(),
StorageEntry::MultiSlot { name, description, slots, values } => RawStorageEntry {
name,
description,
slot: None,
slots: Some(slots),
value: None,
values: Some(values),
},
}
}
}

impl Serialize for StorageEntry {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let raw_storage_entry: RawStorageEntry = self.clone().into();
raw_storage_entry.serialize(serializer)
}
}

impl RawStorageEntry {
pub fn validate(&self) -> Result<(), String> {
pub fn validate(&self) -> Result<(), ComponentTemplateError> {
if self.slot.is_none() && self.slots.is_none() {
return Err(ComponentTemplateError::StorageEntryDeserializationError(
"Missing slot(s) definitions".into(),
));
}

if self.value.is_none() && self.values.is_none() {
return Err(ComponentTemplateError::StorageEntryDeserializationError(
"Missing value(s) definitions".into(),
));
}

if self.slot.is_some() && self.slots.is_some() {
return Err("Fields `slot` and `slots` are mutually exclusive".into());
return Err(ComponentTemplateError::StorageEntryDeserializationError(
"Fields `slot` and `slots` are mutually exclusive".into(),
));
}

if self.value.is_some() && self.values.is_some() {
return Err("Fields `value` and `values` are mutually exclusive".into());
return Err(ComponentTemplateError::StorageEntryDeserializationError(
"Fields `value` and `values` are mutually exclusive".into(),
));
}

let slots_count = if self.slot.is_some() {
Expand All @@ -106,97 +158,46 @@ impl RawStorageEntry {
};

if slots_count != values_count {
return Err(format!(
return Err(ComponentTemplateError::StorageEntryDeserializationError(format!(
"Number of slots ({}) does not match number of values ({})",
slots_count, values_count
));
)));
}

Ok(())
}
}

impl Serialize for StorageEntry {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
StorageEntry::Value { name, description, slot, value } => {
let field_count = 4 + if description.is_some() { 1 } else { 0 };
let mut s = serializer.serialize_struct("Storage", field_count)?;
s.serialize_field("name", name)?;
if let Some(desc) = description {
s.serialize_field("description", desc)?;
}
s.serialize_field("slot", slot)?;
s.serialize_field("value", value)?;
s.end()
},
StorageEntry::Map { name, description, slot, values } => {
let field_count = 3 + if description.is_some() { 1 } else { 0 };
let mut s = serializer.serialize_struct("Storage", field_count)?;
s.serialize_field("name", name)?;
if let Some(desc) = description {
s.serialize_field("description", desc)?;
}
s.serialize_field("slot", slot)?;
s.serialize_field("values", values)?;
s.end()
},
StorageEntry::MultiSlot { name, description, slots, values } => {
let field_count = 2 + if description.is_some() { 1 } else { 0 };
let mut s = serializer.serialize_struct("Storage", field_count)?;
s.serialize_field("name", name)?;
if let Some(desc) = description {
s.serialize_field("description", desc)?;
}
s.serialize_field("slots", slots)?;
s.serialize_field("values", values)?;

s.end()
},
}
}
}

impl<'de> Deserialize<'de> for StorageEntry {
fn deserialize<D>(deserializer: D) -> Result<StorageEntry, D::Error>
where
D: Deserializer<'de>,
{
let raw = RawStorageEntry::deserialize(deserializer)?;
raw.validate().unwrap();
raw.validate().map_err(D::Error::custom)?;

let value_present = raw.value.is_some();
let values_present = raw.values.is_some();
let slots_present = raw.slots.is_some();

// Infer variant based on which fields are present
match (value_present, values_present, slots_present) {
(true, false, false) => {
// Value variant
Ok(StorageEntry::Value {
name: raw.name,
description: raw.description,
slot: raw.slot.ok_or_else(|| D::Error::missing_field("slot"))?,
value: raw.value.unwrap(),
})
},
(false, true, false) => {
// Map variant
match (values_present, slots_present) {
(false, false) => Ok(StorageEntry::Value {
name: raw.name,
description: raw.description,
slot: raw.slot.ok_or_else(|| D::Error::missing_field("slot"))?,
value: raw.value.ok_or_else(|| D::Error::custom("Missing 'value' field"))?,
}),
(true, false) => {
todo!()
},
(false, true, true) => {
// MultiSlot variant
(true, true) => {
if raw.slot.is_some() || raw.value.is_some() {
return Err(D::Error::custom("Invalid fields present for multi-slot variant."));
}
Ok(StorageEntry::MultiSlot {
name: raw.name,
description: raw.description,
slots: raw.slots.unwrap(),
values: raw.values.unwrap(),
slots: raw.slots.ok_or_else(|| D::Error::missing_field("slots"))?,
values: raw.values.ok_or_else(|| D::Error::custom("Missing 'values' field"))?,
})
},
_ => Err(D::Error::custom("Could not infer storage entry type from provided fields.")),
Expand Down

0 comments on commit f12c492

Please sign in to comment.