tetsy_scale_codec/
lib.rs

1// Copyright 2017, 2018 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! # Tetsy SCALE Codec
16//!
17//! Rust implementation of the SCALE (Simple Concatenated Aggregate Little-Endian) data format
18//! for types used in the Tetsy Tetcore framework.
19//!
20//! SCALE is a light-weight format which allows encoding (and decoding) which makes it highly
21//! suitable for resource-constrained execution environments like blockchain runtimes and low-power,
22//! low-memory devices.
23//!
24//! It is important to note that the encoding context (knowledge of how the types and data structures look)
25//! needs to be known separately at both encoding and decoding ends.
26//! The encoded data does not include this contextual information.
27//!
28//! To get a better understanding of how the encoding is done for different types,
29//! take a look at the
30//! [SCALE Code page at the Tetcore Knowledge Base](https://core.tetcoin.org/docs/en/knowledgebase/advanced/codec).
31//!
32//! ## Implementation
33//!
34//! The codec is implemented using the following traits:
35//!
36//! ### Encode
37//!
38//! The `Encode` trait is used for encoding of data into the SCALE format. The `Encode` trait contains the following functions:
39
40//! * `size_hint(&self) -> usize`: Gets the capacity (in bytes) required for the encoded data.
41//! This is to avoid double-allocation of memory needed for the encoding.
42//! It can be an estimate and does not need to be an exact number.
43//! If the size is not known, even no good maximum, then we can skip this function from the trait implementation.
44//! This is required to be a cheap operation, so should not involve iterations etc.
45//! * `encode_to<T: Output>(&self, dest: &mut T)`: Encodes the value and appends it to a destination buffer.
46//! * `encode(&self) -> Vec<u8>`: Encodes the type data and returns a slice.
47//! * `using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R`: Encodes the type data and executes a closure on the encoded value.
48//! Returns the result from the executed closure.
49//!
50//! **Note:** Implementations should override `using_encoded` for value types and `encode_to` for allocating types.
51//! `size_hint` should be implemented for all types, wherever possible. Wrapper types should override all methods.
52//!
53//! ### Decode
54//!
55//! The `Decode` trait is used for deserialization/decoding of encoded data into the respective types.
56//!
57//! * `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.
58//! Returns an `Err` if the decoding fails.
59//!
60//! ### CompactAs
61//!
62//! The `CompactAs` trait is used for wrapping custom types/structs as compact types, which makes them even more space/memory efficient.
63//! The compact encoding is described [here](https://core.tetcoin.org/docs/en/knowledgebase/advanced/codec#compactgeneral-integers).
64//!
65//! * `encode_as(&self) -> &Self::As`: Encodes the type (self) as a compact type.
66//! The type `As` is defined in the same trait and its implementation should be compact encode-able.
67//! * `decode_from(_: Self::As) -> Result<Self, Error>`: Decodes the type (self) from a compact encode-able type.
68//!
69//! ### HasCompact
70//!
71//! The `HasCompact` trait, if implemented, tells that the corresponding type is a compact encode-able type.
72//!
73//! ### EncodeLike
74//!
75//! The `EncodeLike` trait needs to be implemented for each type manually. When using derive, it is
76//! done automatically for you. Basically the trait gives you the opportunity to accept multiple types
77//! to a function that all encode to the same representation.
78//!
79//! ## Usage Examples
80//!
81//! Following are some examples to demonstrate usage of the codec.
82//!
83//! ### Simple types
84//!
85//! ```
86//! # // Import macros if derive feature is not used.
87//! # #[cfg(not(feature="derive"))]
88//! # use tetsy_scale_codec_derive::{Encode, Decode};
89//!
90//! use tetsy_scale_codec::{Encode, Decode};
91//!
92//! #[derive(Debug, PartialEq, Encode, Decode)]
93//! enum EnumType {
94//! 	#[codec(index = 15)]
95//! 	A,
96//! 	B(u32, u64),
97//! 	C {
98//! 		a: u32,
99//! 		b: u64,
100//! 	},
101//! }
102//!
103//! let a = EnumType::A;
104//! let b = EnumType::B(1, 2);
105//! let c = EnumType::C { a: 1, b: 2 };
106//!
107//! a.using_encoded(|ref slice| {
108//!     assert_eq!(slice, &b"\x0f");
109//! });
110//!
111//! b.using_encoded(|ref slice| {
112//!     assert_eq!(slice, &b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0");
113//! });
114//!
115//! c.using_encoded(|ref slice| {
116//!     assert_eq!(slice, &b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0");
117//! });
118//!
119//! let mut da: &[u8] = b"\x0f";
120//! assert_eq!(EnumType::decode(&mut da).ok(), Some(a));
121//!
122//! let mut db: &[u8] = b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0";
123//! assert_eq!(EnumType::decode(&mut db).ok(), Some(b));
124//!
125//! let mut dc: &[u8] = b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0";
126//! assert_eq!(EnumType::decode(&mut dc).ok(), Some(c));
127//!
128//! let mut dz: &[u8] = &[0];
129//! assert_eq!(EnumType::decode(&mut dz).ok(), None);
130//!
131//! # fn main() { }
132//! ```
133//!
134//! ### Compact type with HasCompact
135//!
136//! ```
137//! # // Import macros if derive feature is not used.
138//! # #[cfg(not(feature="derive"))]
139//! # use tetsy_scale_codec_derive::{Encode, Decode};
140//!
141//! use tetsy_scale_codec::{Encode, Decode, Compact, HasCompact};
142//!
143//! #[derive(Debug, PartialEq, Encode, Decode)]
144//! struct Test1CompactHasCompact<T: HasCompact> {
145//!     #[codec(compact)]
146//!     bar: T,
147//! }
148//!
149//! #[derive(Debug, PartialEq, Encode, Decode)]
150//! struct Test1HasCompact<T: HasCompact> {
151//!     #[codec(encoded_as = "<T as HasCompact>::Type")]
152//!     bar: T,
153//! }
154//!
155//! let test_val: (u64, usize) = (0u64, 1usize);
156//!
157//! let encoded = Test1HasCompact { bar: test_val.0 }.encode();
158//! assert_eq!(encoded.len(), test_val.1);
159//! assert_eq!(<Test1CompactHasCompact<u64>>::decode(&mut &encoded[..]).unwrap().bar, test_val.0);
160//!
161//! # fn main() { }
162//! ```
163//! ### Type with CompactAs
164//!
165//! ```rust
166//! # // Import macros if derive feature is not used.
167//! # #[cfg(not(feature="derive"))]
168//! # use tetsy_scale_codec_derive::{Encode, Decode};
169//!
170//! use serde_derive::{Serialize, Deserialize};
171//! use tetsy_scale_codec::{Encode, Decode, Compact, HasCompact, CompactAs, Error};
172//!
173//! #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
174//! #[derive(PartialEq, Eq, Clone)]
175//! struct StructHasCompact(u32);
176//!
177//! impl CompactAs for StructHasCompact {
178//!     type As = u32;
179//!
180//!     fn encode_as(&self) -> &Self::As {
181//!         &12
182//!     }
183//!
184//!     fn decode_from(_: Self::As) -> Result<Self, Error> {
185//!         Ok(StructHasCompact(12))
186//!     }
187//! }
188//!
189//! impl From<Compact<StructHasCompact>> for StructHasCompact {
190//!     fn from(_: Compact<StructHasCompact>) -> Self {
191//!         StructHasCompact(12)
192//!     }
193//! }
194//!
195//! #[derive(Debug, PartialEq, Encode, Decode)]
196//! enum TestGenericHasCompact<T> {
197//!     A {
198//!         #[codec(compact)] a: T
199//!     },
200//! }
201//!
202//! let a = TestGenericHasCompact::A::<StructHasCompact> {
203//!     a: StructHasCompact(12325678),
204//! };
205//!
206//! let encoded = a.encode();
207//! assert_eq!(encoded.len(), 2);
208//!
209//! # fn main() { }
210//! ```
211//!
212//! ## Derive attributes
213//!
214//! The derive implementation supports the following attributes:
215//! - `codec(dumb_trait_bound)`: This attribute needs to be placed above the type that one of the trait
216//!   should be implemented for. It will make the algorithm that determines the to-add trait bounds
217//!   fall back to just use the type parameters of the type. This can be useful for situation where
218//!   the algorithm includes private types in the public interface. By using this attribute, you should
219//!   not get this error/warning again.
220//! - `codec(skip)`: Needs to be placed above a field  or variant and makes it to be skipped while
221//!   encoding/decoding.
222//! - `codec(compact)`: Needs to be placed above a field and makes the field use compact encoding.
223//!   (The type needs to support compact encoding.)
224//! - `codec(encoded_as = "OtherType")`: Needs to be placed above a field and makes the field being encoded
225//!   by using `OtherType`.
226//! - `codec(index = 0)`: Needs to be placed above an enum variant to make the variant use the given
227//!   index when encoded. By default the index is determined by counting from `0` beginning wth the
228//!   first variant.
229//!
230
231#![warn(missing_docs)]
232
233#![cfg_attr(not(feature = "std"), no_std)]
234
235#[cfg(not(feature = "std"))]
236#[macro_use]
237#[doc(hidden)]
238pub extern crate alloc;
239
240#[cfg(feature = "tetsy-scale-codec-derive")]
241#[allow(unused_imports)]
242#[macro_use]
243extern crate tetsy_scale_codec_derive;
244
245#[cfg(all(feature = "std", test))]
246#[macro_use]
247extern crate serde_derive;
248
249#[cfg(feature = "tetsy-scale-codec-derive")]
250pub use tetsy_scale_codec_derive::*;
251
252#[cfg(feature = "std")]
253#[doc(hidden)]
254pub mod alloc {
255	pub use std::boxed;
256	pub use std::vec;
257	pub use std::string;
258	pub use std::borrow;
259	pub use std::collections;
260	pub use std::sync;
261	pub use std::rc;
262}
263
264mod codec;
265mod compact;
266mod joiner;
267mod keyedvec;
268#[cfg(feature = "bit-vec")]
269mod bit_vec;
270#[cfg(feature = "generic-array")]
271mod generic_array;
272mod decode_all;
273mod depth_limit;
274mod encode_append;
275mod encode_like;
276mod error;
277
278pub use self::error::Error;
279pub use self::codec::{
280	Input, Output, Decode, Encode, Codec, EncodeAsRef, WrapperTypeEncode, WrapperTypeDecode,
281	OptionBool, DecodeLength, FullCodec, FullEncode,
282};
283#[cfg(feature = "std")]
284pub use self::codec::IoReader;
285pub use self::compact::{Compact, HasCompact, CompactAs, CompactLen};
286pub use self::joiner::Joiner;
287pub use self::keyedvec::KeyedVec;
288pub use self::decode_all::DecodeAll;
289pub use self::depth_limit::DecodeLimit;
290pub use self::encode_append::EncodeAppend;
291pub use self::encode_like::{EncodeLike, Ref};