Skip to content
This repository has been archived by the owner on Jan 4, 2023. It is now read-only.

Commit

Permalink
Split encoding and decoding into static and dynamic phases.
Browse files Browse the repository at this point in the history
Added more comments.
Implemented traits for `[T; N]` arrays. It has many usage of `unsafe`, but I did the same change in this PR: paritytech/parity-scale-codec#299
  • Loading branch information
xgreenx committed Sep 25, 2022
1 parent c5a12ec commit a4461dd
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 107 deletions.
66 changes: 38 additions & 28 deletions derive/src/deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,61 +8,48 @@ fn deserialize_struct(s: &synstructure::Structure) -> TokenStream2 {
let decode_main = variant.construct(|field, _| {
let ty = &field.ty;
quote! {
<#ty as fuel_tx::io::Deserialize>::decode(buffer)?
<#ty as fuel_tx::io::Deserialize>::decode_static(buffer)?
}
});

let decode_extra = variant.each(|binding| {
let decode_dynamic = variant.each(|binding| {
quote! {
fuel_tx::io::Deserialize::decode_extra(#binding, buffer)?;
fuel_tx::io::Deserialize::decode_dynamic(#binding, buffer)?;
}
});

s.gen_impl(quote! {
gen impl fuel_tx::io::Deserialize for @Self {
fn decode<I: fuel_tx::io::Input + ?Sized>(buffer: &mut I) -> ::core::result::Result<Self, fuel_tx::io::Error> {
let mut object = #decode_main;
fn decode_static<I: fuel_tx::io::Input + ?Sized>(buffer: &mut I) -> ::core::result::Result<Self, fuel_tx::io::Error> {
::core::result::Result::Ok(#decode_main)
}

match object {
#decode_extra,
fn decode_dynamic<I: fuel_tx::io::Input + ?Sized>(&mut self, buffer: &mut I) -> ::core::result::Result<(), fuel_tx::io::Error> {
match self {
#decode_dynamic,
};

::core::result::Result::Ok(object)
::core::result::Result::Ok(())
}
}
})
}

fn deserialize_enum(s: &synstructure::Structure) -> TokenStream2 {
assert!(!s.variants().is_empty(), "got invalid empty enum");
let decode = s
let decode_static = s
.variants()
.iter()
.map(|variant| {
let decode_main = variant.construct(|field, _| {
let ty = &field.ty;
quote! {
<#ty as fuel_tx::io::Deserialize>::decode(buffer)?
}
});

let decode_extra = variant.each(|binding| {
quote! {
fuel_tx::io::Deserialize::decode_extra(#binding, buffer)?;
<#ty as fuel_tx::io::Deserialize>::decode_static(buffer)?
}
});

quote! {
{
let mut object = #decode_main;

match object {
#decode_extra,
// It is not possible, because we created `object` on previous iteration.
_ => panic!("unexpected variant of the enum"),
};

::core::result::Result::Ok(object)
::core::result::Result::Ok(#decode_main)
}
}
})
Expand All @@ -75,14 +62,37 @@ fn deserialize_enum(s: &synstructure::Structure) -> TokenStream2 {
}
});

let decode_dynamic = s.variants().iter().map(|variant| {
let decode_dynamic = variant.each(|binding| {
quote! {
fuel_tx::io::Deserialize::decode_dynamic(#binding, buffer)?;
}
});

quote! {
#decode_dynamic
}
});

s.gen_impl(quote! {
gen impl fuel_tx::io::Deserialize for @Self {
fn decode<I: fuel_tx::io::Input + ?Sized>(buffer: &mut I) -> ::core::result::Result<Self, fuel_tx::io::Error> {
fn decode_static<I: fuel_tx::io::Input + ?Sized>(buffer: &mut I) -> ::core::result::Result<Self, fuel_tx::io::Error> {
match <::core::primitive::u64 as fuel_tx::io::Deserialize>::decode(buffer)? {
#decode
#decode_static
_ => return ::core::result::Result::Err(fuel_tx::io::Error::UnknownDiscriminant),
}
}

fn decode_dynamic<I: fuel_tx::io::Input + ?Sized>(&mut self, buffer: &mut I) -> ::core::result::Result<(), fuel_tx::io::Error> {
match self {
#(
#decode_dynamic
)*
_ => return ::core::result::Result::Err(fuel_tx::io::Error::UnknownDiscriminant),
};

::core::result::Result::Ok(())
}
}
})
}
Expand Down
60 changes: 39 additions & 21 deletions derive/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,34 @@ fn serialize_struct(s: &synstructure::Structure) -> TokenStream2 {
assert_eq!(s.variants().len(), 1, "structs must have one variant");

let variant: &synstructure::VariantInfo = &s.variants()[0];
let encode = variant.each(|binding| {
let encode_static = variant.each(|binding| {
quote! {
if fuel_tx::io::Serialize::size(#binding) % fuel_tx::io::ALIGN > 0 {
return ::core::result::Result::Err(fuel_tx::io::Error::WrongAlign)
}
fuel_tx::io::Serialize::encode(#binding, buffer)?;
fuel_tx::io::Serialize::encode_static(#binding, buffer)?;
}
});

let encode_extra = variant.each(|binding| {
let encode_dynamic = variant.each(|binding| {
quote! {
fuel_tx::io::Serialize::encode_extra(#binding, buffer)?;
fuel_tx::io::Serialize::encode_dynamic(#binding, buffer)?;
}
});

s.gen_impl(quote! {
gen impl fuel_tx::io::Serialize for @Self {
fn encode<O: fuel_tx::io::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), fuel_tx::io::Error> {
fn encode_static<O: fuel_tx::io::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), fuel_tx::io::Error> {
match self {
#encode
#encode_static
};

::core::result::Result::Ok(())
}

fn encode_dynamic<O: fuel_tx::io::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), fuel_tx::io::Error> {
match self {
#encode_extra
#encode_dynamic
};

::core::result::Result::Ok(())
Expand All @@ -38,40 +43,53 @@ fn serialize_struct(s: &synstructure::Structure) -> TokenStream2 {

fn serialize_enum(s: &synstructure::Structure) -> TokenStream2 {
assert!(!s.variants().is_empty(), "got invalid empty enum");
let encode_body = s.variants().iter().enumerate().map(|(i, v)| {
let encode_static = s.variants().iter().enumerate().map(|(i, v)| {
let pat = v.pat();
let index = i as u64;
let encode_iter = v.bindings().iter().map(|binding| {
let encode_static_iter = v.bindings().iter().map(|binding| {
quote! {
if fuel_tx::io::Serialize::size(#binding) % fuel_tx::io::ALIGN > 0 {
return ::core::result::Result::Err(fuel_tx::io::Error::WrongAlign)
}
fuel_tx::io::Serialize::encode(#binding, buffer)?;
}
});
let encode_extra_iter = v.bindings().iter().map(|binding| {
quote! {
fuel_tx::io::Serialize::encode_extra(#binding, buffer)?;
fuel_tx::io::Serialize::encode_static(#binding, buffer)?;
}
});
quote! {
#pat => {
{ <::core::primitive::u64 as fuel_tx::io::Serialize>::encode(&#index, buffer)?; }
#(
{ #encode_iter }
)*
#(
{ #encode_extra_iter }
{ #encode_static_iter }
)*
}
}
});
let encode_dynamic = s.variants().iter().map(|v| {
let encode_dynamic_iter = v.each(|binding| {
quote! {
fuel_tx::io::Serialize::encode_dynamic(#binding, buffer)?;
}
});
quote! {
#encode_dynamic_iter
}
});
s.gen_impl(quote! {
gen impl fuel_tx::io::Serialize for @Self {
fn encode<O: fuel_tx::io::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), fuel_tx::io::Error> {
fn encode_static<O: fuel_tx::io::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), fuel_tx::io::Error> {
match self {
#(
#encode_static
)*,
_ => return ::core::result::Result::Err(fuel_tx::io::Error::UnknownDiscriminant),
};

::core::result::Result::Ok(())
}

fn encode_dynamic<O: fuel_tx::io::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), fuel_tx::io::Error> {
match self {
#(
#encode_body
#encode_dynamic
)*,
_ => return ::core::result::Result::Err(fuel_tx::io::Error::UnknownDiscriminant),
};
Expand Down
1 change: 1 addition & 0 deletions src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use core::iter;

#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(fuel_tx::io::Deserialize, fuel_tx::io::Serialize)]
/// Deployable representation of a contract code.
pub struct Contract(Vec<u8>);

Expand Down
Loading

0 comments on commit a4461dd

Please sign in to comment.