Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
f2036ee
epic: total remake
xDimon Feb 10, 2025
d29aa0a
variant
xDimon Feb 10, 2025
0de2a1e
fixed integer
xDimon Feb 10, 2025
084c3e9
classic compact integer
xDimon Feb 10, 2025
52f9bd7
jam compact integer
xDimon Feb 10, 2025
4b04368
enum
xDimon Feb 10, 2025
09f1ce9
sptr upts refwrap
xDimon Feb 10, 2025
18dcf44
fix: custom decomposable
xDimon Feb 11, 2025
57be4bd
draft
xDimon Feb 11, 2025
3acd8aa
docs and polishing
xDimon Feb 11, 2025
e034540
docs and polishing
xDimon Feb 11, 2025
9253552
fix: boost variant test
xDimon Feb 11, 2025
65fbaad
tagged types
xDimon Feb 11, 2025
6ecc0c6
fixes
xDimon Feb 11, 2025
27310e8
fixes
xDimon Feb 11, 2025
7d6f810
update: qtils
xDimon Feb 11, 2025
11bd851
update: ci os
xDimon Feb 11, 2025
347327a
fix: lvalue/rvalue ambiguous
xDimon Feb 13, 2025
04e43b0
hotfix
xDimon Feb 13, 2025
5127399
hotfix
xDimon Feb 13, 2025
665e351
feature: decode into lvalue and rvalue
xDimon Feb 13, 2025
fd99768
feature: macro for using base-class properties in custom decomposition
xDimon Feb 14, 2025
a55bbc5
feature: support of decoding into immutable collection
xDimon Feb 14, 2025
7cddef7
update: doc&test
xDimon Feb 14, 2025
1661d75
refactor: decomposable
xDimon Feb 14, 2025
99287b6
refactor: remove of using ScaleEncode/ScaleDecode concepts
xDimon Feb 14, 2025
fdb34f1
clean: remove commented code
xDimon Feb 14, 2025
81b7282
fix: clang warn for immutable collection
xDimon Feb 14, 2025
9b348f0
feature: scale::impl::memory::encoded_size
xDimon Feb 15, 2025
61b8cc8
fix: always forward encode's value by cons-lvalue-ref
xDimon Feb 15, 2025
5d96520
refactor: encode for EncodeOpaqueValue
xDimon Feb 15, 2025
75c2314
clean: remove commented code
xDimon Feb 15, 2025
cf20755
fix: typo
xDimon Feb 15, 2025
ad1b310
fix: installation of scale_append
xDimon Feb 15, 2025
07b926e
fix: dtor for encoder/decoder
xDimon Feb 16, 2025
e5792b1
refactor: assert for abnormal aggregate
xDimon Feb 18, 2025
3df0f51
refactor: jump-table
xDimon Feb 20, 2025
e6f3deb
refactor: Decoder::read without copying
xDimon Feb 20, 2025
ddbdc02
remake: BitVector/SmallBitVector
xDimon Feb 20, 2025
f3d97b1
fix: review issues
xDimon Feb 20, 2025
24fbd76
feature: single-byte implementation of optional bool
xDimon Feb 21, 2025
34e980b
update: qtils
xDimon Feb 21, 2025
6f12d37
refactor: use externally provided source and receiver of bytes
xDimon Feb 22, 2025
e0b5faf
refactor: optimisation of read/write continuous sequences of bytes
xDimon Feb 22, 2025
cc8e74f
fix: case of custom config
xDimon Feb 22, 2025
915a705
refactor: unification
xDimon Feb 22, 2025
d58afe3
fix: scale::decode
xDimon Feb 22, 2025
afc73e9
fix: review issue
xDimon Feb 22, 2025
28b9c17
update: README
xDimon Feb 22, 2025
25e6627
fixL: UB
xDimon Feb 23, 2025
1564332
update: bump version
xDimon Feb 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ env:

jobs:
MacOS:
runs-on: macos-latest
runs-on: macos-15
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: ${{ env.CACHE_PATHS }}
key: ${{ github.job }}-${{ env.CACHE_VERSION }}
Expand All @@ -38,10 +38,10 @@ jobs:
- name: "Linux: clang"
run: ./scripts/build.sh -DCMAKE_CXX_COMPILER=clang++
name: "${{ matrix.options.name }}"
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: ${{ env.CACHE_PATHS }}
key: ${{ github.job }}-${{ matrix.options.name }}-${{ env.CACHE_VERSION }}
Expand All @@ -50,13 +50,13 @@ jobs:

clang-tidy:
name: "Linux: clang-tidy"
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
container: qdrvm/kagome-dev@sha256:2d70246c32418a3dd45c246d3f5c2dd99bdafde145b903271849affe476c4cfc
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/cache@v2
- uses: actions/cache@v4
with:
path: ${{ env.CACHE_PATHS }}
key: ${{ github.job }}-${{ env.CACHE_VERSION }}
Expand Down
13 changes: 11 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
cmake_minimum_required(VERSION 3.12)

