Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
parity
Mirrored projects
parity-scale-codec
Commits
9835ab32
Commit
9835ab32
authored
Jul 17, 2019
by
Bastian Köcher
Committed by
thiolliere
Jul 17, 2019
Browse files
Add and implement `DecodeAll` (#126)
parent
f248552d
Pipeline
#43534
passed with stages
in 13 minutes and 36 seconds
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/decode_all.rs
0 → 100644
View file @
9835ab32
// Copyright 2017, 2018 Parity Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use
crate
::{
Error
,
Decode
};
/// The error message returned when `decode_all` fails.
const
DECODE_ALL_ERR_MSG
:
&
str
=
"Input buffer has still data left after decoding!"
;
/// Extension trait to [`Decode`] that ensures that the given input data is consumed completly while
/// decoding.
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
<
Self
,
Error
>
;
}
impl
<
T
:
Decode
>
DecodeAll
for
T
{
fn
decode_all
(
input
:
&
[
u8
])
->
Result
<
Self
,
Error
>
{
let
input
=
&
mut
&
input
[
..
];
let
res
=
T
::
decode
(
input
)
?
;
if
input
.is_empty
()
{
Ok
(
res
)
}
else
{
Err
(
DECODE_ALL_ERR_MSG
.into
())
}
}
}
#[cfg(test)]
mod
tests
{
use
super
::
*
;
use
crate
::{
Encode
,
Input
,
Compact
};
macro_rules!
test_decode_all
{
(
$
(
$type:ty
=>
$value:expr
;
)
*
)
=>
{
$
(
{
let
mut
encoded
=
<
$type
as
Encode
>
::
encode
(
&
$value
);
<
$type
>
::
decode_all
(
&
encoded
)
.expect
(
&
format!
(
"`{} => {}` decodes all!"
,
stringify!
(
$type
),
stringify!
(
$value
)),
);
encoded
.extend
(
&
[
1
,
2
,
3
,
4
,
5
,
6
]);
assert_eq!
(
<
$type
>
::
decode_all
(
&
encoded
)
.unwrap_err
()
.what
(),
DECODE_ALL_ERR_MSG
);
}
)
*
};
}
#[derive(Debug)]
struct
TestStruct
{
data
:
Vec
<
u32
>
,
other
:
u8
,
compact
:
Compact
<
u128
>
,
}
impl
Encode
for
TestStruct
{
fn
encode
(
&
self
)
->
Vec
<
u8
>
{
let
mut
res
=
Vec
::
new
();
self
.data
.encode_to
(
&
mut
res
);
self
.other
.encode_to
(
&
mut
res
);
self
.compact
.encode_to
(
&
mut
res
);
res
}
}
impl
Decode
for
TestStruct
{
fn
decode
<
I
:
Input
>
(
input
:
&
mut
I
)
->
Result
<
Self
,
Error
>
{
Ok
(
Self
{
data
:
Vec
::
<
u32
>
::
decode
(
input
)
?
,
other
:
u8
::
decode
(
input
)
?
,
compact
:
Compact
::
<
u128
>
::
decode
(
input
)
?
,
}
)
}
}
#[test]
fn
decode_all_works
()
{
test_decode_all!
{
u8
=>
120
;
u16
=>
30
;
u32
=>
1
;
u64
=>
2343545
;
u128
=>
34358394245459854
;
Vec
<
u8
>
=>
vec!
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
];
Vec
<
u32
>
=>
vec!
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
];
Compact
<
u32
>
=>
Compact
(
32445
);
Compact
<
u128
>
=>
Compact
(
34353454453545
);
TestStruct
=>
TestStruct
{
data
:
vec!
[
1
,
2
,
4
,
5
,
6
],
other
:
45
,
compact
:
Compact
(
123234545
)
};
}
}
}
\ No newline at end of file
src/lib.rs
View file @
9835ab32
...
...
@@ -13,73 +13,73 @@
// limitations under the License.
//! # Parity SCALE Codec
//!
//! Rust implementation of the SCALE (Simple Concatenated Aggregate Little-Endian) data format
//!
//! Rust implementation of the SCALE (Simple Concatenated Aggregate Little-Endian) data format
//! for types used in the Parity Substrate framework.
//!
//! SCALE is a light-weight format which allows encoding (and decoding) which makes it highly
//! suitable for resource-constrained execution environments like blockchain runtimes and low-power,
//!
//! SCALE is a light-weight format which allows encoding (and decoding) which makes it highly
//! suitable for resource-constrained execution environments like blockchain runtimes and low-power,
//! low-memory devices.
//!
//! It is important to note that the encoding context (knowledge of how the types and data structures look)
//! needs to be known separately at both encoding and decoding ends.
//!
//! It is important to note that the encoding context (knowledge of how the types and data structures look)
//! needs to be known separately at both encoding and decoding ends.
//! The encoded data does not include this contextual information.
//!
//! To get a better understanding of how the encoding is done for different types,
//! take a look at the
//!
//! To get a better understanding of how the encoding is done for different types,
//! take a look at the
//! [low-level data formats overview page at the Substrate docs site](https://substrate.dev/docs/en/overview/low-level-data-format).
//!
//!
//! ## Implementation
//!
//!
//! The codec is implemented using the following traits:
//!
//!
//! ### Encode
//!
//!
//! The `Encode` trait is used for encoding of data into the SCALE format. The `Encode` trait contains the following functions:
//! * `size_hint(&self) -> usize`: Gets the capacity (in bytes) required for the encoded data.
//! This is to avoid double-allocation of memory needed for the encoding.
//! It can be an estimate and does not need to be an exact number.
//! * `size_hint(&self) -> usize`: Gets the capacity (in bytes) required for the encoded data.
//! This is to avoid double-allocation of memory needed for the encoding.
//! It can be an estimate and does not need to be an exact number.
//! If the size is not known, even no good maximum, then we can skip this function from the trait implementation.
//! This is required to be a cheap operation, so should not involve iterations etc.
//! * `encode_to<T: Output>(&self, dest: &mut T)`: Encodes the value and appends it to a destination buffer.
//! * `encode(&self) -> Vec<u8>`: Encodes the type data and returns a slice.
//! * `using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R`: Encodes the type data and executes a closure on the encoded value.
//! * `using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R`: Encodes the type data and executes a closure on the encoded value.
//! Returns the result from the executed closure.
//!
//! **Note:** Implementations should override `using_encoded` for value types and `encode_to` for allocating types.
//!
//! **Note:** Implementations should override `using_encoded` for value types and `encode_to` for allocating types.
//! `size_hint` should be implemented for all types, wherever possible. Wrapper types should override all methods.
//!
//!
//! ### Decode
//!
//!
//! The `Decode` trait is used for deserialization/decoding of encoded data into the respective types.
//!
//! * `fn decode<I: Input>(value: &mut I) -> Result<Self, Error>`: Tries to decode the value from SCALE format to the type it is called on.
//!
//! * `fn decode<I: Input>(value: &mut I) -> Result<Self, Error>`: Tries to decode the value from SCALE format to the type it is called on.
//! Returns an `Err` if the decoding fails.
//!
//!
//! ### CompactAs
//!
//! The `CompactAs` trait is used for wrapping custom types/structs as compact types, which makes them even more space/memory efficient.
//!
//! The `CompactAs` trait is used for wrapping custom types/structs as compact types, which makes them even more space/memory efficient.
//! The compact encoding is described [here](https://substrate.dev/docs/en/overview/low-level-data-format#compact-general-integers).
//!
//! * `encode_as(&self) -> &Self::As`: Encodes the type (self) as a compact type.
//!
//! * `encode_as(&self) -> &Self::As`: Encodes the type (self) as a compact type.
//! The type `As` is defined in the same trait and its implementation should be compact encode-able.
//! * `decode_from(_: Self::As) -> Self`: Decodes the type (self) from a compact encode-able type.
//!
//!
//! ### HasCompact
//!
//!
//! The `HasCompact` trait, if implemented, tells that the corresponding type is a compact encode-able type.
//!
//!
//! ## Usage Examples
//!
//!
//! Following are some examples to demonstrate usage of the codec.
//!
//!
//! ### Simple types
//!
//!
//! ```
//! use parity_scale_codec_derive::{Encode, Decode};
//! use parity_scale_codec::{Encode, Decode};
//!
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
//! enum EnumType {
//! #[codec(index = "15")]
...
...
@@ -90,108 +90,108 @@
//! b: u64,
//! },
//! }
//!
//!
//! let a = EnumType::A;
//! let b = EnumType::B(1, 2);
//! let c = EnumType::C { a: 1, b: 2 };
//!
//!
//! a.using_encoded(|ref slice| {
//! assert_eq!(slice, &b"\x0f");
//! });
//!
//!
//! b.using_encoded(|ref slice| {
//! assert_eq!(slice, &b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0");
//! });
//!
//!
//! c.using_encoded(|ref slice| {
//! assert_eq!(slice, &b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0");
//! });
//!
//!
//! let mut da: &[u8] = b"\x0f";
//! assert_eq!(EnumType::decode(&mut da).ok(), Some(a));
//!
//!
//! let mut db: &[u8] = b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0";
//! assert_eq!(EnumType::decode(&mut db).ok(), Some(b));
//!
//!
//! let mut dc: &[u8] = b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0";
//! assert_eq!(EnumType::decode(&mut dc).ok(), Some(c));
//!
//!
//! let mut dz: &[u8] = &[0];
//! assert_eq!(EnumType::decode(&mut dz).ok(), None);
//!
//!
//! # fn main() { }
//! ```
//!
//!
//! ### Compact type with HasCompact
//!
//!
//! ```
//! use parity_scale_codec_derive::{Encode, Decode};;
//! use parity_scale_codec::{Encode, Decode, Compact, HasCompact};
//!
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
//! struct Test1CompactHasCompact<T: HasCompact> {
//! #[codec(compact)]
//! bar: T,
//! }
//!
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
//! struct Test1HasCompact<T: HasCompact> {
//! #[codec(encoded_as = "<T as HasCompact>::Type")]
//! bar: T,
//! }
//!
//!
//! let test_val: (u64, usize) = (0u64, 1usize);
//!
//!
//! let encoded = Test1HasCompact { bar: test_val.0 }.encode();
//! assert_eq!(encoded.len(), test_val.1);
//! assert_eq!(<Test1CompactHasCompact<u64>>::decode(&mut &encoded[..]).unwrap().bar, test_val.0);
//!
//!
//! # fn main() { }
//! ```
//! ### Type with CompactAs
//!
//!
//! ```rust
//!
//!
//! use serde_derive::{Serialize, Deserialize};
//! use parity_scale_codec_derive::{Encode, Decode};;
//! use parity_scale_codec::{Encode, Decode, Compact, HasCompact, CompactAs};
//!
//!
//! #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
//! #[derive(PartialEq, Eq, Clone)]
//! struct StructHasCompact(u32);
//!
//!
//! impl CompactAs for StructHasCompact {
//! type As = u32;
//!
//!
//! fn encode_as(&self) -> &Self::As {
//! &12
//! }
//!
//!
//! fn decode_from(_: Self::As) -> Self {
//! StructHasCompact(12)
//! }
//! }
//!
//!
//! impl From<Compact<StructHasCompact>> for StructHasCompact {
//! fn from(_: Compact<StructHasCompact>) -> Self {
//! StructHasCompact(12)
//! }
//! }
//!
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
//! enum TestGenericHasCompact<T> {
//! A {
//! #[codec(compact)] a: T
//! },
//! }
//!
//!
//! let a = TestGenericHasCompact::A::<StructHasCompact> {
//! a: StructHasCompact(12325678),
//! };
//!
//!
//! let encoded = a.encode();
//! assert_eq!(encoded.len(), 2);
//!
//!
//! # fn main() { }
//! ```
...
...
@@ -240,6 +240,7 @@ mod joiner;
mod
keyedvec
;
#[cfg(feature
=
"bit-vec"
)]
mod
bit_vec
;
mod
decode_all
;
pub
use
self
::
codec
::{
Input
,
Output
,
Error
,
Encode
,
Decode
,
Codec
,
EncodeAsRef
,
EncodeAppend
,
WrapperTypeEncode
,
...
...
@@ -248,3 +249,4 @@ pub use self::codec::{
pub
use
self
::
compact
::{
Compact
,
HasCompact
,
CompactAs
};
pub
use
self
::
joiner
::
Joiner
;
pub
use
self
::
keyedvec
::
KeyedVec
;
pub
use
self
::
decode_all
::
DecodeAll
;
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment