Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use marker trait StrictCodec to indicate strict one-to-one correspondance #252

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,36 @@ pub fn compact_as_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStr

wrap_with_dummy_const(impl_block)
}

/// Derive marker trait `parity_scale_codec::StrictCodec` for struct and enum.
#[proc_macro_derive(Strict, attributes(codec))]
pub fn strict_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut input: DeriveInput = match syn::parse(input) {
Ok(input) => input,
Err(e) => return e.to_compile_error().into(),
};

if let Err(e) = utils::check_attributes(&input) {
return e.to_compile_error().into();
}

if let Err(e) = trait_bounds::add(
&input.ident,
&mut input.generics,
&input.data,
parse_quote!(_parity_scale_codec::StrictCodec),
None,
utils::has_dumb_trait_bound(&input.attrs),
) {
return e.to_compile_error().into();
}

let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

let impl_block = quote! {
impl #impl_generics _parity_scale_codec::StrictCodec for #name #ty_generics #where_clause {}
};

wrap_with_dummy_const(impl_block)
}
35 changes: 33 additions & 2 deletions src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ pub trait Encode {
///
/// # Note
///
/// This works by using a special [`Output`] that only tracks the size. So, there are no allocations inside the
/// output. However, this can not prevent allocations that some types are doing inside their own encoding.
/// This works by using a special [`Output`] that only tracks the size. So, there are no allocations inside the
/// output. However, this can not prevent allocations that some types are doing inside their own encoding.
fn encoded_size(&self) -> usize {
let mut size_tracker = SizeTracker { written: 0 };
self.encode_to(&mut size_tracker);
Expand Down Expand Up @@ -309,6 +309,9 @@ impl<S: Encode + EncodeLike> FullEncode for S {}
pub trait FullCodec: Decode + FullEncode {}
impl<S: Decode + FullEncode> FullCodec for S {}

/// Marker trait indicating that SCALE on the struct has strict one-to-one correspondance.
pub trait StrictCodec: Codec {}

/// A marker trait for types that wrap other encodable type.
///
/// Such types should not carry any additional information
Expand Down Expand Up @@ -489,6 +492,8 @@ impl<T: Decode, E: Decode> Decode for Result<T, E> {
}
}

impl<T: StrictCodec, E: StrictCodec> StrictCodec for Result<T, E> {}

/// Shim type because we can't do a specialised implementation for `Option<bool>` directly.
#[derive(Eq, PartialEq, Clone, Copy)]
pub struct OptionBool(pub Option<bool>);
Expand Down Expand Up @@ -526,6 +531,8 @@ impl Decode for OptionBool {
}
}

impl StrictCodec for OptionBool {}

impl<T: EncodeLike<U>, U: Encode> EncodeLike<Option<U>> for Option<T> {}

impl<T: Encode> Encode for Option<T> {
Expand Down Expand Up @@ -561,6 +568,8 @@ impl<T: Decode> Decode for Option<T> {
}
}

impl<T: StrictCodec> StrictCodec for Option<T> {}

macro_rules! impl_for_non_zero {
( $( $name:ty ),* $(,)? ) => {
$(
Expand Down Expand Up @@ -588,6 +597,8 @@ macro_rules! impl_for_non_zero {
.ok_or_else(|| Error::from("cannot create non-zero number from 0"))
}
}

impl StrictCodec for $name {}
)*
}
}
Expand Down Expand Up @@ -717,6 +728,8 @@ macro_rules! impl_array {
}

impl<T: EncodeLike<U>, U: Encode> EncodeLike<[U; $n]> for [T; $n] {}

impl<T: StrictCodec> StrictCodec for [T; $n] {}
)*
}
}
Expand Down Expand Up @@ -778,6 +791,8 @@ impl<T> Decode for PhantomData<T> {
}
}

impl<T> StrictCodec for PhantomData<T> {}

#[cfg(any(feature = "std", feature = "full"))]
impl Decode for String {
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
Expand Down Expand Up @@ -886,6 +901,8 @@ impl<T: Decode> Decode for Vec<T> {
}
}

impl<T: StrictCodec> StrictCodec for Vec<T> {}

macro_rules! impl_codec_through_iterator {
($(
$type:ident
Expand Down Expand Up @@ -990,6 +1007,8 @@ impl<T: Decode> Decode for VecDeque<T> {
}
}

impl<T: StrictCodec> StrictCodec for VecDeque<T> {}

impl EncodeLike for () {}

impl Encode for () {
Expand All @@ -1011,6 +1030,8 @@ impl Decode for () {
}
}

impl StrictCodec for () {}

macro_rules! impl_len {
( $( $type:ident< $($g:ident),* > ),* ) => { $(
impl<$($g),*> DecodeLength for $type<$($g),*> {
Expand Down Expand Up @@ -1063,6 +1084,7 @@ macro_rules! tuple_impl {
}

impl<$one: EncodeLike<$extra>, $extra: Encode> crate::EncodeLike<($extra,)> for ($one,) {}
impl<$one: StrictCodec> StrictCodec for ($one,) {}
};
(($first:ident, $fextra:ident), $( ( $rest:ident, $rextra:ident ), )+) => {
impl<$first: Encode, $($rest: Encode),+> Encode for ($first, $($rest),+) {
Expand Down Expand Up @@ -1111,6 +1133,8 @@ macro_rules! tuple_impl {
}
}

impl<$first: StrictCodec, $($rest: StrictCodec),+> StrictCodec for ($first, $($rest),+) {}

tuple_impl!( $( ($rest, $rextra), )+ );
}
}
Expand Down Expand Up @@ -1151,6 +1175,8 @@ macro_rules! impl_endians {
Ok(<$t>::from_le_bytes(buf))
}
}

impl StrictCodec for $t {}
)* }
}
macro_rules! impl_one_byte {
Expand All @@ -1176,6 +1202,8 @@ macro_rules! impl_one_byte {
Ok(input.read_byte()? as $t)
}
}

impl StrictCodec for $t {}
)* }
}

Expand Down Expand Up @@ -1205,6 +1233,8 @@ impl Decode for bool {
}
}

impl StrictCodec for bool {}

impl Encode for Duration {
fn size_hint(&self) -> usize {
mem::size_of::<u64>() + mem::size_of::<u32>()
Expand All @@ -1230,6 +1260,7 @@ impl Decode for Duration {
}

impl EncodeLike for Duration {}
impl StrictCodec for Duration {}

#[cfg(test)]
mod tests {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ mod error;
pub use self::error::Error;
pub use self::codec::{
Input, Output, Decode, Encode, Codec, EncodeAsRef, WrapperTypeEncode, WrapperTypeDecode,
OptionBool, DecodeLength, FullCodec, FullEncode,
OptionBool, DecodeLength, FullCodec, FullEncode, StrictCodec,
};
#[cfg(feature = "std")]
pub use self::codec::IoReader;
Expand Down
4 changes: 2 additions & 2 deletions tests/single_field_struct_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
use parity_scale_codec_derive::{Encode, Decode, CompactAs};
#[cfg(feature="derive")]
use parity_scale_codec::CompactAs;
use parity_scale_codec::{Compact, Decode, Encode, HasCompact};
use parity_scale_codec::{Compact, Decode, Encode, HasCompact, Strict};
use serde_derive::{Serialize, Deserialize};

#[derive(Debug, PartialEq, Encode, Decode)]
#[derive(Debug, PartialEq, Encode, Decode, Strict)]
struct S {
x: u32,
}
Expand Down