option(JAM_COMPATIBLE "Build compatible with JAM-codec" OFF)
option(CUSTOM_CONFIG_SUPPORT "Support custom config of streams" OFF)
option(CUSTOM_CONFIG_SUPPORT "Support custom config of coder" OFF)
set(MAX_AGGREGATE_FIELDS 20 CACHE STRING "Max number of aggregates fields (1..1000); for generation")

option(BUILD_TESTS "Whether to include the test suite in build" OFF)
Expand Down Expand Up @@ -42,7 +42,7 @@ if(BUILD_TESTS)
endif()
endif()

project(Scale LANGUAGES CXX VERSION 1.1.0)
project(Scale LANGUAGES CXX VERSION 2.0.0)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down Expand Up @@ -88,6 +88,15 @@ install(TARGETS scale EXPORT scaleConfig
FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX}
)

install(TARGETS scale_append EXPORT scaleConfig
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX}
)

install(
DIRECTORY ${CMAKE_SOURCE_DIR}/include/scale
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
Expand Down
199 changes: 121 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,51 @@
# SCALE codec C++ implementation
fully meets polkadot specification.\
**SCALE (Simple Concatenated Aggregate Little-Endian)** is a lightweight serialization format commonly used in blockchain applications.
More details in [spec](https://docs.polkadot.com/polkadot-protocol/basics/data-encoding/#scale-codec) from Polkadot.

It allows encoding and decoding following data types:
* Built-in integer types specified by size:
* ```uint8_t```, ```int8_t```
* ```uint16_t```, ```int16_t```
* ```uint32_t```, ```int32_t```
* ```uint64_t```, ```int64_t```
* bool values
* pairs of types represented by ```std::pair<T1, T2>```
* compact integers represented by CompactInteger type
* optional values represented by ```std::optional<T>```
* as special case of optional values ```std::optional<bool>``` is encoded using one byte following specification.
* collections of items represented by ```std::vector<T>```
* variants represented by ```boost::variant<T...>```

## ScaleEncoderStream
class ScaleEncoderStream is in charge of encoding data
* ```uint8_t```, ```int8_t```
* ```uint16_t```, ```int16_t```
* ```uint32_t```, ```int32_t```
* ```uint64_t```, ```int64_t```
* Multiprecision integer from boost:
* ```uint128_t```, ```int128_t```
* ```uint256_t```, ```int256_t```
* ```uint512_t```, ```int512_t```
* ```uint1024_t```, ```int1024_t```
* boolean values
* pairs, tuples and other structurally bindable types (limited by N members)
* aggregates limited by N field (except array, that coded as collection)
* compact integers represented by CompactInteger type (classic and JAM-compatible). **Unsigned only!**
* optional values represented by ```std::optional<T>``` and ```boost::optional<T>```
* as special case of optional values ```*::optional<bool>``` is encoded using one byte following specification.
* various collections of items
* if item codable
* encodes item by item in order of forward iterator
* decodes items by inserting in order as encoded
* variants represented by ```std::variant<T...>``` and ```boost::variant<T...>```

## encode(value, encoder)
It is function is in charge of encoding of value and store to backend set in encoder

## decode(value, encoder)
It is function is in charge of read and decode data from backend set in encoder and initialize provided variable

## Encoder
class Encoder is in charge of encoding data
It receives values over `encode()` function and store encoded data into EncoderBackend
Additionally it receive values over `<<` operator.

## Decoder
class Decoder is in charge of decoding data
It initializes provided value over `decode()` function by decoded value from encoded source data
Additionally it initialize provided values over `>>` operator.

## Example
```c++
ScaleEncoderStream s;
std::vector<uint8_t> out;
ToBytes encoder(out); // Encoder which used backend 'to bytes'

uint32_t ui32 = 123u;
uint8_t ui8 = 234u;
std::string str = "asdasdasd";
Expand All @@ -32,9 +59,16 @@ std::pair<uint8_t, uint32_t> pair{1u, 2u};
std::vector<uint32_t> coll_ui32 = {1u, 2u, 3u, 4u};
std::vector<std::string> coll_str = {"asd", "fgh", "jkl"};
std::vector<std::vector<int32_t>> coll_coll_i32 = {{1, 2, 3}, {4, 5, 6, 7}};

try {
s << ui32 << ui8 << str << raw_str << b << ci << vint;
s << opt_str << opt_bool << pair << coll_ui32 << coll_str << coll_coll_i32;
// functional style
encode(ui32, encoder);
encode(ui8, encoder);
encode(str, encoder);
// combine for one call
encode(std::tie(raw_str, b, ci, vint), encoder);
// stream-style
encoder << opt_str << opt_bool << pair << coll_ui32 << coll_str << coll_coll_i32;
} catch (std::runtime_error &e) {
// handle error
// for example make and return outcome::result
Expand All @@ -43,15 +77,12 @@ try {
```
You can now get encoded data:
```c++
ByteArray data = s.data();
auto in = out;;
```

## ScaleDecoderStream
class ScaleEncoderStream is in charge of encoding data

Now you can decode that data back:
```c++
ByteArray bytes = {...};
ScaleEncoderStream s(bytes);
FromBytes decoder(in); // Decoder which used backend 'from bytes'

uint32_t ui32 = 0u;
uint8_t ui8 = 0u;
std::string str;
Expand All @@ -65,90 +96,102 @@ std::vector<uint32_t> coll_ui32;
std::vector<std::string> coll_str;
std::vector<std::vector<int32_t>> coll_coll_i32;
try {
s >> ui32 >> ui8 >> str >> b >> ci >> vint;
s >> opt_str >> opt_bool >> pair >> coll_ui32 >> coll_str >> coll_coll_i32;
// functional style
decode(ui32, decoder);
decode(ui8, decoder);
decode(str, decoder);
// combine for one call
decode(std::tie(raw_str, b, ci, vint), decoder);
// stream-style
decoder >> opt_str >> opt_bool >> pair >> coll_ui32 >> coll_str >> coll_coll_i32;
} catch (std::system_error &e) {
// handle error
}
```
Now we have variables initialized by decoded values

## Custom types
You may need to encode or decode custom data types, you have to define custom << and >> operators.
You may need to encode or decode custom data types, you have to define custom `encode()` and `decode()` function.
Please note, that your custom data types must be default-constructible.
```c++
struct MyType {
int a = 0;
std::string b;

friend void encode(const MyType &v, Encoder &encoder) {
encoder << a;
encode(b, encoder);
}
friend void decode(MyType &v, Decoder &decoder) {
decoder >> a;
decode(b, decoder);
}
};

ScaleEncoderStream &operator<<(ScaleEncoderStream &s, const MyType &v) {
return s << v.a << v.b;
}

ScaleDecoderStream &operator>>(ScaleDecoderStream &s, MyType &v) {
return s >> v.a >> v.b;
}
```
Now you can use them in collections, optionals and variants
```c++
std::vector<MyType> v = {{1, "asd"}, {2, "qwe"}};
ScaleEncoderStream s;
std::vector<uint8_t> out;
EncoderToVector encoder(out)
std::vector<MyType> src_vec = {{1, "asd"}, {2, "qwe"}};
try {
s << v;
encoder << src_vec;
} catch (...) {
// handle error
}
```
The same for ```ScaleDecoderStream```
```c++
ByteArray data = {...};
std::vector<MyType> v;
ScaleDecoderStream s{data};

std::vector<uint8_t> in = {...};
DecoderFromSpan decoder(in);
std::vector<MyType> dst_vec;
try {
s >> v;
decode(dst, decoder);
} catch (...) {
// handle error
}
```

## Convenience functions
Convenience functions
Library provides ready well done function to encode/decode in one line. You should just use import it in you namespace:

```c++
template <typename T>
outcome::result<std::vector<uint8_t>> encode(T &&t);
// template <typename T>
// outcome::result<std::vector<uint8_t>> encode(T &&value);
using ::scale::impl::bytes::encode;

template <typename T>
outcome::result<T> decode(const RangeOfBytes auto& span)
SomeClass object = {...};
auto res = encode(object); // <- Just one-line call
if (res.has_value()) {
std::vector<uint8_t> encoded = std::move(res.value()); // Bytes of encoded data
}

template <typename T>
outcome::result<T> decode(ScaleDecoderStream &s)
```
are wrappers over ```<<``` and ```>>``` operators described above.
// template <typename T>
// outcome::result<T> decode(const RangeOfBytes auto& span);
using ::scale::impl::memory::decode;

Encoding data using ```encode``` convenience function looks as follows:
```c++
std::vector<uint32_t> v = {1u, 2u, 3u, 4u};
auto &&result = encode(v);
if (!res) {
// handle error
BytesArray data = {...};
auto res = decode<SomeClass>(data); // <- Just one-line call
if (res.has_value()) {
SomeClass object = std::move(res.value()); // Decoded value
}
```

Decoding data using ```decode``` convenience function looks as follows:
using ::scale::impl::bytes::EncoderToVector;

SomeClass object = {...};
std::vector<uint8_t> out;
EncoderToVector encoder;
try {
encoder << object;
// or encode(object, decoder);
std::vector<uint8_t> encoded = std::move(res.value())
} catch ...

using ::scale::impl::bytes::DecoderFromBytes;

BytesArray in = {...};
DecoderFromSpan decoder(in);
try {
Object object;
decoder >> object;
// or decode(object, decoder);
} catch ...

```c++
ByteArray bytes = {...};
outcome::result<MyType> result = decode<MyType>(bytes);
if (!result) {
// handle error
}
```
or
```c++
ByteArray bytes = {...};
ScaleDecoderStream s(bytes);
outcome::result<MyType> result = decode<MyType>(s);
if (!result) {
// handle error
}
```
4 changes: 2 additions & 2 deletions cmake/Hunter/config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@

hunter_config(
qtils
URL https://github.com/qdrvm/qtils/archive/16e7c819dd50af2f64e2d319b918d0d815332266.tar.gz
SHA1 71989938b5c8b7650eaf1a8195c2b52c5a8c250b
URL https://github.com/qdrvm/qtils/archive/9a64dfd6ed0226dec29805aa89d4c713a6f81d9f.tar.gz
SHA1 16c0269175018e88c33090f9fbdaa230c8fdb911
)
Loading