|
| 1 | +# SCALE codec C++ implementation |
| 2 | +fully meets polkadot specification.\ |
| 3 | +It allows encoding and decoding following data types: |
| 4 | +* Built-in integer types specified by size: |
| 5 | + * ```uint8_t```, ```int8_t``` |
| 6 | + * ```uint16_t```, ```int16_t``` |
| 7 | + * ```uint32_t```, ```int32_t``` |
| 8 | + * ```uint64_t```, ```int64_t``` |
| 9 | +* bool values |
| 10 | +* pairs of types represented by ```std::pair<T1, T2>``` |
| 11 | +* compact integers represented by CompactInteger type |
| 12 | +* optional values represented by ```boost::optional<T>``` |
| 13 | + * as special case of optional values ```boost::optional<bool>``` is encoded using one byte following specification. |
| 14 | +* collections of items represented by ```std::vector<T>``` |
| 15 | +* variants represented by ```boost::variant<T...>``` |
| 16 | + |
| 17 | +## ScaleEncoderStream |
| 18 | +class ScaleEncoderStream is in charge of encoding data |
| 19 | + |
| 20 | +```c++ |
| 21 | +ScaleEncoderStream s; |
| 22 | +uint32_t ui32 = 123u; |
| 23 | +uint8_t ui8 = 234u; |
| 24 | +std::string str = "asdasdasd"; |
| 25 | +auto * raw_str = "zxczxczx"; |
| 26 | +bool b = true; |
| 27 | +CompactInteger ci = 123456789; |
| 28 | +boost::variant<uint8_t, uint32_t, CompactInteger> vint = CompactInteger(12345); |
| 29 | +boost::optional<std::string> opt_str = "asdfghjkl"; |
| 30 | +boost::optional<bool> opt_bool = false; |
| 31 | +std::pair<uint8_t, uint32_t> pair{1u, 2u}; |
| 32 | +std::vector<uint32_t> coll_ui32 = {1u, 2u, 3u, 4u}; |
| 33 | +std::vector<std::string> coll_str = {"asd", "fgh", "jkl"}; |
| 34 | +std::vector<std::vector<int32_t>> coll_coll_i32 = {{1, 2, 3}, {4, 5, 6, 7}}; |
| 35 | +try { |
| 36 | + s << ui32 << ui8 << str << raw_str << b << ci << vint; |
| 37 | + s << opt_str << opt_bool << pair << coll_ui32 << coll_str << coll_coll_i32; |
| 38 | +} catch (std::runtime_error &e) { |
| 39 | + // handle error |
| 40 | + // for example make and return outcome::result |
| 41 | + return outcome::failure(e.code()); |
| 42 | +} |
| 43 | +``` |
| 44 | +You can now get encoded data: |
| 45 | +```c++ |
| 46 | +ByteArray data = s.data(); |
| 47 | +``` |
| 48 | + |
| 49 | +## ScaleDecoderStream |
| 50 | +class ScaleEncoderStream is in charge of encoding data |
| 51 | + |
| 52 | +```c++ |
| 53 | +ByteArray bytes = {...}; |
| 54 | +ScaleEncoderStream s(bytes); |
| 55 | +uint32_t ui32 = 0u; |
| 56 | +uint8_t ui8 = 0u; |
| 57 | +std::string str; |
| 58 | +bool b = true; |
| 59 | +CompactInteger ci; |
| 60 | +boost::variant<uint8_t, uint32_t, CompactInteger> vint; |
| 61 | +boost::optional<std::string> opt_str; |
| 62 | +boost::optional<bool> opt_bool; |
| 63 | +std::pair<uint8_t, uint32_t> pair{}; |
| 64 | +std::vector<uint32_t> coll_ui32; |
| 65 | +std::vector<std::string> coll_str; |
| 66 | +std::vector<std::vector<int32_t>> coll_coll_i32; |
| 67 | +try { |
| 68 | + s >> ui32 >> ui8 >> str >> b >> ci >> vint; |
| 69 | + s >> opt_str >> opt_bool >> pair >> coll_ui32 >> coll_str >> coll_coll_i32; |
| 70 | +} catch (std::system_error &e) { |
| 71 | + // handle error |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +## Custom types |
| 76 | +You may need to encode or decode custom data types, you have to define custom << and >> operators. |
| 77 | +Please note, that your custom data types must be default-constructible. |
| 78 | +```c++ |
| 79 | +struct MyType { |
| 80 | + int a = 0; |
| 81 | + std::string b; |
| 82 | +}; |
| 83 | + |
| 84 | +ScaleEncoderStream &operator<<(ScaleEncoderStream &s, const MyType &v) { |
| 85 | + return s << v.a << v.b; |
| 86 | +} |
| 87 | + |
| 88 | +ScaleDecoderStream &operator>>(ScaleDecoderStream &s, MyType &v) { |
| 89 | + return s >> v.a >> v.b; |
| 90 | +} |
| 91 | +``` |
| 92 | +Now you can use them in collections, optionals and variants |
| 93 | +```c++ |
| 94 | +std::vector<MyType> v = {{1, "asd"}, {2, "qwe"}}; |
| 95 | +ScaleEncoderStream s; |
| 96 | +try { |
| 97 | + s << v; |
| 98 | +} catch (...) { |
| 99 | + // handle error |
| 100 | +} |
| 101 | +``` |
| 102 | +The same for ```ScaleDecoderStream``` |
| 103 | +```c++ |
| 104 | +ByteArray data = {...}; |
| 105 | +std::vector<MyType> v; |
| 106 | +ScaleDecoderStream s{data}; |
| 107 | +try { |
| 108 | + s >> v; |
| 109 | +} catch (...) { |
| 110 | + // handle error |
| 111 | +} |
| 112 | +``` |
| 113 | + |
| 114 | +## Convenience functions |
| 115 | +Convenience functions |
| 116 | +```c++ |
| 117 | +template<class T> |
| 118 | +outcome::result<std::vector<uint8_t>> encode(T &&t); |
| 119 | + |
| 120 | +template <class T> |
| 121 | +outcome::result<T> decode(gsl::span<const uint8_t> span) |
| 122 | + |
| 123 | +template <class T> |
| 124 | +outcome::result<T> decode(ScaleDecoderStream &s) |
| 125 | +``` |
| 126 | +are wrappers over ```<<``` and ```>>``` operators described above. |
| 127 | +
|
| 128 | +Encoding data using ```encode``` convenience function looks as follows: |
| 129 | +```c++ |
| 130 | +std::vector<uint32_t> v = {1u, 2u, 3u, 4u}; |
| 131 | +auto &&result = encode(v); |
| 132 | +if (!res) { |
| 133 | + // handle error |
| 134 | +} |
| 135 | +``` |
| 136 | + |
| 137 | +Decoding data using ```decode``` convenience function looks as follows: |
| 138 | + |
| 139 | +```c++ |
| 140 | +ByteArray bytes = {...}; |
| 141 | +outcome::result<MyType> result = decode<MyType>(bytes); |
| 142 | +if (!result) { |
| 143 | + // handle error |
| 144 | +} |
| 145 | +``` |
| 146 | +or |
| 147 | +```c++ |
| 148 | +ByteArray bytes = {...}; |
| 149 | +ScaleDecoderStream s(bytes); |
| 150 | +outcome::result<MyType> result = decode<MyType>(s); |
| 151 | +if (!result) { |
| 152 | + // handle error |
| 153 | +} |
| 154 | +``` |
0 commit comments