diff --git a/elrond-codec/Cargo.toml b/elrond-codec/Cargo.toml index 14b4ee8036..e9caaebf0e 100644 --- a/elrond-codec/Cargo.toml +++ b/elrond-codec/Cargo.toml @@ -24,3 +24,7 @@ optional = true [dependencies] wee_alloc = "0.4" arrayvec = { version = "0.7.1", default-features = false } + +[dev-dependencies.elrond-codec-derive] +path = "../elrond-codec-derive" +version = "=0.5.3" diff --git a/elrond-codec/src/impl_for_types/impl_array.rs b/elrond-codec/src/impl_for_types/impl_array.rs index 5e493a7ac8..e162d56094 100644 --- a/elrond-codec/src/impl_for_types/impl_array.rs +++ b/elrond-codec/src/impl_for_types/impl_array.rs @@ -1,9 +1,7 @@ use crate::codec_err::{DecodeError, EncodeError}; use crate::nested_de::NestedDecode; use crate::nested_de_input::NestedDecodeInput; -use crate::nested_ser::{ - dep_encode_slice_contents, dep_encode_slice_contents_or_exit, NestedEncode, -}; +use crate::nested_ser::NestedEncode; use crate::nested_ser_output::NestedEncodeOutput; use crate::top_de::{top_decode_from_nested, top_decode_from_nested_or_exit, TopDecode}; use crate::top_de_input::TopDecodeInput; @@ -16,7 +14,7 @@ use arrayvec::ArrayVec; impl NestedEncode for [T; N] { #[inline] fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - dep_encode_slice_contents(&self[..], dest) + super::impl_slice::dep_encode_slice_contents(&self[..], dest) } #[inline] @@ -26,7 +24,7 @@ impl NestedEncode for [T; N] { c: ExitCtx, exit: fn(ExitCtx, EncodeError) -> !, ) { - dep_encode_slice_contents_or_exit(&self[..], dest, c, exit); + super::impl_slice::dep_encode_slice_contents_or_exit(&self[..], dest, c, exit); } } diff --git a/elrond-codec/src/impl_for_types/impl_bool.rs b/elrond-codec/src/impl_for_types/impl_bool.rs index da36bda26f..7cee162a32 100644 --- a/elrond-codec/src/impl_for_types/impl_bool.rs +++ b/elrond-codec/src/impl_for_types/impl_bool.rs @@ -1,3 +1,74 @@ +use crate::codec_err::{DecodeError, EncodeError}; +use crate::nested_de::NestedDecode; +use crate::nested_de_input::NestedDecodeInput; +use crate::nested_ser::{NestedEncode, NestedEncodeNoErr}; +use crate::nested_ser_output::NestedEncodeOutput; +use crate::top_de::TopDecode; +use crate::top_de_input::TopDecodeInput; +use crate::top_ser::{TopEncode, TopEncodeNoErr}; +use crate::top_ser_output::TopEncodeOutput; +use crate::{dep_encode_from_no_err, dep_encode_num_mimic, top_encode_from_no_err, TypeInfo}; + +impl TopEncodeNoErr for bool { + fn top_encode_no_err(&self, output: O) { + // only using signed because this one is implemented in Arwen, unsigned is not + // TODO: change to set_u64 + output.set_i64(if *self { 1i64 } else { 0i64 }); + } +} + +top_encode_from_no_err! {bool, TypeInfo::Bool} + +impl TopDecode for bool { + const TYPE_INFO: TypeInfo = TypeInfo::Bool; + + fn top_decode(input: I) -> Result { + match input.into_u64() { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(DecodeError::INPUT_OUT_OF_RANGE), + } + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + match input.into_u64() { + 0 => false, + 1 => true, + _ => exit(c, DecodeError::INPUT_OUT_OF_RANGE), + } + } +} + +dep_encode_num_mimic! {bool, u8, TypeInfo::Bool} + +impl NestedDecode for bool { + const TYPE_INFO: TypeInfo = TypeInfo::Bool; + + fn dep_decode(input: &mut I) -> Result { + match input.read_byte()? { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(DecodeError::INVALID_VALUE), + } + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + match input.read_byte_or_exit(c.clone(), exit) { + 0 => false, + 1 => true, + _ => exit(c, DecodeError::INVALID_VALUE), + } + } +} + #[cfg(test)] pub mod tests { use crate::test_util::{check_dep_encode_decode, check_top_encode_decode}; diff --git a/elrond-codec/src/impl_for_types/impl_decode_num_signed.rs b/elrond-codec/src/impl_for_types/impl_decode_num_signed.rs deleted file mode 100644 index 89aeef553c..0000000000 --- a/elrond-codec/src/impl_for_types/impl_decode_num_signed.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::codec_err::DecodeError; -use crate::nested_de::NestedDecode; -use crate::nested_de_input::NestedDecodeInput; -use crate::num_conv::bytes_to_number; -use crate::top_de::TopDecode; -use crate::top_de_input::TopDecodeInput; -use crate::TypeInfo; - -macro_rules! decode_num_signed { - ($ty:ty, $num_bytes:expr, $type_info:expr) => { - impl NestedDecode for $ty { - const TYPE_INFO: TypeInfo = $type_info; - - fn dep_decode(input: &mut I) -> Result { - let bytes = input.read_slice($num_bytes)?; - let num = bytes_to_number(bytes, true) as $ty; - Ok(num) - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - let bytes = input.read_slice_or_exit($num_bytes, c, exit); - let num = bytes_to_number(bytes, true) as $ty; - num - } - } - }; -} - -decode_num_signed!(i8, 1, TypeInfo::I8); -decode_num_signed!(i16, 2, TypeInfo::I16); -decode_num_signed!(i32, 4, TypeInfo::I32); -decode_num_signed!(isize, 4, TypeInfo::ISIZE); -decode_num_signed!(i64, 8, TypeInfo::I64); - -macro_rules! decode_num_signed { - ($ty:ty, $bounds_ty:ty, $type_info:expr) => { - impl TopDecode for $ty { - const TYPE_INFO: TypeInfo = $type_info; - - fn top_decode(input: I) -> Result { - let arg_i64 = input.into_i64(); - let min = <$bounds_ty>::MIN as i64; - let max = <$bounds_ty>::MAX as i64; - if arg_i64 < min || arg_i64 > max { - Err(DecodeError::INPUT_OUT_OF_RANGE) - } else { - Ok(arg_i64 as $ty) - } - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - let arg_i64 = input.into_i64(); - let min = <$bounds_ty>::MIN as i64; - let max = <$bounds_ty>::MAX as i64; - if arg_i64 < min || arg_i64 > max { - exit(c, DecodeError::INPUT_OUT_OF_RANGE) - } else { - arg_i64 as $ty - } - } - } - }; -} - -decode_num_signed!(i8, i8, TypeInfo::I8); -decode_num_signed!(i16, i16, TypeInfo::I16); -decode_num_signed!(i32, i32, TypeInfo::I32); -decode_num_signed!(isize, i32, TypeInfo::ISIZE); // even if isize can be 64 bits on some platforms, we always deserialize as max 32 bits -decode_num_signed!(i64, i64, TypeInfo::I64); diff --git a/elrond-codec/src/impl_for_types/impl_decode_num_unsigned.rs b/elrond-codec/src/impl_for_types/impl_decode_num_unsigned.rs deleted file mode 100644 index f5d93ff137..0000000000 --- a/elrond-codec/src/impl_for_types/impl_decode_num_unsigned.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::codec_err::DecodeError; -use crate::nested_de::NestedDecode; -use crate::nested_de_input::NestedDecodeInput; -use crate::num_conv::bytes_to_number; -use crate::top_de::TopDecode; -use crate::top_de_input::TopDecodeInput; -use crate::TypeInfo; - -macro_rules! decode_num_unsigned { - ($ty:ty, $num_bytes:expr, $type_info:expr) => { - impl NestedDecode for $ty { - const TYPE_INFO: TypeInfo = $type_info; - - fn dep_decode(input: &mut I) -> Result { - let bytes = input.read_slice($num_bytes)?; - let num = bytes_to_number(bytes, false) as $ty; - Ok(num) - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - let bytes = input.read_slice_or_exit($num_bytes, c, exit); - let num = bytes_to_number(bytes, false) as $ty; - num - } - } - }; -} - -decode_num_unsigned!(u16, 2, TypeInfo::U16); -decode_num_unsigned!(u32, 4, TypeInfo::U32); -decode_num_unsigned!(usize, 4, TypeInfo::USIZE); -decode_num_unsigned!(u64, 8, TypeInfo::U64); - -macro_rules! decode_num_unsigned { - ($ty:ty, $bounds_ty:ty, $type_info:expr) => { - impl TopDecode for $ty { - const TYPE_INFO: TypeInfo = $type_info; - - fn top_decode(input: I) -> Result { - let arg_u64 = input.into_u64(); - let max = <$bounds_ty>::MAX as u64; - if arg_u64 > max { - Err(DecodeError::INPUT_TOO_LONG) - } else { - Ok(arg_u64 as $ty) - } - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - let arg_u64 = input.into_u64(); - let max = <$bounds_ty>::MAX as u64; - if arg_u64 > max { - exit(c, DecodeError::INPUT_TOO_LONG) - } else { - arg_u64 as $ty - } - } - } - }; -} - -decode_num_unsigned!(u8, u8, TypeInfo::U8); -decode_num_unsigned!(u16, u16, TypeInfo::U16); -decode_num_unsigned!(u32, u32, TypeInfo::U32); -decode_num_unsigned!(usize, u32, TypeInfo::USIZE); // even if usize can be 64 bits on some platforms, we always deserialize as max 32 bits -decode_num_unsigned!(u64, u64, TypeInfo::U64); diff --git a/elrond-codec/src/impl_for_types/impl_dep_encode_from_no_err.rs b/elrond-codec/src/impl_for_types/impl_dep_encode_from_no_err.rs deleted file mode 100644 index 9fc9c78e9a..0000000000 --- a/elrond-codec/src/impl_for_types/impl_dep_encode_from_no_err.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::codec_err::EncodeError; -use crate::nested_ser::NestedEncode; -use crate::nested_ser::NestedEncodeNoErr; -use crate::nested_ser_output::NestedEncodeOutput; -use crate::TypeInfo; - -#[macro_export] -macro_rules! dep_encode_from_no_err { - ($type:ty, $type_info:expr) => { - impl NestedEncode for $type { - const TYPE_INFO: TypeInfo = $type_info; - - #[inline] - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - self.dep_encode_no_err(dest); - Ok(()) - } - - #[inline] - fn dep_encode_or_exit( - &self, - dest: &mut O, - _: ExitCtx, - _: fn(ExitCtx, EncodeError) -> !, - ) { - self.dep_encode_no_err(dest); - } - } - }; -} - -dep_encode_from_no_err! {(), TypeInfo::Unit} -dep_encode_from_no_err! {u8, TypeInfo::U8} diff --git a/elrond-codec/src/impl_for_types/impl_encode_num_mimic.rs b/elrond-codec/src/impl_for_types/impl_encode_num_mimic.rs deleted file mode 100644 index fe7fc7eab8..0000000000 --- a/elrond-codec/src/impl_for_types/impl_encode_num_mimic.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::codec_err::EncodeError; -use crate::dep_encode_from_no_err; -use crate::nested_ser::NestedEncode; -use crate::nested_ser::NestedEncodeNoErr; -use crate::nested_ser_output::NestedEncodeOutput; -use crate::TypeInfo; -// Derive the implementation of the other types by casting. -#[macro_export] -macro_rules! encode_num_mimic { - ($num_type:ty, $mimic_type:ident, $type_info:expr) => { - impl NestedEncodeNoErr for $num_type { - #[inline] - fn dep_encode_no_err(&self, dest: &mut O) { - (*self as $mimic_type).dep_encode_no_err(dest) - } - } - - dep_encode_from_no_err! {$num_type, $type_info} - }; -} - -encode_num_mimic! {usize, u32, TypeInfo::USIZE} -encode_num_mimic! {i64, u64, TypeInfo::I64} -encode_num_mimic! {i32, u32, TypeInfo::I32} -encode_num_mimic! {isize, u32, TypeInfo::ISIZE} -encode_num_mimic! {i16, u16, TypeInfo::I16} -encode_num_mimic! {i8, u8, TypeInfo::I8} -encode_num_mimic! {bool, u8, TypeInfo::Bool} diff --git a/elrond-codec/src/impl_for_types/impl_encode_num_signed.rs b/elrond-codec/src/impl_for_types/impl_encode_num_signed.rs deleted file mode 100644 index 7770335dce..0000000000 --- a/elrond-codec/src/impl_for_types/impl_encode_num_signed.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::codec_err::EncodeError; -use crate::top_encode_from_no_err; -use crate::top_ser::TopEncode; -use crate::top_ser::TopEncodeNoErr; -use crate::top_ser_output::TopEncodeOutput; -use crate::TypeInfo; - -macro_rules! encode_num_signed { - ($num_type:ty, $size_in_bits:expr, $type_info:expr) => { - impl TopEncodeNoErr for $num_type { - #[inline] - fn top_encode_no_err(&self, output: O) { - output.set_i64(*self as i64); - } - } - - top_encode_from_no_err! {$num_type, $type_info} - }; -} - -encode_num_signed! {i64, 64, TypeInfo::I64} -encode_num_signed! {i32, 32, TypeInfo::I32} -encode_num_signed! {isize, 32, TypeInfo::ISIZE} -encode_num_signed! {i16, 16, TypeInfo::I16} -encode_num_signed! {i8, 8, TypeInfo::I8} diff --git a/elrond-codec/src/impl_for_types/impl_encode_num_unsigned.rs b/elrond-codec/src/impl_for_types/impl_encode_num_unsigned.rs deleted file mode 100644 index 983e193a89..0000000000 --- a/elrond-codec/src/impl_for_types/impl_encode_num_unsigned.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::codec_err::EncodeError; -use crate::dep_encode_from_no_err; -use crate::nested_ser::NestedEncode; -use crate::nested_ser::NestedEncodeNoErr; -use crate::nested_ser_output::NestedEncodeOutput; -use crate::top_encode_from_no_err; -use crate::top_ser::TopEncode; -use crate::top_ser::TopEncodeNoErr; -use crate::top_ser_output::TopEncodeOutput; -use crate::TypeInfo; -// The main unsigned types need to be reversed before serializing. -macro_rules! encode_num_unsigned { - ($num_type:ty, $size_in_bits:expr, $type_info:expr) => { - impl NestedEncodeNoErr for $num_type { - #[inline(never)] - fn dep_encode_no_err(&self, dest: &mut O) { - dest.write(&self.to_be_bytes()[..]); - } - } - - dep_encode_from_no_err! {$num_type, $type_info} - }; -} - -encode_num_unsigned! {u64, 64, TypeInfo::U64} -encode_num_unsigned! {u32, 32, TypeInfo::U32} -encode_num_unsigned! {u16, 16, TypeInfo::U16} - -macro_rules! encode_num_unsigned { - ($num_type:ty, $size_in_bits:expr, $type_info:expr) => { - impl TopEncodeNoErr for $num_type { - #[inline] - fn top_encode_no_err(&self, output: O) { - output.set_u64(*self as u64); - } - } - top_encode_from_no_err! {$num_type, $type_info} - }; -} - -encode_num_unsigned! {u64, 64, TypeInfo::U64} -encode_num_unsigned! {u32, 32, TypeInfo::U32} -encode_num_unsigned! {usize, 32, TypeInfo::USIZE} -encode_num_unsigned! {u16, 16, TypeInfo::U16} -encode_num_unsigned! {u8, 8, TypeInfo::U8} diff --git a/elrond-codec/src/impl_for_types/impl_non_zero_usize.rs b/elrond-codec/src/impl_for_types/impl_non_zero_usize.rs new file mode 100644 index 0000000000..20f3408165 --- /dev/null +++ b/elrond-codec/src/impl_for_types/impl_non_zero_usize.rs @@ -0,0 +1,103 @@ +use core::num::NonZeroUsize; + +use crate::codec_err::{DecodeError, EncodeError}; +use crate::nested_de::NestedDecode; +use crate::nested_de_input::NestedDecodeInput; +use crate::nested_ser::NestedEncode; +use crate::nested_ser_output::NestedEncodeOutput; +use crate::top_de::TopDecode; +use crate::top_de_input::TopDecodeInput; +use crate::top_ser::TopEncode; +use crate::top_ser_output::TopEncodeOutput; + +impl TopEncode for NonZeroUsize { + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + self.get().top_encode(output) + } + + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.get().top_encode_or_exit(output, c, exit); + } +} + +impl TopDecode for NonZeroUsize { + fn top_decode(input: I) -> Result { + if let Some(nz) = NonZeroUsize::new(usize::top_decode(input)?) { + Ok(nz) + } else { + Err(DecodeError::INVALID_VALUE) + } + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + if let Some(nz) = NonZeroUsize::new(usize::top_decode_or_exit(input, c.clone(), exit)) { + nz + } else { + exit(c, DecodeError::INVALID_VALUE) + } + } +} + +impl NestedEncode for NonZeroUsize { + #[inline] + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + self.get().dep_encode(dest) + } + + #[inline] + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.get().dep_encode_or_exit(dest, c, exit); + } +} + +impl NestedDecode for NonZeroUsize { + fn dep_decode(input: &mut I) -> Result { + if let Some(nz) = NonZeroUsize::new(usize::dep_decode(input)?) { + Ok(nz) + } else { + Err(DecodeError::INVALID_VALUE) + } + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + if let Some(nz) = NonZeroUsize::new(usize::dep_decode_or_exit(input, c.clone(), exit)) { + nz + } else { + exit(c, DecodeError::INVALID_VALUE) + } + } +} + +#[cfg(test)] +pub mod tests { + use crate::test_util::{check_dep_encode_decode, check_top_encode_decode}; + use core::num::NonZeroUsize; + + #[test] + fn test_top() { + check_top_encode_decode(NonZeroUsize::new(5).unwrap(), &[5]); + } + + #[test] + fn test_dep() { + check_dep_encode_decode(NonZeroUsize::new(5).unwrap(), &[0, 0, 0, 5]); + } +} diff --git a/elrond-codec/src/impl_for_types/impl_num_signed.rs b/elrond-codec/src/impl_for_types/impl_num_signed.rs new file mode 100644 index 0000000000..c03633424c --- /dev/null +++ b/elrond-codec/src/impl_for_types/impl_num_signed.rs @@ -0,0 +1,150 @@ +use crate::num_conv::bytes_to_number; +use crate::{ + dep_encode_from_no_err, dep_encode_num_mimic, top_encode_from_no_err, top_ser::TopEncodeNoErr, + DecodeError, EncodeError, NestedDecode, NestedDecodeInput, NestedEncode, NestedEncodeNoErr, + NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, TypeInfo, +}; + +macro_rules! top_encode_num_signed { + ($num_type:ty, $size_in_bits:expr, $type_info:expr) => { + impl TopEncodeNoErr for $num_type { + #[inline] + fn top_encode_no_err(&self, output: O) { + output.set_i64(*self as i64); + } + } + + top_encode_from_no_err! {$num_type, $type_info} + }; +} + +top_encode_num_signed! {i64, 64, TypeInfo::I64} +top_encode_num_signed! {i32, 32, TypeInfo::I32} +top_encode_num_signed! {isize, 32, TypeInfo::ISIZE} +top_encode_num_signed! {i16, 16, TypeInfo::I16} +top_encode_num_signed! {i8, 8, TypeInfo::I8} + +dep_encode_num_mimic! {i64, u64, TypeInfo::I64} +dep_encode_num_mimic! {i32, u32, TypeInfo::I32} +dep_encode_num_mimic! {isize, u32, TypeInfo::ISIZE} +dep_encode_num_mimic! {i16, u16, TypeInfo::I16} +dep_encode_num_mimic! {i8, u8, TypeInfo::I8} + +macro_rules! dep_decode_num_signed { + ($ty:ty, $num_bytes:expr, $type_info:expr) => { + impl NestedDecode for $ty { + const TYPE_INFO: TypeInfo = $type_info; + + fn dep_decode(input: &mut I) -> Result { + let bytes = input.read_slice($num_bytes)?; + let num = bytes_to_number(bytes, true) as $ty; + Ok(num) + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + let bytes = input.read_slice_or_exit($num_bytes, c, exit); + let num = bytes_to_number(bytes, true) as $ty; + num + } + } + }; +} + +dep_decode_num_signed!(i8, 1, TypeInfo::I8); +dep_decode_num_signed!(i16, 2, TypeInfo::I16); +dep_decode_num_signed!(i32, 4, TypeInfo::I32); +dep_decode_num_signed!(isize, 4, TypeInfo::ISIZE); +dep_decode_num_signed!(i64, 8, TypeInfo::I64); + +macro_rules! top_decode_num_signed { + ($ty:ty, $bounds_ty:ty, $type_info:expr) => { + impl TopDecode for $ty { + const TYPE_INFO: TypeInfo = $type_info; + + fn top_decode(input: I) -> Result { + let arg_i64 = input.into_i64(); + let min = <$bounds_ty>::MIN as i64; + let max = <$bounds_ty>::MAX as i64; + if arg_i64 < min || arg_i64 > max { + Err(DecodeError::INPUT_OUT_OF_RANGE) + } else { + Ok(arg_i64 as $ty) + } + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + let arg_i64 = input.into_i64(); + let min = <$bounds_ty>::MIN as i64; + let max = <$bounds_ty>::MAX as i64; + if arg_i64 < min || arg_i64 > max { + exit(c, DecodeError::INPUT_OUT_OF_RANGE) + } else { + arg_i64 as $ty + } + } + } + }; +} + +top_decode_num_signed!(i8, i8, TypeInfo::I8); +top_decode_num_signed!(i16, i16, TypeInfo::I16); +top_decode_num_signed!(i32, i32, TypeInfo::I32); +top_decode_num_signed!(isize, i32, TypeInfo::ISIZE); // even if isize can be 64 bits on some platforms, we always deserialize as max 32 bits +top_decode_num_signed!(i64, i64, TypeInfo::I64); + +#[cfg(test)] +pub mod tests { + use crate::test_util::{check_dep_encode_decode, check_top_encode_decode}; + + #[test] + fn test_top() { + // signed zero + check_top_encode_decode(0i8, &[]); + check_top_encode_decode(0i16, &[]); + check_top_encode_decode(0i32, &[]); + check_top_encode_decode(0i64, &[]); + check_top_encode_decode(0isize, &[]); + // signed positive + check_top_encode_decode(5i8, &[5]); + check_top_encode_decode(5i16, &[5]); + check_top_encode_decode(5i32, &[5]); + check_top_encode_decode(5i64, &[5]); + check_top_encode_decode(5isize, &[5]); + // signed negative + check_top_encode_decode(-5i8, &[251]); + check_top_encode_decode(-5i16, &[251]); + check_top_encode_decode(-5i32, &[251]); + check_top_encode_decode(-5i64, &[251]); + check_top_encode_decode(-5isize, &[251]); + } + + #[test] + fn test_dep() { + // signed zero + check_dep_encode_decode(0i8, &[0]); + check_dep_encode_decode(0i16, &[0, 0]); + check_dep_encode_decode(0i32, &[0, 0, 0, 0]); + check_dep_encode_decode(0isize, &[0, 0, 0, 0]); + check_dep_encode_decode(0i64, &[0, 0, 0, 0, 0, 0, 0, 0]); + // signed positive + check_dep_encode_decode(5i8, &[5]); + check_dep_encode_decode(5i16, &[0, 5]); + check_dep_encode_decode(5i32, &[0, 0, 0, 5]); + check_dep_encode_decode(5isize, &[0, 0, 0, 5]); + check_dep_encode_decode(5i64, &[0, 0, 0, 0, 0, 0, 0, 5]); + // signed negative + check_dep_encode_decode(-5i8, &[251]); + check_dep_encode_decode(-5i16, &[255, 251]); + check_dep_encode_decode(-5i32, &[255, 255, 255, 251]); + check_dep_encode_decode(-5isize, &[255, 255, 255, 251]); + check_dep_encode_decode(-5i64, &[255, 255, 255, 255, 255, 255, 255, 251]); + } +} diff --git a/elrond-codec/src/impl_for_types/impl_num_unsigned.rs b/elrond-codec/src/impl_for_types/impl_num_unsigned.rs new file mode 100644 index 0000000000..dcfa9744f2 --- /dev/null +++ b/elrond-codec/src/impl_for_types/impl_num_unsigned.rs @@ -0,0 +1,172 @@ +use crate::num_conv::bytes_to_number; +use crate::{ + dep_encode_from_no_err, dep_encode_num_mimic, top_encode_from_no_err, top_ser::TopEncodeNoErr, + DecodeError, EncodeError, NestedDecode, NestedDecodeInput, NestedEncode, NestedEncodeNoErr, + NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, TypeInfo, +}; + +// No reversing needed for u8, because it is a single byte. +impl NestedEncodeNoErr for u8 { + fn dep_encode_no_err(&self, dest: &mut O) { + dest.push_byte(*self as u8); + } +} +dep_encode_from_no_err! {u8, TypeInfo::U8} + +dep_encode_num_mimic! {usize, u32, TypeInfo::USIZE} + +// The main unsigned types need to be reversed before serializing. +macro_rules! dep_encode_num_unsigned { + ($num_type:ty, $size_in_bits:expr, $type_info:expr) => { + impl NestedEncodeNoErr for $num_type { + #[inline(never)] + fn dep_encode_no_err(&self, dest: &mut O) { + dest.write(&self.to_be_bytes()[..]); + } + } + + dep_encode_from_no_err! {$num_type, $type_info} + }; +} + +dep_encode_num_unsigned! {u64, 64, TypeInfo::U64} +dep_encode_num_unsigned! {u32, 32, TypeInfo::U32} +dep_encode_num_unsigned! {u16, 16, TypeInfo::U16} + +macro_rules! top_encode_num_unsigned { + ($num_type:ty, $size_in_bits:expr, $type_info:expr) => { + impl TopEncodeNoErr for $num_type { + #[inline] + fn top_encode_no_err(&self, output: O) { + output.set_u64(*self as u64); + } + } + top_encode_from_no_err! {$num_type, $type_info} + }; +} + +top_encode_num_unsigned! {u64, 64, TypeInfo::U64} +top_encode_num_unsigned! {u32, 32, TypeInfo::U32} +top_encode_num_unsigned! {usize, 32, TypeInfo::USIZE} +top_encode_num_unsigned! {u16, 16, TypeInfo::U16} +top_encode_num_unsigned! {u8, 8, TypeInfo::U8} + +impl NestedDecode for u8 { + const TYPE_INFO: TypeInfo = TypeInfo::U8; + + fn dep_decode(input: &mut I) -> Result { + input.read_byte() + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + input.read_byte_or_exit(c, exit) + } +} + +macro_rules! dep_decode_num_unsigned { + ($ty:ty, $num_bytes:expr, $type_info:expr) => { + impl NestedDecode for $ty { + const TYPE_INFO: TypeInfo = $type_info; + + fn dep_decode(input: &mut I) -> Result { + let bytes = input.read_slice($num_bytes)?; + let num = bytes_to_number(bytes, false) as $ty; + Ok(num) + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + let bytes = input.read_slice_or_exit($num_bytes, c, exit); + let num = bytes_to_number(bytes, false) as $ty; + num + } + } + }; +} + +dep_decode_num_unsigned!(u16, 2, TypeInfo::U16); +dep_decode_num_unsigned!(u32, 4, TypeInfo::U32); +dep_decode_num_unsigned!(usize, 4, TypeInfo::USIZE); +dep_decode_num_unsigned!(u64, 8, TypeInfo::U64); + +macro_rules! top_decode_num_unsigned { + ($ty:ty, $bounds_ty:ty, $type_info:expr) => { + impl TopDecode for $ty { + const TYPE_INFO: TypeInfo = $type_info; + + fn top_decode(input: I) -> Result { + let arg_u64 = input.into_u64(); + let max = <$bounds_ty>::MAX as u64; + if arg_u64 > max { + Err(DecodeError::INPUT_TOO_LONG) + } else { + Ok(arg_u64 as $ty) + } + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + let arg_u64 = input.into_u64(); + let max = <$bounds_ty>::MAX as u64; + if arg_u64 > max { + exit(c, DecodeError::INPUT_TOO_LONG) + } else { + arg_u64 as $ty + } + } + } + }; +} + +top_decode_num_unsigned!(u8, u8, TypeInfo::U8); +top_decode_num_unsigned!(u16, u16, TypeInfo::U16); +top_decode_num_unsigned!(u32, u32, TypeInfo::U32); +top_decode_num_unsigned!(usize, u32, TypeInfo::USIZE); // even if usize can be 64 bits on some platforms, we always deserialize as max 32 bits +top_decode_num_unsigned!(u64, u64, TypeInfo::U64); + +#[cfg(test)] +pub mod tests { + use crate::test_util::{check_dep_encode_decode, check_top_encode_decode}; + + #[test] + fn test_top() { + // unsigned zero + check_top_encode_decode(0u8, &[]); + check_top_encode_decode(0u16, &[]); + check_top_encode_decode(0u32, &[]); + check_top_encode_decode(0u64, &[]); + check_top_encode_decode(0usize, &[]); + // unsigned positive + check_top_encode_decode(5u8, &[5]); + check_top_encode_decode(5u16, &[5]); + check_top_encode_decode(5u32, &[5]); + check_top_encode_decode(5u64, &[5]); + check_top_encode_decode(5usize, &[5]); + } + + #[test] + fn test_dep() { + // unsigned zero + check_dep_encode_decode(0u8, &[0]); + check_dep_encode_decode(0u16, &[0, 0]); + check_dep_encode_decode(0u32, &[0, 0, 0, 0]); + check_dep_encode_decode(0usize, &[0, 0, 0, 0]); + check_dep_encode_decode(0u64, &[0, 0, 0, 0, 0, 0, 0, 0]); + // unsigned positive + check_dep_encode_decode(5u8, &[5]); + check_dep_encode_decode(5u16, &[0, 5]); + check_dep_encode_decode(5u32, &[0, 0, 0, 5]); + check_dep_encode_decode(5usize, &[0, 0, 0, 5]); + check_dep_encode_decode(5u64, &[0, 0, 0, 0, 0, 0, 0, 5]); + } +} diff --git a/elrond-codec/src/impl_for_types/impl_numbers.rs b/elrond-codec/src/impl_for_types/impl_numbers.rs deleted file mode 100644 index 13986c5584..0000000000 --- a/elrond-codec/src/impl_for_types/impl_numbers.rs +++ /dev/null @@ -1,59 +0,0 @@ -#[cfg(test)] -pub mod tests { - use crate::test_util::{check_dep_encode_decode, check_top_encode_decode}; - use core::num::NonZeroUsize; - - #[test] - fn test_top() { - // zero - check_top_encode_decode(0u8, &[]); - check_top_encode_decode(0u16, &[]); - check_top_encode_decode(0u32, &[]); - check_top_encode_decode(0u64, &[]); - check_top_encode_decode(0usize, &[]); - // unsigned positive - check_top_encode_decode(5u8, &[5]); - check_top_encode_decode(5u16, &[5]); - check_top_encode_decode(5u32, &[5]); - check_top_encode_decode(5u64, &[5]); - check_top_encode_decode(5usize, &[5]); - // signed positive - check_top_encode_decode(5i8, &[5]); - check_top_encode_decode(5i16, &[5]); - check_top_encode_decode(5i32, &[5]); - check_top_encode_decode(5i64, &[5]); - check_top_encode_decode(5isize, &[5]); - // signed negative - check_top_encode_decode(-5i8, &[251]); - check_top_encode_decode(-5i16, &[251]); - check_top_encode_decode(-5i32, &[251]); - check_top_encode_decode(-5i64, &[251]); - check_top_encode_decode(-5isize, &[251]); - // non zero usize - check_top_encode_decode(NonZeroUsize::new(5).unwrap(), &[5]); - } - - #[test] - fn test_dep() { - // unsigned positive - check_dep_encode_decode(5u8, &[5]); - check_dep_encode_decode(5u16, &[0, 5]); - check_dep_encode_decode(5u32, &[0, 0, 0, 5]); - check_dep_encode_decode(5usize, &[0, 0, 0, 5]); - check_dep_encode_decode(5u64, &[0, 0, 0, 0, 0, 0, 0, 5]); - // signed positive - check_dep_encode_decode(5i8, &[5]); - check_dep_encode_decode(5i16, &[0, 5]); - check_dep_encode_decode(5i32, &[0, 0, 0, 5]); - check_dep_encode_decode(5isize, &[0, 0, 0, 5]); - check_dep_encode_decode(5i64, &[0, 0, 0, 0, 0, 0, 0, 5]); - // signed negative - check_dep_encode_decode(-5i8, &[251]); - check_dep_encode_decode(-5i16, &[255, 251]); - check_dep_encode_decode(-5i32, &[255, 255, 255, 251]); - check_dep_encode_decode(-5isize, &[255, 255, 255, 251]); - check_dep_encode_decode(-5i64, &[255, 255, 255, 255, 255, 255, 255, 251]); - // non zero usize - check_dep_encode_decode(NonZeroUsize::new(5).unwrap(), &[0, 0, 0, 5]); - } -} diff --git a/elrond-codec/src/impl_for_types/impl_option.rs b/elrond-codec/src/impl_for_types/impl_option.rs index 89efa0dd78..dd907bb3b4 100644 --- a/elrond-codec/src/impl_for_types/impl_option.rs +++ b/elrond-codec/src/impl_for_types/impl_option.rs @@ -1,3 +1,135 @@ +use crate::codec_err::{DecodeError, EncodeError}; +use crate::nested_de::NestedDecode; +use crate::nested_de_input::NestedDecodeInput; +use crate::nested_ser::NestedEncode; +use crate::nested_ser_output::NestedEncodeOutput; +use crate::top_de::TopDecode; +use crate::top_de_input::TopDecodeInput; +use crate::top_ser::TopEncode; +use crate::top_ser_output::TopEncodeOutput; +use crate::{dep_decode_from_byte_slice, dep_decode_from_byte_slice_or_exit}; +use alloc::vec::Vec; + +impl NestedEncode for Option { + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + match self { + Some(v) => { + dest.push_byte(1u8); + v.dep_encode(dest) + }, + None => { + dest.push_byte(0u8); + Ok(()) + }, + } + } + + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + match self { + Some(v) => { + dest.push_byte(1u8); + v.dep_encode_or_exit(dest, c, exit); + }, + None => { + dest.push_byte(0u8); + }, + } + } +} + +impl NestedDecode for Option { + fn dep_decode(input: &mut I) -> Result { + match input.read_byte()? { + 0 => Ok(None), + 1 => Ok(Some(T::dep_decode(input)?)), + _ => Err(DecodeError::INVALID_VALUE), + } + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + match input.read_byte_or_exit(c.clone(), exit) { + 0 => None, + 1 => Some(T::dep_decode_or_exit(input, c, exit)), + _ => exit(c, DecodeError::INVALID_VALUE), + } + } +} + +impl TopEncode for Option { + /// Allow None to be serialized to empty bytes, but leave the leading "1" for Some, + /// to allow disambiguation between e.g. Some(0) and None. + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + match self { + Some(v) => { + let mut buffer = Vec::::new(); + buffer.push_byte(1u8); + v.dep_encode(&mut buffer)?; + output.set_slice_u8(&buffer[..]); + }, + None => { + output.set_slice_u8(&[]); + }, + } + Ok(()) + } + + /// Allow None to be serialized to empty bytes, but leave the leading "1" for Some, + /// to allow disambiguation between e.g. Some(0) and None. + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + match self { + Some(v) => { + let mut buffer = Vec::::new(); + buffer.push_byte(1u8); + v.dep_encode_or_exit(&mut buffer, c, exit); + output.set_slice_u8(&buffer[..]); + }, + None => { + output.set_slice_u8(&[]); + }, + } + } +} + +impl TopDecode for Option { + fn top_decode(input: I) -> Result { + let bytes = input.into_boxed_slice_u8(); + if bytes.is_empty() { + Ok(None) + } else { + let item = dep_decode_from_byte_slice::(&bytes[1..])?; + Ok(Some(item)) + } + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + let bytes = input.into_boxed_slice_u8(); + if bytes.is_empty() { + None + } else { + let item = dep_decode_from_byte_slice_or_exit(&bytes[1..], c, exit); + Some(item) + } + } +} + #[cfg(test)] pub mod tests { use alloc::vec::Vec; diff --git a/elrond-codec/src/impl_for_types/impl_ref.rs b/elrond-codec/src/impl_for_types/impl_ref.rs new file mode 100644 index 0000000000..7454054a16 --- /dev/null +++ b/elrond-codec/src/impl_for_types/impl_ref.rs @@ -0,0 +1,99 @@ +use crate::{ + DecodeError, EncodeError, NestedDecode, NestedDecodeInput, NestedEncode, NestedEncodeOutput, + TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, +}; +use alloc::boxed::Box; + +impl TopEncode for &T { + #[inline] + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + (*self).top_encode(output) + } + + #[inline] + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + (*self).top_encode_or_exit(output, c, exit); + } +} + +impl TopEncode for Box { + #[inline] + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + self.as_ref().top_encode(output) + } + + #[inline] + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_ref().top_encode_or_exit(output, c, exit); + } +} + +impl TopDecode for Box { + fn top_decode(input: I) -> Result { + T::top_decode_boxed(input) + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + T::top_decode_boxed_or_exit(input, c, exit) + } +} + +impl NestedEncode for &T { + #[inline] + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + (*self).dep_encode(dest) + } + + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + (*self).dep_encode_or_exit(dest, c, exit); + } +} + +impl NestedEncode for Box { + #[inline(never)] + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + self.as_ref().dep_encode(dest) + } + + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_ref().dep_encode_or_exit(dest, c, exit); + } +} + +impl NestedDecode for Box { + fn dep_decode(input: &mut I) -> Result { + Ok(Box::new(T::dep_decode(input)?)) + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + Box::new(T::dep_decode_or_exit(input, c, exit)) + } +} diff --git a/elrond-codec/src/impl_for_types/impl_slice.rs b/elrond-codec/src/impl_for_types/impl_slice.rs new file mode 100644 index 0000000000..9a34b5a365 --- /dev/null +++ b/elrond-codec/src/impl_for_types/impl_slice.rs @@ -0,0 +1,194 @@ +use crate::codec_err::{DecodeError, EncodeError}; +use crate::nested_de::NestedDecode; +use crate::nested_ser::NestedEncode; +use crate::nested_ser_output::NestedEncodeOutput; +use crate::top_de::TopDecode; +use crate::top_de_input::TopDecodeInput; +use crate::top_ser::TopEncode; +use crate::top_ser_output::TopEncodeOutput; +use crate::{vec_into_boxed_slice, TypeInfo}; +use alloc::boxed::Box; +use alloc::vec::Vec; + +/// Adds the concantenated encoded contents of a slice to an output buffer, +/// without serializing the slice length. +/// Byte slice is treated separately, via direct transmute. +pub fn dep_encode_slice_contents( + slice: &[T], + dest: &mut O, +) -> Result<(), EncodeError> { + match T::TYPE_INFO { + TypeInfo::U8 => { + // cast &[T] to &[u8] + let slice: &[u8] = + unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) }; + dest.write(slice); + }, + _ => { + for x in slice { + x.dep_encode(dest)?; + } + }, + } + Ok(()) +} + +pub fn dep_encode_slice_contents_or_exit( + slice: &[T], + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, +) where + T: NestedEncode, + O: NestedEncodeOutput, + ExitCtx: Clone, +{ + match T::TYPE_INFO { + TypeInfo::U8 => { + // cast &[T] to &[u8] + let slice: &[u8] = + unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) }; + dest.write(slice); + }, + _ => { + for x in slice { + x.dep_encode_or_exit(dest, c.clone(), exit); + } + }, + } +} + +impl TopEncode for &[T] { + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + match T::TYPE_INFO { + TypeInfo::U8 => { + // transmute to &[u8] + // save directly, without passing through the buffer + let slice: &[u8] = + unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) }; + output.set_slice_u8(slice); + }, + _ => { + // only using `dep_encode_slice_contents` for non-u8, + // because it always appends to the buffer, + // which is not necessary above + let mut buffer = Vec::::new(); + dep_encode_slice_contents(self, &mut buffer)?; + output.set_slice_u8(&buffer[..]); + }, + } + Ok(()) + } + + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + match T::TYPE_INFO { + TypeInfo::U8 => { + // transmute to &[u8] + // save directly, without passing through the buffer + let slice: &[u8] = + unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) }; + output.set_slice_u8(slice); + }, + _ => { + // only using `dep_encode_slice_contents` for non-u8, + // because it always appends to the buffer, + // which is not necessary above + let mut buffer = Vec::::new(); + for x in *self { + x.dep_encode_or_exit(&mut buffer, c.clone(), exit); + } + output.set_slice_u8(&buffer[..]); + }, + } + } +} + +impl TopEncode for Box<[T]> { + #[inline] + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + self.as_ref().top_encode(output) + } + + #[inline] + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_ref().top_encode_or_exit(output, c, exit); + } +} + +// Allowed to implement this because [T] cannot implement NestedDecode, being ?Sized. +impl TopDecode for Box<[T]> { + fn top_decode(input: I) -> Result { + if let TypeInfo::U8 = T::TYPE_INFO { + let bytes = input.into_boxed_slice_u8(); + let cast_bytes: Box<[T]> = unsafe { core::mem::transmute(bytes) }; + Ok(cast_bytes) + } else { + let vec = Vec::::top_decode(input)?; + Ok(vec_into_boxed_slice(vec)) + } + } + + /// Quick exit for any of the contained types + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + if let TypeInfo::U8 = T::TYPE_INFO { + let bytes = input.into_boxed_slice_u8(); + let cast_bytes: Box<[T]> = unsafe { core::mem::transmute(bytes) }; + cast_bytes + } else { + let vec = Vec::::top_decode_or_exit(input, c, exit); + vec_into_boxed_slice(vec) + } + } +} + +impl NestedEncode for &[T] { + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + // push size + self.len().dep_encode(dest)?; + // actual data + dep_encode_slice_contents(self, dest) + } + + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + // push size + self.len().dep_encode_or_exit(dest, c.clone(), exit); + // actual data + dep_encode_slice_contents_or_exit(self, dest, c, exit); + } +} + +impl NestedEncode for Box<[T]> { + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + self.as_ref().dep_encode(dest) + } + + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_ref().dep_encode_or_exit(dest, c, exit); + } +} + +// TODO: NestedDecode for Box<[T]> missing diff --git a/elrond-codec/src/impl_for_types/impl_string.rs b/elrond-codec/src/impl_for_types/impl_string.rs index 90d47ab7d4..8f4164951a 100644 --- a/elrond-codec/src/impl_for_types/impl_string.rs +++ b/elrond-codec/src/impl_for_types/impl_string.rs @@ -1,3 +1,189 @@ +use crate::codec_err::{DecodeError, EncodeError}; +use crate::nested_de::NestedDecode; +use crate::nested_de_input::NestedDecodeInput; +use crate::nested_ser::NestedEncode; +use crate::nested_ser_output::NestedEncodeOutput; +use crate::top_de::TopDecode; +use crate::top_de_input::TopDecodeInput; +use crate::top_ser::TopEncode; +use crate::top_ser_output::TopEncodeOutput; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; + +impl TopEncode for String { + #[inline] + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + self.as_bytes().top_encode(output) + } + + #[inline] + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_bytes().top_encode_or_exit(output, c, exit); + } +} + +impl TopEncode for &str { + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + output.set_slice_u8(self.as_bytes()); + Ok(()) + } + + fn top_encode_or_exit( + &self, + output: O, + _: ExitCtx, + _: fn(ExitCtx, EncodeError) -> !, + ) { + output.set_slice_u8(self.as_bytes()); + } +} + +impl TopEncode for Box { + #[inline] + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + self.as_ref().as_bytes().top_encode(output) + } + + #[inline] + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_ref().as_bytes().top_encode_or_exit(output, c, exit); + } +} + +impl TopDecode for String { + fn top_decode(input: I) -> Result { + let raw = Vec::::top_decode(input)?; + match String::from_utf8(raw) { + Ok(s) => Ok(s), + Err(_) => Err(DecodeError::UTF8_DECODE_ERROR), + } + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + let raw = Vec::::top_decode_or_exit(input, c.clone(), exit); + match String::from_utf8(raw) { + Ok(s) => s, + Err(_) => exit(c, DecodeError::UTF8_DECODE_ERROR), + } + } +} + +impl TopDecode for Box { + fn top_decode(input: I) -> Result { + Ok(String::top_decode(input)?.into_boxed_str()) + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + String::top_decode_or_exit(input, c, exit).into_boxed_str() + } +} + +impl NestedEncode for String { + #[inline] + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + self.as_bytes().dep_encode(dest) + } + + #[inline] + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_bytes().dep_encode_or_exit(dest, c, exit); + } +} + +impl NestedEncode for &str { + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + self.as_bytes().dep_encode(dest) + } + + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_bytes().dep_encode_or_exit(dest, c, exit); + } +} + +impl NestedEncode for Box { + #[inline] + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + self.as_ref().as_bytes().dep_encode(dest) + } + + #[inline] + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_ref().as_bytes().dep_encode_or_exit(dest, c, exit); + } +} + +impl NestedDecode for String { + fn dep_decode(input: &mut I) -> Result { + let raw = Vec::::dep_decode(input)?; + match String::from_utf8(raw) { + Ok(s) => Ok(s), + Err(_) => Err(DecodeError::UTF8_DECODE_ERROR), + } + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + let raw = Vec::::dep_decode_or_exit(input, c.clone(), exit); + match String::from_utf8(raw) { + Ok(s) => s, + Err(_) => exit(c, DecodeError::UTF8_DECODE_ERROR), + } + } +} + +impl NestedDecode for Box { + #[inline] + fn dep_decode(input: &mut I) -> Result { + Ok(String::dep_decode(input)?.into_boxed_str()) + } + + #[inline] + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + String::dep_decode_or_exit(input, c, exit).into_boxed_str() + } +} + #[cfg(test)] mod tests { use crate::test_util::{check_dep_encode_decode, check_top_encode_decode}; diff --git a/elrond-codec/src/impl_for_types/impl_top_encode_from_no_err.rs b/elrond-codec/src/impl_for_types/impl_top_encode_from_no_err.rs deleted file mode 100644 index e119fdef93..0000000000 --- a/elrond-codec/src/impl_for_types/impl_top_encode_from_no_err.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[macro_export] -macro_rules! top_encode_from_no_err { - ($type:ty, $type_info:expr) => { - impl TopEncode for $type { - const TYPE_INFO: TypeInfo = $type_info; - - #[inline] - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - self.top_encode_no_err(output); - Ok(()) - } - - #[inline] - fn top_encode_or_exit( - &self, - output: O, - _: ExitCtx, - _: fn(ExitCtx, EncodeError) -> !, - ) { - self.top_encode_no_err(output); - } - } - }; -} diff --git a/elrond-codec/src/impl_for_types/impl_unit.rs b/elrond-codec/src/impl_for_types/impl_unit.rs new file mode 100644 index 0000000000..e56f5cd9ae --- /dev/null +++ b/elrond-codec/src/impl_for_types/impl_unit.rs @@ -0,0 +1,51 @@ +use crate::{ + dep_encode_from_no_err, nested_ser::NestedEncodeNoErr, top_encode_from_no_err, + top_ser::TopEncodeNoErr, DecodeError, EncodeError, NestedDecode, NestedDecodeInput, + NestedEncode, NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, + TypeInfo, +}; + +impl TopEncodeNoErr for () { + #[inline] + fn top_encode_no_err(&self, output: O) { + output.set_unit(); + } +} + +top_encode_from_no_err! {(), TypeInfo::Unit} + +impl TopDecode for () { + const TYPE_INFO: TypeInfo = TypeInfo::Unit; + + fn top_decode(_: I) -> Result { + Ok(()) + } + + fn top_decode_or_exit( + _: I, + _: ExitCtx, + _: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + } +} + +impl NestedEncodeNoErr for () { + fn dep_encode_no_err(&self, _: &mut O) {} +} + +dep_encode_from_no_err! {(), TypeInfo::Unit} + +impl NestedDecode for () { + const TYPE_INFO: TypeInfo = TypeInfo::Unit; + + fn dep_decode(_: &mut I) -> Result<(), DecodeError> { + Ok(()) + } + + fn dep_decode_or_exit( + _: &mut I, + _: ExitCtx, + _: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + } +} diff --git a/elrond-codec/src/impl_for_types/impl_vec.rs b/elrond-codec/src/impl_for_types/impl_vec.rs index f619fd28da..85b14c8fa1 100644 --- a/elrond-codec/src/impl_for_types/impl_vec.rs +++ b/elrond-codec/src/impl_for_types/impl_vec.rs @@ -1,6 +1,135 @@ +use crate::codec_err::{DecodeError, EncodeError}; +use crate::nested_de::NestedDecode; +use crate::nested_de_input::NestedDecodeInput; +use crate::nested_ser::NestedEncode; +use crate::nested_ser_output::NestedEncodeOutput; +use crate::top_de::TopDecode; +use crate::top_de_input::TopDecodeInput; +use crate::top_ser::TopEncode; +use crate::top_ser_output::TopEncodeOutput; +use crate::{boxed_slice_into_vec, TypeInfo}; +use alloc::vec::Vec; + +impl TopEncode for Vec { + #[inline] + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + self.as_slice().top_encode(output) + } + + #[inline] + fn top_encode_or_exit( + &self, + output: O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_slice().top_encode_or_exit(output, c, exit); + } +} + +impl TopDecode for Vec { + fn top_decode(input: I) -> Result { + if let TypeInfo::U8 = T::TYPE_INFO { + let bytes = input.into_boxed_slice_u8(); + let bytes_vec = boxed_slice_into_vec(bytes); + let cast_vec: Vec = unsafe { core::mem::transmute(bytes_vec) }; + Ok(cast_vec) + } else { + let bytes = input.into_boxed_slice_u8(); + let mut_slice = &mut &*bytes; + let mut result: Vec = Vec::new(); + while !mut_slice.is_empty() { + result.push(T::dep_decode(mut_slice)?); + } + Ok(result) + } + } + + fn top_decode_or_exit( + input: I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + if let TypeInfo::U8 = T::TYPE_INFO { + let bytes = input.into_boxed_slice_u8(); + let bytes_vec = boxed_slice_into_vec(bytes); + let cast_vec: Vec = unsafe { core::mem::transmute(bytes_vec) }; + cast_vec + } else { + let bytes = input.into_boxed_slice_u8(); + let mut_slice = &mut &*bytes; + let mut result: Vec = Vec::new(); + while !mut_slice.is_empty() { + result.push(T::dep_decode_or_exit(mut_slice, c.clone(), exit)); + } + result + } + } +} + +impl NestedEncode for Vec { + #[inline] + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + self.as_slice().dep_encode(dest) + } + + #[inline] + fn dep_encode_or_exit( + &self, + dest: &mut O, + c: ExitCtx, + exit: fn(ExitCtx, EncodeError) -> !, + ) { + self.as_slice().dep_encode_or_exit(dest, c, exit); + } +} + +impl NestedDecode for Vec { + fn dep_decode(input: &mut I) -> Result { + let size = usize::dep_decode(input)?; + match T::TYPE_INFO { + TypeInfo::U8 => { + let bytes = input.read_slice(size)?; + let bytes_copy = bytes.to_vec(); // copy is needed because result might outlive input + let cast_vec: Vec = unsafe { core::mem::transmute(bytes_copy) }; + Ok(cast_vec) + }, + _ => { + let mut result: Vec = Vec::with_capacity(size); + for _ in 0..size { + result.push(T::dep_decode(input)?); + } + Ok(result) + }, + } + } + + fn dep_decode_or_exit( + input: &mut I, + c: ExitCtx, + exit: fn(ExitCtx, DecodeError) -> !, + ) -> Self { + let size = usize::dep_decode_or_exit(input, c.clone(), exit); + match T::TYPE_INFO { + TypeInfo::U8 => { + let bytes = input.read_slice_or_exit(size, c, exit); + let bytes_copy = bytes.to_vec(); // copy is needed because result might outlive input + let cast_vec: Vec = unsafe { core::mem::transmute(bytes_copy) }; + cast_vec + }, + _ => { + let mut result: Vec = Vec::with_capacity(size); + for _ in 0..size { + result.push(T::dep_decode_or_exit(input, c.clone(), exit)); + } + result + }, + } + } +} + #[cfg(test)] pub mod tests { - use crate::test_util::check_top_encode_decode; #[test] diff --git a/elrond-codec/src/impl_for_types/local_macro.rs b/elrond-codec/src/impl_for_types/local_macro.rs new file mode 100644 index 0000000000..33550fcd44 --- /dev/null +++ b/elrond-codec/src/impl_for_types/local_macro.rs @@ -0,0 +1,64 @@ +// Derive the implementation of the other types by casting. +#[macro_export] +macro_rules! dep_encode_num_mimic { + ($num_type:ty, $mimic_type:ident, $type_info:expr) => { + impl NestedEncodeNoErr for $num_type { + #[inline] + fn dep_encode_no_err(&self, dest: &mut O) { + (*self as $mimic_type).dep_encode_no_err(dest) + } + } + + dep_encode_from_no_err! {$num_type, $type_info} + }; +} + +#[macro_export] +macro_rules! dep_encode_from_no_err { + ($type:ty, $type_info:expr) => { + impl NestedEncode for $type { + const TYPE_INFO: TypeInfo = $type_info; + + #[inline] + fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { + self.dep_encode_no_err(dest); + Ok(()) + } + + #[inline] + fn dep_encode_or_exit( + &self, + dest: &mut O, + _: ExitCtx, + _: fn(ExitCtx, EncodeError) -> !, + ) { + self.dep_encode_no_err(dest); + } + } + }; +} + +#[macro_export] +macro_rules! top_encode_from_no_err { + ($type:ty, $type_info:expr) => { + impl TopEncode for $type { + const TYPE_INFO: TypeInfo = $type_info; + + #[inline] + fn top_encode(&self, output: O) -> Result<(), EncodeError> { + self.top_encode_no_err(output); + Ok(()) + } + + #[inline] + fn top_encode_or_exit( + &self, + output: O, + _: ExitCtx, + _: fn(ExitCtx, EncodeError) -> !, + ) { + self.top_encode_no_err(output); + } + } + }; +} diff --git a/elrond-codec/src/impl_for_types/mod.rs b/elrond-codec/src/impl_for_types/mod.rs index 6e301329c7..d77d126708 100644 --- a/elrond-codec/src/impl_for_types/mod.rs +++ b/elrond-codec/src/impl_for_types/mod.rs @@ -1,16 +1,15 @@ mod impl_array; mod impl_bool; mod impl_bytes; -mod impl_decode_num_signed; -mod impl_decode_num_unsigned; -mod impl_dep_encode_from_no_err; mod impl_empty; -mod impl_encode_num_mimic; -mod impl_encode_num_signed; -mod impl_encode_num_unsigned; -mod impl_numbers; +mod impl_non_zero_usize; +mod impl_num_signed; +mod impl_num_unsigned; mod impl_option; +mod impl_ref; +mod impl_slice; mod impl_string; -mod impl_top_encode_from_no_err; mod impl_tuple; +mod impl_unit; mod impl_vec; +mod local_macro; diff --git a/elrond-codec/src/nested_de.rs b/elrond-codec/src/nested_de.rs index c22812cd4d..f86f055b70 100644 --- a/elrond-codec/src/nested_de.rs +++ b/elrond-codec/src/nested_de.rs @@ -1,8 +1,3 @@ -use alloc::boxed::Box; -use alloc::string::String; -use alloc::vec::Vec; -use core::num::NonZeroUsize; - use crate::codec_err::DecodeError; use crate::nested_de_input::NestedDecodeInput; use crate::TypeInfo; @@ -59,198 +54,3 @@ pub fn dep_decode_from_byte_slice_or_exit( } result } - -impl NestedDecode for () { - const TYPE_INFO: TypeInfo = TypeInfo::Unit; - - fn dep_decode(_: &mut I) -> Result<(), DecodeError> { - Ok(()) - } - - fn dep_decode_or_exit( - _: &mut I, - _: ExitCtx, - _: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - } -} - -impl NestedDecode for u8 { - const TYPE_INFO: TypeInfo = TypeInfo::U8; - - fn dep_decode(input: &mut I) -> Result { - input.read_byte() - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - input.read_byte_or_exit(c, exit) - } -} - -impl NestedDecode for Vec { - fn dep_decode(input: &mut I) -> Result { - let size = usize::dep_decode(input)?; - match T::TYPE_INFO { - TypeInfo::U8 => { - let bytes = input.read_slice(size)?; - let bytes_copy = bytes.to_vec(); // copy is needed because result might outlive input - let cast_vec: Vec = unsafe { core::mem::transmute(bytes_copy) }; - Ok(cast_vec) - }, - _ => { - let mut result: Vec = Vec::with_capacity(size); - for _ in 0..size { - result.push(T::dep_decode(input)?); - } - Ok(result) - }, - } - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - let size = usize::dep_decode_or_exit(input, c.clone(), exit); - match T::TYPE_INFO { - TypeInfo::U8 => { - let bytes = input.read_slice_or_exit(size, c, exit); - let bytes_copy = bytes.to_vec(); // copy is needed because result might outlive input - let cast_vec: Vec = unsafe { core::mem::transmute(bytes_copy) }; - cast_vec - }, - _ => { - let mut result: Vec = Vec::with_capacity(size); - for _ in 0..size { - result.push(T::dep_decode_or_exit(input, c.clone(), exit)); - } - result - }, - } - } -} - -impl NestedDecode for String { - fn dep_decode(input: &mut I) -> Result { - let raw = Vec::::dep_decode(input)?; - match String::from_utf8(raw) { - Ok(s) => Ok(s), - Err(_) => Err(DecodeError::UTF8_DECODE_ERROR), - } - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - let raw = Vec::::dep_decode_or_exit(input, c.clone(), exit); - match String::from_utf8(raw) { - Ok(s) => s, - Err(_) => exit(c, DecodeError::UTF8_DECODE_ERROR), - } - } -} - -impl NestedDecode for Box { - #[inline] - fn dep_decode(input: &mut I) -> Result { - Ok(String::dep_decode(input)?.into_boxed_str()) - } - - #[inline] - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - String::dep_decode_or_exit(input, c, exit).into_boxed_str() - } -} - -impl NestedDecode for bool { - const TYPE_INFO: TypeInfo = TypeInfo::Bool; - - fn dep_decode(input: &mut I) -> Result { - match input.read_byte()? { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(DecodeError::INVALID_VALUE), - } - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - match input.read_byte_or_exit(c.clone(), exit) { - 0 => false, - 1 => true, - _ => exit(c, DecodeError::INVALID_VALUE), - } - } -} - -impl NestedDecode for Option { - fn dep_decode(input: &mut I) -> Result { - match input.read_byte()? { - 0 => Ok(None), - 1 => Ok(Some(T::dep_decode(input)?)), - _ => Err(DecodeError::INVALID_VALUE), - } - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - match input.read_byte_or_exit(c.clone(), exit) { - 0 => None, - 1 => Some(T::dep_decode_or_exit(input, c, exit)), - _ => exit(c, DecodeError::INVALID_VALUE), - } - } -} - -impl NestedDecode for Box { - fn dep_decode(input: &mut I) -> Result { - Ok(Box::new(T::dep_decode(input)?)) - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - Box::new(T::dep_decode_or_exit(input, c, exit)) - } -} - -impl NestedDecode for NonZeroUsize { - fn dep_decode(input: &mut I) -> Result { - if let Some(nz) = NonZeroUsize::new(usize::dep_decode(input)?) { - Ok(nz) - } else { - Err(DecodeError::INVALID_VALUE) - } - } - - fn dep_decode_or_exit( - input: &mut I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - if let Some(nz) = NonZeroUsize::new(usize::dep_decode_or_exit(input, c.clone(), exit)) { - nz - } else { - exit(c, DecodeError::INVALID_VALUE) - } - } -} diff --git a/elrond-codec/src/nested_ser.rs b/elrond-codec/src/nested_ser.rs index 0d8ead200e..c3de3ad9db 100644 --- a/elrond-codec/src/nested_ser.rs +++ b/elrond-codec/src/nested_ser.rs @@ -1,11 +1,7 @@ -use alloc::boxed::Box; -use alloc::string::String; -use alloc::vec::Vec; -use core::num::NonZeroUsize; - use crate::codec_err::EncodeError; use crate::nested_ser_output::NestedEncodeOutput; use crate::TypeInfo; +use alloc::vec::Vec; /// Most types will be encoded without any possibility of error. /// The trait is used to provide these implementations. @@ -50,245 +46,3 @@ pub fn dep_encode_to_vec(obj: &T) -> Result, EncodeErro obj.dep_encode(&mut bytes)?; Ok(bytes) } - -/// Adds the concantenated encoded contents of a slice to an output buffer, -/// without serializing the slice length. -/// Byte slice is treated separately, via direct transmute. -pub fn dep_encode_slice_contents( - slice: &[T], - dest: &mut O, -) -> Result<(), EncodeError> { - match T::TYPE_INFO { - TypeInfo::U8 => { - // cast &[T] to &[u8] - let slice: &[u8] = - unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) }; - dest.write(slice); - }, - _ => { - for x in slice { - x.dep_encode(dest)?; - } - }, - } - Ok(()) -} - -pub fn dep_encode_slice_contents_or_exit( - slice: &[T], - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, -) where - T: NestedEncode, - O: NestedEncodeOutput, - ExitCtx: Clone, -{ - match T::TYPE_INFO { - TypeInfo::U8 => { - // cast &[T] to &[u8] - let slice: &[u8] = - unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) }; - dest.write(slice); - }, - _ => { - for x in slice { - x.dep_encode_or_exit(dest, c.clone(), exit); - } - }, - } -} - -impl NestedEncodeNoErr for () { - fn dep_encode_no_err(&self, _: &mut O) {} -} - -impl NestedEncode for &[T] { - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - // push size - self.len().dep_encode(dest)?; - // actual data - dep_encode_slice_contents(self, dest) - } - - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - // push size - self.len().dep_encode_or_exit(dest, c.clone(), exit); - // actual data - dep_encode_slice_contents_or_exit(self, dest, c, exit); - } -} - -impl NestedEncode for &T { - #[inline] - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - (*self).dep_encode(dest) - } - - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - (*self).dep_encode_or_exit(dest, c, exit); - } -} - -impl NestedEncode for &str { - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - self.as_bytes().dep_encode(dest) - } - - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_bytes().dep_encode_or_exit(dest, c, exit); - } -} - -impl NestedEncode for Vec { - #[inline] - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - self.as_slice().dep_encode(dest) - } - - #[inline] - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_slice().dep_encode_or_exit(dest, c, exit); - } -} - -impl NestedEncode for String { - #[inline] - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - self.as_bytes().dep_encode(dest) - } - - #[inline] - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_bytes().dep_encode_or_exit(dest, c, exit); - } -} - -impl NestedEncode for Box { - #[inline] - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - self.as_ref().as_bytes().dep_encode(dest) - } - - #[inline] - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_ref().as_bytes().dep_encode_or_exit(dest, c, exit); - } -} - -// No reversing needed for u8, because it is a single byte. -impl NestedEncodeNoErr for u8 { - fn dep_encode_no_err(&self, dest: &mut O) { - dest.push_byte(*self as u8); - } -} - -impl NestedEncode for Option { - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - match self { - Some(v) => { - dest.push_byte(1u8); - v.dep_encode(dest) - }, - None => { - dest.push_byte(0u8); - Ok(()) - }, - } - } - - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - match self { - Some(v) => { - dest.push_byte(1u8); - v.dep_encode_or_exit(dest, c, exit); - }, - None => { - dest.push_byte(0u8); - }, - } - } -} - -impl NestedEncode for Box { - #[inline(never)] - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - self.as_ref().dep_encode(dest) - } - - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_ref().dep_encode_or_exit(dest, c, exit); - } -} - -impl NestedEncode for Box<[T]> { - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - self.as_ref().dep_encode(dest) - } - - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_ref().dep_encode_or_exit(dest, c, exit); - } -} - -impl NestedEncode for NonZeroUsize { - #[inline] - fn dep_encode(&self, dest: &mut O) -> Result<(), EncodeError> { - self.get().dep_encode(dest) - } - - #[inline] - fn dep_encode_or_exit( - &self, - dest: &mut O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.get().dep_encode_or_exit(dest, c, exit); - } -} diff --git a/elrond-codec/src/top_de.rs b/elrond-codec/src/top_de.rs index 17cd867267..de6b211f82 100644 --- a/elrond-codec/src/top_de.rs +++ b/elrond-codec/src/top_de.rs @@ -1,12 +1,8 @@ use alloc::boxed::Box; -use alloc::string::String; -use alloc::vec::Vec; -use core::num::NonZeroUsize; use crate::codec_err::DecodeError; use crate::nested_de::*; use crate::top_de_input::TopDecodeInput; -use crate::transmute::*; use crate::TypeInfo; /// Trait that allows zero-copy read of values from an underlying API in big endian format. @@ -96,210 +92,3 @@ where } result } - -impl TopDecode for () { - const TYPE_INFO: TypeInfo = TypeInfo::Unit; - - fn top_decode(_: I) -> Result { - Ok(()) - } - - fn top_decode_or_exit( - _: I, - _: ExitCtx, - _: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - } -} - -impl TopDecode for Box { - fn top_decode(input: I) -> Result { - T::top_decode_boxed(input) - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - T::top_decode_boxed_or_exit(input, c, exit) - } -} - -// Allowed to implement this because [T] cannot implement NestedDecode, being ?Sized. -impl TopDecode for Box<[T]> { - fn top_decode(input: I) -> Result { - if let TypeInfo::U8 = T::TYPE_INFO { - let bytes = input.into_boxed_slice_u8(); - let cast_bytes: Box<[T]> = unsafe { core::mem::transmute(bytes) }; - Ok(cast_bytes) - } else { - let vec = Vec::::top_decode(input)?; - Ok(vec_into_boxed_slice(vec)) - } - } - - /// Quick exit for any of the contained types - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - if let TypeInfo::U8 = T::TYPE_INFO { - let bytes = input.into_boxed_slice_u8(); - let cast_bytes: Box<[T]> = unsafe { core::mem::transmute(bytes) }; - cast_bytes - } else { - let vec = Vec::::top_decode_or_exit(input, c, exit); - vec_into_boxed_slice(vec) - } - } -} - -impl TopDecode for Vec { - fn top_decode(input: I) -> Result { - if let TypeInfo::U8 = T::TYPE_INFO { - let bytes = input.into_boxed_slice_u8(); - let bytes_vec = boxed_slice_into_vec(bytes); - let cast_vec: Vec = unsafe { core::mem::transmute(bytes_vec) }; - Ok(cast_vec) - } else { - let bytes = input.into_boxed_slice_u8(); - let mut_slice = &mut &*bytes; - let mut result: Vec = Vec::new(); - while !mut_slice.is_empty() { - result.push(T::dep_decode(mut_slice)?); - } - Ok(result) - } - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - if let TypeInfo::U8 = T::TYPE_INFO { - let bytes = input.into_boxed_slice_u8(); - let bytes_vec = boxed_slice_into_vec(bytes); - let cast_vec: Vec = unsafe { core::mem::transmute(bytes_vec) }; - cast_vec - } else { - let bytes = input.into_boxed_slice_u8(); - let mut_slice = &mut &*bytes; - let mut result: Vec = Vec::new(); - while !mut_slice.is_empty() { - result.push(T::dep_decode_or_exit(mut_slice, c.clone(), exit)); - } - result - } - } -} - -impl TopDecode for String { - fn top_decode(input: I) -> Result { - let raw = Vec::::top_decode(input)?; - match String::from_utf8(raw) { - Ok(s) => Ok(s), - Err(_) => Err(DecodeError::UTF8_DECODE_ERROR), - } - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - let raw = Vec::::top_decode_or_exit(input, c.clone(), exit); - match String::from_utf8(raw) { - Ok(s) => s, - Err(_) => exit(c, DecodeError::UTF8_DECODE_ERROR), - } - } -} - -impl TopDecode for Box { - fn top_decode(input: I) -> Result { - Ok(String::top_decode(input)?.into_boxed_str()) - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - String::top_decode_or_exit(input, c, exit).into_boxed_str() - } -} - -impl TopDecode for bool { - const TYPE_INFO: TypeInfo = TypeInfo::Bool; - - fn top_decode(input: I) -> Result { - match input.into_u64() { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(DecodeError::INPUT_OUT_OF_RANGE), - } - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - match input.into_u64() { - 0 => false, - 1 => true, - _ => exit(c, DecodeError::INPUT_OUT_OF_RANGE), - } - } -} - -impl TopDecode for Option { - fn top_decode(input: I) -> Result { - let bytes = input.into_boxed_slice_u8(); - if bytes.is_empty() { - Ok(None) - } else { - let item = dep_decode_from_byte_slice::(&bytes[1..])?; - Ok(Some(item)) - } - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - let bytes = input.into_boxed_slice_u8(); - if bytes.is_empty() { - None - } else { - let item = dep_decode_from_byte_slice_or_exit(&bytes[1..], c, exit); - Some(item) - } - } -} - -impl TopDecode for NonZeroUsize { - fn top_decode(input: I) -> Result { - if let Some(nz) = NonZeroUsize::new(usize::top_decode(input)?) { - Ok(nz) - } else { - Err(DecodeError::INVALID_VALUE) - } - } - - fn top_decode_or_exit( - input: I, - c: ExitCtx, - exit: fn(ExitCtx, DecodeError) -> !, - ) -> Self { - if let Some(nz) = NonZeroUsize::new(usize::top_decode_or_exit(input, c.clone(), exit)) { - nz - } else { - exit(c, DecodeError::INVALID_VALUE) - } - } -} diff --git a/elrond-codec/src/top_ser.rs b/elrond-codec/src/top_ser.rs index 968490f0be..3a606d5be1 100644 --- a/elrond-codec/src/top_ser.rs +++ b/elrond-codec/src/top_ser.rs @@ -1,13 +1,8 @@ use crate::codec_err::EncodeError; -use crate::nested_ser::{dep_encode_slice_contents, NestedEncode}; -use crate::nested_ser_output::NestedEncodeOutput; -use crate::top_encode_from_no_err; +use crate::nested_ser::NestedEncode; use crate::top_ser_output::TopEncodeOutput; use crate::TypeInfo; -use alloc::boxed::Box; -use alloc::string::String; use alloc::vec::Vec; -use core::num::NonZeroUsize; /// Most types will be encoded without any possibility of error. /// The trait is used to provide these implementations. @@ -78,245 +73,3 @@ pub fn top_encode_to_vec(obj: &T) -> Result, EncodeError> obj.top_encode(&mut bytes)?; Ok(bytes) } - -impl TopEncodeNoErr for () { - #[inline] - fn top_encode_no_err(&self, output: O) { - output.set_unit(); - } -} - -top_encode_from_no_err! {(), TypeInfo::Unit} - -impl TopEncode for &[T] { - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - match T::TYPE_INFO { - TypeInfo::U8 => { - // transmute to &[u8] - // save directly, without passing through the buffer - let slice: &[u8] = - unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) }; - output.set_slice_u8(slice); - }, - _ => { - // only using `dep_encode_slice_contents` for non-u8, - // because it always appends to the buffer, - // which is not necessary above - let mut buffer = Vec::::new(); - dep_encode_slice_contents(self, &mut buffer)?; - output.set_slice_u8(&buffer[..]); - }, - } - Ok(()) - } - - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - match T::TYPE_INFO { - TypeInfo::U8 => { - // transmute to &[u8] - // save directly, without passing through the buffer - let slice: &[u8] = - unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) }; - output.set_slice_u8(slice); - }, - _ => { - // only using `dep_encode_slice_contents` for non-u8, - // because it always appends to the buffer, - // which is not necessary above - let mut buffer = Vec::::new(); - for x in *self { - x.dep_encode_or_exit(&mut buffer, c.clone(), exit); - } - output.set_slice_u8(&buffer[..]); - }, - } - } -} - -impl TopEncode for &T { - #[inline] - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - (*self).top_encode(output) - } - - #[inline] - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - (*self).top_encode_or_exit(output, c, exit); - } -} - -impl TopEncode for &str { - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - output.set_slice_u8(self.as_bytes()); - Ok(()) - } - - fn top_encode_or_exit( - &self, - output: O, - _: ExitCtx, - _: fn(ExitCtx, EncodeError) -> !, - ) { - output.set_slice_u8(self.as_bytes()); - } -} - -impl TopEncode for Vec { - #[inline] - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - self.as_slice().top_encode(output) - } - - #[inline] - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_slice().top_encode_or_exit(output, c, exit); - } -} - -impl TopEncode for String { - #[inline] - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - self.as_bytes().top_encode(output) - } - - #[inline] - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_bytes().top_encode_or_exit(output, c, exit); - } -} - -impl TopEncode for Box { - #[inline] - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - self.as_ref().as_bytes().top_encode(output) - } - - #[inline] - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_ref().as_bytes().top_encode_or_exit(output, c, exit); - } -} - -impl TopEncodeNoErr for bool { - fn top_encode_no_err(&self, output: O) { - // only using signed because this one is implemented in Arwen, unsigned is not - // TODO: change to set_u64 - output.set_i64(if *self { 1i64 } else { 0i64 }); - } -} - -top_encode_from_no_err! {bool, TypeInfo::Bool} - -impl TopEncode for Option { - /// Allow None to be serialized to empty bytes, but leave the leading "1" for Some, - /// to allow disambiguation between e.g. Some(0) and None. - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - match self { - Some(v) => { - let mut buffer = Vec::::new(); - buffer.push_byte(1u8); - v.dep_encode(&mut buffer)?; - output.set_slice_u8(&buffer[..]); - }, - None => { - output.set_slice_u8(&[]); - }, - } - Ok(()) - } - - /// Allow None to be serialized to empty bytes, but leave the leading "1" for Some, - /// to allow disambiguation between e.g. Some(0) and None. - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - match self { - Some(v) => { - let mut buffer = Vec::::new(); - buffer.push_byte(1u8); - v.dep_encode_or_exit(&mut buffer, c, exit); - output.set_slice_u8(&buffer[..]); - }, - None => { - output.set_slice_u8(&[]); - }, - } - } -} - -impl TopEncode for Box { - #[inline] - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - self.as_ref().top_encode(output) - } - - #[inline] - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_ref().top_encode_or_exit(output, c, exit); - } -} - -impl TopEncode for Box<[T]> { - #[inline] - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - self.as_ref().top_encode(output) - } - - #[inline] - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.as_ref().top_encode_or_exit(output, c, exit); - } -} - -impl TopEncode for NonZeroUsize { - fn top_encode(&self, output: O) -> Result<(), EncodeError> { - self.get().top_encode(output) - } - - fn top_encode_or_exit( - &self, - output: O, - c: ExitCtx, - exit: fn(ExitCtx, EncodeError) -> !, - ) { - self.get().top_encode_or_exit(output, c, exit); - } -}