Skip to content

Commit

Permalink
feat: de/serialize based on human readability
Browse files Browse the repository at this point in the history
  • Loading branch information
kariy authored and xJonathanLEI committed Jul 16, 2024
1 parent 08a7807 commit d84edaf
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 9 deletions.
21 changes: 18 additions & 3 deletions starknet-core/src/serde/num_hex.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod u64 {
use alloc::{fmt::Formatter, format};
use core::mem;

use serde::{de::Visitor, Deserializer, Serializer};

Expand All @@ -9,21 +10,29 @@ pub mod u64 {
where
S: Serializer,
{
serializer.serialize_str(&format!("{value:#x}"))
if serializer.is_human_readable() {
serializer.serialize_str(&format!("{value:#x}"))
} else {
serializer.serialize_bytes(&value.to_be_bytes())
}
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(NumHexVisitor)
if deserializer.is_human_readable() {
deserializer.deserialize_any(NumHexVisitor)
} else {
deserializer.deserialize_bytes(NumHexVisitor)
}
}

impl<'de> Visitor<'de> for NumHexVisitor {
type Value = u64;

fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result {
write!(formatter, "string")
write!(formatter, "string, or an array of u8")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
Expand All @@ -33,5 +42,11 @@ pub mod u64 {
u64::from_str_radix(v.trim_start_matches("0x"), 16)
.map_err(|err| serde::de::Error::custom(format!("invalid u64 hex string: {err}")))
}

fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
<[u8; mem::size_of::<u64>()]>::try_from(v)
.map(u64::from_be_bytes)
.map_err(serde::de::Error::custom)
}
}
}
28 changes: 25 additions & 3 deletions starknet-core/src/serde/unsigned_field_element.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use alloc::{fmt::Formatter, format};

use crypto_bigint::U256;
use serde::{
de::{Error as DeError, Visitor},
Deserializer, Serializer,
Expand All @@ -8,6 +9,9 @@ use serde_with::{DeserializeAs, SerializeAs};

use starknet_types_core::felt::Felt;

const PRIME: U256 =
U256::from_be_hex("0800000000000011000000000000000000000000000000000000000000000001");

pub struct UfeHex;

pub struct UfeHexOption;
Expand All @@ -23,7 +27,11 @@ impl SerializeAs<Felt> for UfeHex {
where
S: Serializer,
{
serializer.serialize_str(&format!("{value:#x}"))
if serializer.is_human_readable() {
serializer.serialize_str(&format!("{value:#x}"))
} else {
serializer.serialize_bytes(&value.to_bytes_be())
}
}
}

Expand All @@ -32,15 +40,19 @@ impl<'de> DeserializeAs<'de, Felt> for UfeHex {
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(UfeHexVisitor)
if deserializer.is_human_readable() {
deserializer.deserialize_any(UfeHexVisitor)
} else {
deserializer.deserialize_bytes(UfeHexVisitor)
}
}
}

impl<'de> Visitor<'de> for UfeHexVisitor {
type Value = Felt;

fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result {
write!(formatter, "string")
write!(formatter, "a hex string, or an array of u8")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
Expand All @@ -49,6 +61,16 @@ impl<'de> Visitor<'de> for UfeHexVisitor {
{
Felt::from_hex(v).map_err(|err| DeError::custom(format!("invalid hex string: {err}")))
}

fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
let buf = <[u8; 32]>::try_from(v).map_err(serde::de::Error::custom)?;

if U256::from_be_slice(&buf) < PRIME {
Ok(Felt::from_bytes_be(&buf))
} else {
Err(serde::de::Error::custom("field element value out of range"))
}
}
}

impl SerializeAs<Option<Felt>> for UfeHexOption {
Expand Down
20 changes: 17 additions & 3 deletions starknet-core/src/types/hash_256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,11 @@ impl Serialize for Hash256 {
where
S: serde::Serializer,
{
serializer.serialize_str(&format!("0x{}", hex::encode(self.inner)))
if serializer.is_human_readable() {
serializer.serialize_str(&format!("0x{}", hex::encode(self.inner)))
} else {
serializer.serialize_bytes(self.as_bytes())
}
}
}

Expand All @@ -87,15 +91,19 @@ impl<'de> Deserialize<'de> for Hash256 {
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(Hash256Visitor)
if deserializer.is_human_readable() {
deserializer.deserialize_any(Hash256Visitor)
} else {
deserializer.deserialize_bytes(Hash256Visitor)
}
}
}

impl<'de> Visitor<'de> for Hash256Visitor {
type Value = Hash256;

fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result {
write!(formatter, "string")
write!(formatter, "string, or an array of u8")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
Expand All @@ -105,6 +113,12 @@ impl<'de> Visitor<'de> for Hash256Visitor {
v.parse()
.map_err(|err| serde::de::Error::custom(format!("{}", err)))
}

fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
<[u8; HASH_256_BYTE_COUNT]>::try_from(v)
.map(Hash256::from_bytes)
.map_err(serde::de::Error::custom)
}
}

impl FromStr for Hash256 {
Expand Down

0 comments on commit d84edaf

Please sign in to comment.