From 0841cc48bc14d2573cb7a8de8b2d342db362ee62 Mon Sep 17 00:00:00 2001 From: wigy <1888808+wigy-opensource-developer@users.noreply.github.com> Date: Thu, 3 Feb 2022 16:14:12 +0100 Subject: [PATCH] BREAKING CHANGE: DecodeLimit and DecodeAll extensions now advance input (#314) * BREAKING CHANGE: DecodeLimit and DecodeAll extensions now properly advance input * Prepare for release 3.0.0 * This repo uses hard tabs --- CHANGELOG.md | 16 +++++++++- Cargo.lock | 4 +-- Cargo.toml | 11 +++---- derive/Cargo.toml | 2 +- rustfmt.toml | 23 +++++++++++++ src/decode_all.rs | 25 +++++++-------- src/depth_limit.rs | 80 ++++++++++++++++++++++------------------------ 7 files changed, 94 insertions(+), 67 deletions(-) create mode 100644 rustfmt.toml diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d90fcda..f262e804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,21 @@ All notable changes to this crate are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this crate adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## [3.0.0] - 2022-02-02 + +### Fix + +- Optimised the Decode::decode for [T; N] [#299](https://github.com/paritytech/parity-scale-codec/pull/299) + +### Changed + - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#298](https://github.com/paritytech/parity-scale-codec/pull/298) +- Upgrade to BitVec 1.0 [#311](https://github.com/paritytech/parity-scale-codec/pull/311) +- DecodeLimit and DecodeAll extensions now advance input [#314](https://github.com/paritytech/parity-scale-codec/pull/314) + +### Added + +- Add bytes::Bytes implementation [#309](https://github.com/paritytech/parity-scale-codec/pull/309) ## [2.3.1] - 2021-09-28 @@ -17,6 +30,7 @@ and this crate adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h ## [2.3.0] - 2021-09-11 ### Added + - `decode_and_advance_with_depth_limit` to the `DecodeLimit` trait. This allows advancing the cursor while decoding the input. PR #286 ## [2.2.0] - 2021-07-02 diff --git a/Cargo.lock b/Cargo.lock index 88585619..c57526f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -423,7 +423,7 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "parity-scale-codec" -version = "2.3.1" +version = "3.0.0" dependencies = [ "arbitrary", "arrayvec", @@ -443,7 +443,7 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "2.3.1" +version = "3.0.0" dependencies = [ "parity-scale-codec", "proc-macro-crate", diff --git a/Cargo.toml b/Cargo.toml index c5670890..fc47222c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "parity-scale-codec" description = "SCALE - Simple Concatenating Aggregated Little Endians" -version = "2.3.1" +version = "3.0.0" authors = ["Parity Technologies "] license = "Apache-2.0" repository = "https://github.com/paritytech/parity-scale-codec" @@ -12,8 +12,8 @@ rust-version = "1.56.1" [dependencies] arrayvec = { version = "0.7", default-features = false } serde = { version = "1.0.102", optional = true } -parity-scale-codec-derive = { path = "derive", version = "2.3.1", default-features = false, optional = true } -bitvec = { version = "1", default-features = false, features = ["alloc"], optional = true } +parity-scale-codec-derive = { path = "derive", version = "3.0.0", default-features = false, optional = true } +bitvec = { version = "1", default-features = false, features = [ "alloc" ], optional = true } bytes = { version = "1", default-features = false, optional = true } byte-slice-cast = { version = "1.0.0", default-features = false } generic-array = { version = "0.14.4", optional = true } @@ -59,7 +59,4 @@ chain-error = [] full = [] [workspace] -members = [ - "derive", - "fuzzer", -] +members = ["derive", "fuzzer"] diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 0d312ad6..24316e25 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "parity-scale-codec-derive" description = "Serialization and deserialization derive macro for Parity SCALE Codec" -version = "2.3.1" +version = "3.0.0" authors = ["Parity Technologies "] license = "Apache-2.0" edition = "2021" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..441913f6 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,23 @@ +# Basic +hard_tabs = true +max_width = 100 +use_small_heuristics = "Max" +# Imports +imports_granularity = "Crate" +reorder_imports = true +# Consistency +newline_style = "Unix" +# Format comments +comment_width = 100 +wrap_comments = true +# Misc +chain_width = 80 +spaces_around_ranges = false +binop_separator = "Back" +reorder_impl_items = false +match_arm_leading_pipes = "Preserve" +match_arm_blocks = false +match_block_trailing_comma = true +trailing_comma = "Vertical" +trailing_semicolon = false +use_field_init_shorthand = true diff --git a/src/decode_all.rs b/src/decode_all.rs index 64f8df6d..fb29c66c 100644 --- a/src/decode_all.rs +++ b/src/decode_all.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{Error, Decode}; +use crate::{Decode, Error}; /// The error message returned when `decode_all` fails. pub(crate) const DECODE_ALL_ERR_MSG: &str = "Input buffer has still data left after decoding!"; @@ -23,12 +23,11 @@ pub trait DecodeAll: Sized { /// Decode `Self` and consume all of the given input data. /// /// If not all data is consumed, an error is returned. - fn decode_all(input: &[u8]) -> Result; + fn decode_all(input: &mut &[u8]) -> Result; } impl DecodeAll for T { - fn decode_all(input: &[u8]) -> Result { - let input = &mut &input[..]; + fn decode_all(input: &mut &[u8]) -> Result { let res = T::decode(input)?; if input.is_empty() { @@ -42,7 +41,7 @@ impl DecodeAll for T { #[cfg(test)] mod tests { use super::*; - use crate::{Encode, Input, Compact, EncodeLike}; + use crate::{Compact, Encode, EncodeLike, Input}; macro_rules! test_decode_all { ( @@ -51,13 +50,13 @@ mod tests { $( { let mut encoded = <$type as Encode>::encode(&$value); - <$type>::decode_all(&encoded).expect( + <$type>::decode_all(&mut encoded.as_slice()).expect( &format!("`{} => {}` decodes all!", stringify!($type), stringify!($value)), ); encoded.extend(&[1, 2, 3, 4, 5, 6]); assert_eq!( - <$type>::decode_all(&encoded).unwrap_err().to_string(), + <$type>::decode_all(&mut encoded.as_slice()).unwrap_err().to_string(), "Input buffer has still data left after decoding!", ); } @@ -86,13 +85,11 @@ mod tests { impl Decode for TestStruct { fn decode(input: &mut I) -> Result { - Ok( - Self { - data: Vec::::decode(input)?, - other: u8::decode(input)?, - compact: Compact::::decode(input)?, - } - ) + Ok(Self { + data: Vec::::decode(input)?, + other: u8::decode(input)?, + compact: Compact::::decode(input)?, + }) } } diff --git a/src/depth_limit.rs b/src/depth_limit.rs index 7a6ec356..2af17843 100644 --- a/src/depth_limit.rs +++ b/src/depth_limit.rs @@ -12,37 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{Error, Decode, Input}; +use crate::{Decode, Error, Input}; /// The error message returned when depth limit is reached. const DECODE_MAX_DEPTH_MSG: &str = "Maximum recursion depth reached when decoding"; /// Extension trait to [`Decode`] for decoding with a maximum recursion depth. pub trait DecodeLimit: Sized { - /// Decode `Self` with the given maximum recursion depth. + /// Decode `Self` with the given maximum recursion depth and advance `input` by the number of + /// bytes consumed. /// /// If `limit` is hit, an error is returned. - fn decode_with_depth_limit(limit: u32, input: &[u8]) -> Result; - - /// Decode `Self` and advance `input` by the number of bytes consumed. - /// - /// If `limit` is hit, an error is returned. - fn decode_and_advance_with_depth_limit(limit: u32, input: &mut I) -> Result; + fn decode_with_depth_limit(limit: u32, input: &mut I) -> Result; /// Decode `Self` and consume all of the given input data. /// /// If not all data is consumed or `limit` is hit, an error is returned. - fn decode_all_with_depth_limit(limit: u32, input: &[u8]) -> Result; + fn decode_all_with_depth_limit(limit: u32, input: &mut &[u8]) -> Result; } - struct DepthTrackingInput<'a, I> { input: &'a mut I, depth: u32, max_depth: u32, } -impl<'a, I:Input> Input for DepthTrackingInput<'a, I> { +impl<'a, I: Input> Input for DepthTrackingInput<'a, I> { fn remaining_len(&mut self) -> Result, Error> { self.input.remaining_len() } @@ -72,36 +67,18 @@ impl<'a, I:Input> Input for DepthTrackingInput<'a, I> { } impl DecodeLimit for T { - fn decode_all_with_depth_limit(limit: u32, input: &[u8]) -> Result { - let mut input = DepthTrackingInput { - input: &mut &input[..], - depth: 0, - max_depth: limit, - }; - let res = T::decode(&mut input)?; - - if input.input.is_empty() { - Ok(res) + fn decode_all_with_depth_limit(limit: u32, input: &mut &[u8]) -> Result { + let t = ::decode_with_depth_limit(limit, input)?; + + if input.is_empty() { + Ok(t) } else { Err(crate::decode_all::DECODE_ALL_ERR_MSG.into()) } } - fn decode_and_advance_with_depth_limit(limit: u32, input: &mut I) -> Result { - let mut input = DepthTrackingInput { - input, - depth: 0, - max_depth: limit, - }; - T::decode(&mut input) - } - - fn decode_with_depth_limit(limit: u32, input: &[u8]) -> Result { - let mut input = DepthTrackingInput { - input: &mut &input[..], - depth: 0, - max_depth: limit, - }; + fn decode_with_depth_limit(limit: u32, input: &mut I) -> Result { + let mut input = DepthTrackingInput { input, depth: 0, max_depth: limit }; T::decode(&mut input) } } @@ -117,19 +94,38 @@ mod tests { let nested: NestedVec = vec![vec![vec![vec![1]]]]; let encoded = nested.encode(); - let decoded = NestedVec::decode_with_depth_limit(3, &encoded).unwrap(); + let decoded = NestedVec::decode_with_depth_limit(3, &mut encoded.as_slice()).unwrap(); assert_eq!(decoded, nested); - assert!(NestedVec::decode_with_depth_limit(2, &encoded).is_err()); + assert!(NestedVec::decode_with_depth_limit(2, &mut encoded.as_slice()).is_err()); } #[test] - fn decode_and_advance_works() { + fn decode_limit_advances_input() { type NestedVec = Vec>>>; let nested: NestedVec = vec![vec![vec![vec![1]]]]; - let encoded = &mut &nested.encode()[..]; + let encoded = nested.encode(); + let encoded_slice = &mut encoded.as_slice(); - let decoded = Vec::::decode_and_advance_with_depth_limit(1, encoded).unwrap(); + let decoded = Vec::::decode_with_depth_limit(1, encoded_slice).unwrap(); assert_eq!(decoded, vec![4]); - assert!(NestedVec::decode_with_depth_limit(3, encoded).is_err()); + assert!(NestedVec::decode_with_depth_limit(3, encoded_slice).is_err()); + } + + #[test] + fn decode_all_with_limit_advances_input() { + type NestedVec = Vec>>>; + let nested: NestedVec = vec![vec![vec![vec![1]]]]; + let mut encoded = NestedVec::encode(&nested); + + let decoded = NestedVec::decode_all_with_depth_limit(3, &mut encoded.as_slice()).unwrap(); + assert_eq!(decoded, nested); + + encoded.extend(&[1, 2, 3, 4, 5, 6]); + assert_eq!( + NestedVec::decode_all_with_depth_limit(3, &mut encoded.as_slice()) + .unwrap_err() + .to_string(), + "Input buffer has still data left after decoding!", + ); } }