Skip to content

Commit

Permalink
fix(gadget-blueprint-serde)!: handle bytes properly (#500)
Browse files Browse the repository at this point in the history
* fix(gadget-blueprint-serde)!: test `AccountId32` and `Bytes` serialization

* fix(gadget-blueprint-proc-macro)!: recognize `ByteBuf` as `FieldType::Bytes`

* feat(gadget-sdk): export ByteBuf

* chore: fmt
  • Loading branch information
Serial-ATA authored Nov 26, 2024
1 parent a2f2a47 commit 042718b
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 170 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ reqwest = "0.12.7"
rustdoc-types = "0.31.0"
schnorrkel = { version = "0.11.4", default-features = false, features = ["preaudit_deprecated", "getrandom"] }
serde = { version = "1.0.208", default-features = false }
serde_bytes = { version = "0.11.15", default-features = false }
serde_json = "1.0"
serde_test = "1.0.177"
sha2 = "0.10.8"
Expand Down
6 changes: 5 additions & 1 deletion blueprint-serde/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ repository.workspace = true
[dependencies]
paste.workspace = true
serde.workspace = true
serde_bytes = { workspace = true, features = ["alloc"] }
tangle-subxt.workspace = true

[dev-dependencies]
Expand All @@ -21,4 +22,7 @@ workspace = true

[features]
default = ["std"]
std = []
std = [
"serde/std",
"serde_bytes/std"
]
115 changes: 12 additions & 103 deletions blueprint-serde/src/de.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::error::{Error, Result, UnsupportedType};
use crate::Field;
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use serde::de;
use serde::de::IntoDeserializer;
use serde::{de, forward_to_deserialize_any};
use tangle_subxt::subxt_core::utils::AccountId32;
use tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec;
use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString;
Expand All @@ -16,24 +16,6 @@ use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives:
/// See [`crate::from_field`].
pub struct Deserializer(pub(crate) Field<AccountId32>);

macro_rules! deserialize_primitive {
($($t:ty => $pat:pat),+ $(,)?) => {
$(
paste::paste! {
fn [<deserialize_ $t>]<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
match self.0 {
$pat(value) => visitor.[<visit_ $t>](value),
_ => Err(self.invalid_type(&visitor))
}
}
}
)+
}
}

impl<'de> de::Deserializer<'de> for Deserializer {
type Error = Error;

Expand All @@ -56,25 +38,16 @@ impl<'de> de::Deserializer<'de> for Deserializer {
let s = String::from_utf8(s.0 .0)?;
visitor.visit_string(s)
}
Field::Bytes(b) => visitor.visit_bytes(b.0.as_slice()),
Field::Bytes(b) => {
// Unless `deserialize_bytes` is explicitly called, assume a sequence is desired
de::value::SeqDeserializer::new(b.0.into_iter()).deserialize_any(visitor)
}
Field::Array(seq) | Field::List(seq) => visit_seq(seq.0, visitor),
Field::Struct(_, fields) => visit_struct(*fields, visitor),
Field::AccountId(a) => visitor.visit_bytes(a.0.as_slice()),
Field::AccountId(a) => visitor.visit_string(a.to_string()),
}
}

deserialize_primitive!(
bool => Field::Bool,
i8 => Field::Int8,
i16 => Field::Int16,
i32 => Field::Int32,
i64 => Field::Int64,
u8 => Field::Uint8,
u16 => Field::Uint16,
u32 => Field::Uint32,
u64 => Field::Uint64,
);

fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
Expand Down Expand Up @@ -118,36 +91,6 @@ impl<'de> de::Deserializer<'de> for Deserializer {
self.deserialize_string(visitor)
}

fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
match self.0 {
Field::String(bound_string) => {
visitor.visit_string(String::from_utf8(bound_string.0 .0)?)
}
_ => Err(self.invalid_type(&visitor)),
}
}

fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
self.deserialize_byte_buf(visitor)
}

fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
match self.0 {
Field::Bytes(seq) => visitor.visit_byte_buf(seq.0),
Field::String(s) => visitor.visit_string(String::from_utf8(s.0 .0)?),
_ => Err(self.invalid_type(&visitor)),
}
}

fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
Expand Down Expand Up @@ -182,23 +125,6 @@ impl<'de> de::Deserializer<'de> for Deserializer {
visitor.visit_newtype_struct(self)
}

fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
match self.0 {
Field::Array(seq) | Field::List(seq) => visit_seq(seq.0, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}

fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
self.deserialize_seq(visitor)
}

fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
Expand Down Expand Up @@ -228,21 +154,6 @@ impl<'de> de::Deserializer<'de> for Deserializer {
Err(Error::UnsupportedType(UnsupportedType::Map))
}

fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
match self.0 {
Field::Struct(_name, fields) => visit_struct(*fields, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}

fn deserialize_enum<V>(
self,
_name: &'static str,
Expand All @@ -261,20 +172,18 @@ impl<'de> de::Deserializer<'de> for Deserializer {
}
}

fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
self.deserialize_str(visitor)
}

fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
drop(self);
visitor.visit_unit()
}

forward_to_deserialize_any! {
bool u8 u16 u32 u64 i8 i16 i32 i64 string
bytes byte_buf seq struct identifier tuple
}
}

impl Deserializer {
Expand Down
1 change: 1 addition & 0 deletions blueprint-serde/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ use tangle_subxt::subxt_core::utils::AccountId32;
pub use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field;
pub use tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec;
pub use ser::new_bounded_string;
pub use serde_bytes::ByteBuf;
use error::Result;

/// Derive a [`Field`] from an instance of type `S`
Expand Down
67 changes: 5 additions & 62 deletions blueprint-serde/src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ impl<'a> serde::Serializer for &'a mut Serializer {
type SerializeSeq = SerializeSeq<'a>;
type SerializeTuple = Self::SerializeSeq;
type SerializeTupleStruct = SerializeTupleStruct<'a>;
type SerializeTupleVariant = Self;
type SerializeMap = Self;
type SerializeTupleVariant = ser::Impossible<Self::Ok, Self::Error>;
type SerializeMap = ser::Impossible<Self::Ok, Self::Error>;
type SerializeStruct = SerializeStruct<'a>;
type SerializeStructVariant = Self;
type SerializeStructVariant = ser::Impossible<Self::Ok, Self::Error>;

fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
Ok(Field::Bool(v))
Expand Down Expand Up @@ -164,7 +164,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant> {
Ok(self)
Err(Self::Error::UnsupportedType(UnsupportedType::NonUnitEnum))
}

fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
Expand All @@ -187,7 +187,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant> {
Ok(self)
Err(Self::Error::UnsupportedType(UnsupportedType::NonUnitEnum))
}

fn is_human_readable(&self) -> bool {
Expand Down Expand Up @@ -342,63 +342,6 @@ impl ser::SerializeStruct for SerializeStruct<'_> {
}
}

// === UNSUPPORTED TYPES ===

impl ser::SerializeTupleVariant for &mut Serializer {
type Ok = Field<AccountId32>;
type Error = crate::error::Error;

fn serialize_field<T>(&mut self, _value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
Err(Self::Error::UnsupportedType(UnsupportedType::NonUnitEnum))
}

fn end(self) -> Result<Self::Ok> {
Err(Self::Error::UnsupportedType(UnsupportedType::NonUnitEnum))
}
}

impl ser::SerializeMap for &mut Serializer {
type Ok = Field<AccountId32>;
type Error = crate::error::Error;

fn serialize_key<T>(&mut self, _key: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
Err(Self::Error::UnsupportedType(UnsupportedType::Map))
}

fn serialize_value<T>(&mut self, _value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
Err(Self::Error::UnsupportedType(UnsupportedType::Map))
}

fn end(self) -> Result<Self::Ok> {
Err(Self::Error::UnsupportedType(UnsupportedType::Map))
}
}

impl ser::SerializeStructVariant for &mut Serializer {
type Ok = Field<AccountId32>;
type Error = crate::error::Error;

fn serialize_field<T>(&mut self, _key: &'static str, _value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
Err(Self::Error::UnsupportedType(UnsupportedType::NonUnitEnum))
}

fn end(self) -> Result<Self::Ok> {
Err(Self::Error::UnsupportedType(UnsupportedType::NonUnitEnum))
}
}

pub fn new_bounded_string<S>(s: S) -> BoundedString
where
S: Into<String>,
Expand Down
Loading

0 comments on commit 042718b

Please sign in to comment.