Commit 422213e5 authored by Bastian Köcher's avatar Bastian Köcher Committed by thiolliere
Browse files

Fuzzer cleanup (#125)

parent 2b66d2ce
Pipeline #43654 passed with stages
in 13 minutes and 59 seconds
......@@ -23,7 +23,21 @@ cache:
test:rust:stable:
stage: test
script:
- time cargo test --verbose --all --features bit-vec
- time cargo test --verbose --all --features bit-vec,derive
only:
- triggers
- tags
- master
- schedules
- web
- /^[0-9]+$/
tags:
- rust
test:rust:stable:no_derive:
stage: test
script:
- time cargo test --verbose --features bit-vec
only:
- triggers
- tags
......@@ -37,7 +51,7 @@ test:rust:stable:
bench:rust:nightly:
stage: test
script:
- time cargo +nightly bench --features bit-vec
- time cargo +nightly bench --features bit-vec,derive
only:
- triggers
- tags
......@@ -53,7 +67,7 @@ bench:rust:nightly:
build:linux:ubuntu:amd64:
stage: build
script:
- cargo build --verbose --release --features bit-vec
- cargo build --verbose --release --features bit-vec,derive
only:
- master
- tags
......
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "arbitrary"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "arrayvec"
version = "0.4.10"
......@@ -30,7 +35,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitvec"
version = "0.11.1"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -71,6 +76,15 @@ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "codec-fuzzer"
version = "0.1.0"
dependencies = [
"bitvec 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-scale-codec 1.0.0",
]
[[package]]
name = "criterion"
version = "0.2.11"
......@@ -167,6 +181,16 @@ name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "honggfuzz"
version = "0.5.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.8.0"
......@@ -198,6 +222,15 @@ dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memmap"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memoffset"
version = "0.2.1"
......@@ -234,7 +267,7 @@ name = "parity-scale-codec"
version = "1.0.0"
dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"bitvec 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitvec 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-slice-cast 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-scale-codec-derive 1.0.0",
......@@ -490,11 +523,12 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64cf76cb6e2222ed0ea86b2b0ee2f71c96ec6edd5af42e84d59160e91b836ec4"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bitvec 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c28d4291b516ccfbb897d45de3c468c135e6af7c4f1f1aacfaae0a5bc2e6ea2c"
"checksum bitvec 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9633b74910e1870f50f5af189b08487195cdb83c0e27a71d6f64d5e09dd0538b"
"checksum byte-slice-cast 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cb79b824ad8026dfaf918b0f3f072a6faf916fe843aff07321a738babfd575"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
......@@ -510,11 +544,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)" = "24c27b4aa3049d6d10d8e33d52c9d03ca9aec18f8a449b246f8c4a5b0c10fb34"
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
......
......@@ -12,14 +12,14 @@ edition = "2018"
arrayvec = { version = "0.4", default-features = false, features = ["array-sizes-33-128", "array-sizes-129-255"] }
serde = { version = "1.0", optional = true }
parity-scale-codec-derive = { path = "derive", version = "1.0", default-features = false, optional = true }
bitvec = { version = "0.11", default-features = false, features = ["alloc"], optional = true }
bitvec = { version = "0.14.0", default-features = false, features = ["alloc"], optional = true }
byte-slice-cast = { version = "0.3.1", optional = true }
[dev-dependencies]
serde_derive = { version = "1.0" }
parity-scale-codec-derive = { path = "derive", version = "1.0", default-features = false }
criterion = "0.2"
bitvec = "0.11"
bitvec = "0.14.0"
[[bench]]
name = "benches"
......@@ -44,4 +44,5 @@ full = []
[workspace]
members = [
"derive",
"fuzzer",
]
# Parity SCALE Codec
Rust implementation of the SCALE (Simple Concatenated Aggregate Little-Endian) data format for types used in the Parity Substrate framework.
Rust implementation of the SCALE (Simple Concatenated Aggregate Little-Endian) data format
for types used in the Parity Substrate framework.
<!-- Inspired from Gav's codec overview written for Subtrate docs site -->
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.
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. The encoded data does not include this contextual information.
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 [low-level data formats overview page at the Substrate docs site](https://substrate.dev/docs/en/overview/low-level-data-format).
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
......@@ -16,26 +22,34 @@ 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. 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.
* `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. Returns the result from the executed closure.
* `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. `size_hint` should be implemented for all types, wherever possible. Wrapper types should override all methods.
**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.
Returns an `Err` if the decoding fails.
* `fn min_encoded_len() -> usize`: The minimum length a valid encoded value can have.
* `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 compact encoding is described [here](https://substrate.dev/docs/en/overview/low-level-data-format#compact-general-integers).
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. The type `As` is defined in the same trait and its implementation should be compact encode-able.
* `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
......@@ -49,6 +63,8 @@ Following are some examples to demonstrate usage of the codec.
### Simple types
```rust
use parity_scale_codec::{Encode, Decode};
#[derive(Debug, PartialEq, Encode, Decode)]
enum EnumType {
#[codec(index = "15")]
......@@ -87,11 +103,14 @@ assert_eq!(EnumType::decode(&mut dc).ok(), Some(c));
let mut dz: &[u8] = &[0];
assert_eq!(EnumType::decode(&mut dz).ok(), None);
```
### Compact type with HasCompact
```rust
use parity_scale_codec::{Encode, Decode, Compact, HasCompact};
#[derive(Debug, PartialEq, Encode, Decode)]
struct Test1CompactHasCompact<T: HasCompact> {
#[codec(compact)]
......@@ -109,11 +128,15 @@ 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);
```
```
### Type with CompactAs
```rust
use serde_derive::{Serialize, Deserialize};
use parity_scale_codec::{Encode, Decode, Compact, HasCompact, CompactAs};
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(PartialEq, Eq, Clone)]
struct StructHasCompact(u32);
......@@ -149,12 +172,7 @@ let a = TestGenericHasCompact::A::<StructHasCompact> {
let encoded = a.encode();
assert_eq!(encoded.len(), 2);
```
## Derive macros
This repository also contains an implementation of derive macros for the Parity SCALE codec. These macros can be used to implement the encode and decode functions for types using attributes. For reference, see the `derive` attributes on the types defined in the examples above.
## License
```
This Rust implementation of Parity SCALE Codec is licenced under the [Apache 2 license](./LICENSE).
License: Apache-2.0
[package]
name = "codec-fuzzer"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>", "Vincent Ulitzsch <vincent@srlabs.de>"]
edition = "2018"
publish = false
[dependencies]
parity-scale-codec = { path = "../", features = [ "derive", "bit-vec" ] }
honggfuzz = "0.5.45"
bitvec = { version = "0.14.0", features = ["alloc"] }
\ No newline at end of file
# Codec fuzzer
## Requirements:
# Parity SCALE Codec fuzzer
## Requirements:
Install [honggfuzz-rs](https://github.com/rust-fuzz/honggfuzz-rs):
```
cargo install honggfuzz
```
Run the fuzzer like so:
Run the fuzzer:
```
cargo hfuzz run codec_fuzzer
cargo hfuzz run codec-fuzzer
```
......
use parity_scale_codec::{Encode, Decode, Compact};
use std::collections::{BTreeMap, BTreeSet, VecDeque, LinkedList, BinaryHeap};
use honggfuzz::fuzz;
use bitvec::{vec::BitVec, cursor::BigEndian};
#[derive(Encode, Decode)]
pub struct MockStruct{
vec_u: Vec<u8>
}
#[derive(Encode, Decode)]
pub enum MockEnum {
Empty,
Unit(u32),
UnitVec(Vec<u8>),
Complex {
data: Vec<u32>,
map: BTreeMap<[u8; 32], Vec<u8>>,
string: String,
},
Mock(MockStruct),
NestedVec(Vec<Vec<Vec<Vec<Vec<Vec<Vec<Vec<Option<u8>>>>>>>>>),
}
macro_rules! fuzz_types {
(
$data:ident;
$first:ty,
$( $rest:ty, )*
) => {
fuzz_types! {
@INTERNAL
$data;
1u8;
{ $first; 0u8 }
$( $rest, )*
}
};
(@INTERNAL
$data:ident;
$counter:expr;
{ $( $parsed:ty; $index:expr ),* }
$current:ty,
$( $rest:ty, )*
) => {
fuzz_types! {
@INTERNAL
$data;
$counter + 1u8;
{ $current; $counter $(, $parsed; $index )* }
$( $rest, )*
}
};
(@INTERNAL
$data:ident;
$counter:expr;
{ $( $parsed:ty; $index:expr ),* }
) => {
let num = $counter;
$(
if $data[0] % num == $index {
let mut input = &$data[1..];
let input_start_len = input.len();
// Check that decode doesn't panic.
let result = <$parsed>::decode(&mut input);
// Check that min_encoded_len is valid.
if result.is_ok() {
let encoded_len = input_start_len - input.len();
assert!(<$parsed>::min_encoded_len() <= encoded_len);
}
return
}
)*
unreachable!()
};
}
fn fuzz_one_input(data: &[u8]){
fuzz_types! {
data;
u8,
u16,
u32,
u64,
u128,
Compact<u8>,
Compact<u16>,
Compact<u32>,
Compact<u64>,
Compact<u128>,
String,
Vec<u8>,
Vec<Vec<u8>>,
Option<Vec<u8>>,
Vec<u32>,
LinkedList<u8>,
BTreeMap<String, Vec<u8>>,
BTreeMap<u8, u8>,
BTreeSet<u32>,
VecDeque<u8>,
BinaryHeap<u32>,
MockStruct,
MockEnum,
BitVec<BigEndian, u8>,
BitVec<BigEndian, u32>,
}
}
fn main() {
loop {
fuzz!(|data: &[u8]| { fuzz_one_input(data); });
}
}
[package]
name = "codec_fuzzer"
version = "0.1.0"
authors = ["Vincent Ulitzsch <vincent@srlabs.de>"]
edition = "2018"
[dependencies]
parity-scale-codec = { path = "../", features=["derive"]}
honggfuzz = ""
[workspace]
use parity_scale_codec::{Encode, Decode};
use std::collections::{BTreeMap, BTreeSet, VecDeque, LinkedList, BinaryHeap};
#[cfg(not(fuzzing))]
use std::io::{self, Read};
#[derive(Encode, Decode, Default, Clone, PartialEq)]
#[derive(Debug)]
pub struct MockStruct{
vec_u: Vec<u8>
}
fn fuzz_one_input(data: &[u8]){
match data[0] % 9 {
0 => { let _u_16 = u16::decode(&mut &data[1..]);},
1 => { let _vec_u8= Vec::<u8>::decode(&mut &data[1..]);},
2 => { let _vec_u32 = Vec::<u32>::decode(&mut &data[1..]);}
3 => { let _linked_list = LinkedList::<u8>::decode(&mut &data[1..]);},
4 => { let _btree = BTreeMap::<u8, u8>::decode(&mut &data[1..]);},
5 => { let _btreeset = BTreeSet::<u8>::decode(&mut &data[1..]);},
6 => { let _vecdeque = VecDeque::<u8>::decode(&mut &data[1..]);},
7 => { let _binaryheap = BinaryHeap::<u8>::decode(&mut &data[1..]);},
8 => { let _mock_struct = MockStruct::decode(&mut &data[1..]);}
_ => unreachable!()
}
}
#[macro_use] extern crate honggfuzz;
#[cfg(fuzzing)]
fn main() {
loop {
fuzz!(|data: &[u8]| {
fuzz_one_input(data);
});
}
}
#[cfg(not(fuzzing))]
fn main() -> io::Result<()> {
let mut buffer = String::new();
io::stdin().read_to_string(&mut buffer)?;
let data = buffer.as_bytes();
println!("Trying data: {:?}", data);
fuzz_one_input(data);
Ok(())
}
......@@ -16,7 +16,7 @@
use core::mem;
use bitvec::{vec::BitVec, bits::Bits, cursor::Cursor, slice::BitSlice, boxed::BitBox};
use bitvec::{vec::BitVec, store::BitStore, cursor::Cursor, slice::BitSlice, boxed::BitBox};
use byte_slice_cast::{AsByteSlice, ToByteSlice, FromByteSlice, Error as FromByteSliceError};
use crate::codec::{Encode, Decode, Input, Output, Error};
......@@ -31,7 +31,7 @@ impl From<FromByteSliceError> for Error {
}
}
impl<C: Cursor, T: Bits + ToByteSlice> Encode for BitSlice<C, T> {
impl<C: Cursor, T: BitStore + ToByteSlice> Encode for BitSlice<C, T> {
fn encode_to<W: Output>(&self, dest: &mut W) {
let len = self.len();
assert!(len <= u32::max_value() as usize, "Attempted to serialize a collection with too many elements.");
......@@ -40,13 +40,13 @@ impl<C: Cursor, T: Bits + ToByteSlice> Encode for BitSlice<C, T> {
}
}
impl<C: Cursor, T: Bits + ToByteSlice> Encode for BitVec<C, T> {
impl<C: Cursor, T: BitStore + ToByteSlice> Encode for BitVec<C, T> {
fn encode_to<W: Output>(&self, dest: &mut W) {
self.as_bitslice().encode_to(dest)
}
}
impl<C: Cursor, T: Bits + FromByteSlice> Decode for BitVec<C, T> {
impl<C: Cursor, T: BitStore + FromByteSlice> Decode for BitVec<C, T> {
fn min_encoded_len() -> usize {
<Compact<u32>>::min_encoded_len()
}
......@@ -66,13 +66,13 @@ impl<C: Cursor, T: Bits + FromByteSlice> Decode for BitVec<C, T> {
}
}
impl<C: Cursor, T: Bits + ToByteSlice> Encode for BitBox<C, T> {
impl<C: Cursor, T: BitStore + ToByteSlice> Encode for BitBox<C, T> {
fn encode_to<W: Output>(&self, dest: &mut W) {
self.as_bitslice().encode_to(dest)
}
}
impl<C: Cursor, T: Bits + FromByteSlice> Decode for BitBox<C, T> {
impl<C: Cursor, T: BitStore + FromByteSlice> Decode for BitBox<C, T> {
fn min_encoded_len() -> usize {
<BitVec<C, T>>::min_encoded_len()
}
......
......@@ -79,6 +79,12 @@ mod tests {
}
impl Decode for TestStruct {
fn min_encoded_len() -> usize {
Vec::<u32>::min_encoded_len()
+ u8::min_encoded_len()
+ Compact::<u128>::min_encoded_len()
}
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
Ok(
Self {
......@@ -105,4 +111,4 @@ mod tests {
TestStruct => TestStruct { data: vec![1, 2, 4, 5, 6], other: 45, compact: Compact(123234545) };
}
}
}
\ No newline at end of file
}
......@@ -77,7 +77,10 @@
//! ### Simple types
//!
//! ```
//! use parity_scale_codec_derive::{Encode, Decode};
//! # // Import macros if derive feature is not used.
//! # #[cfg(not(feature="derive"))]
//! # use parity_scale_codec_derive::{Encode, Decode};
//!
//! use parity_scale_codec::{Encode, Decode};
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
......@@ -125,7 +128,10 @@
//! ### Compact type with HasCompact
//!
//! ```
//! use parity_scale_codec_derive::{Encode, Decode};;
//! # // Import macros if derive feature is not used.
//! # #[cfg(not(feature="derive"))]
//! # use parity_scale_codec_derive::{Encode, Decode};
//!
//! use parity_scale_codec::{Encode, Decode, Compact, HasCompact};
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
......@@ -151,9 +157,11 @@
//! ### Type with CompactAs
//!
//! ```rust
//! # // Import macros if derive feature is not used.
//! # #[cfg(not(feature="derive"))]
//! # use parity_scale_codec_derive::{Encode, Decode};
//!
//! 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))]
......
......@@ -12,13 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate parity_scale_codec_derive;
#[cfg(not(feature="derive"))]
use parity_scale_codec_derive::{Encode, Decode};
use parity_scale_codec::{Encode, Decode, HasCompact, Compact, EncodeAsRef, CompactAs};
use serde_derive::{Serialize, Deserialize};
mod mock;
......
#[macro_use]
extern crate parity_scale_codec_derive;
#[cfg(not(feature="derive"))]
use parity_scale_codec_derive::{Encode, Decode, CompactAs};
#[cfg(feature="derive")]
use parity_scale_codec::{Decode, CompactAs};
use parity_scale_codec::{Compact, Encode, HasCompact};
use serde_derive::{Serialize, Deserialize};
......