sui::bcsThis module implements BCS (de)serialization in Move. Full specification can be found here: https://github.com/diem/bcs
Short summary (for Move-supported types):
Usage example:
/// This function reads u8 and u64 value from the input
/// and returns the rest of the bytes.
fun deserialize(bytes: vector<u8>): (u8, u64, vector<u8>) {
use sui::bcs::{Self, BCS};
let prepared: BCS = bcs::new(bytes);
let (u8_value, u64_value) = (
prepared.peel_u8(),
prepared.peel_u64()
);
// unpack bcs struct
let leftovers = prepared.into_remainder_bytes();
(u8_value, u64_value, leftovers)
}
BCSto_bytesnewinto_remainder_bytespeel_addresspeel_boolpeel_u8peel_numpeel_u16peel_u32peel_u64peel_u128peel_u256peel_vec_lengthpeel_vecpeel_vec_addresspeel_vec_boolpeel_vec_u8peel_vec_vec_u8peel_vec_u16peel_vec_u32peel_vec_u64peel_vec_u128peel_vec_u256peel_enum_tagpeel_optionpeel_option_addresspeel_option_boolpeel_option_u8peel_option_u16peel_option_u32peel_option_u64peel_option_u128peel_option_u256use std::ascii;
use std::bcs;
use std::option;
use std::string;
use std::vector;
use sui::address;
use sui::hex;
BCSA helper struct that saves resources on operations. For better
vector performance, it stores reversed bytes of the BCS and
enables use of vector::pop_back.
public struct BCS has copy, drop, store
bytes: vector<u8>
For when bytes length is less than required for deserialization.
const EOutOfRange: u64 = 0;
For when the boolean value different than 0 or 1.
const ENotBool: u64 = 1;
For when ULEB byte is out of range (or not found).
const ELenOutOfRange: u64 = 2;
to_bytesGet BCS serialized bytes for any value.
Re-exports stdlib bcs::to_bytes.
public fun to_bytes<T>(value: &T): vector<u8>
public fun to_bytes<T>(value: &T): vector<u8> {
bcs::to_bytes(value)
}
newCreates a new instance of BCS wrapper that holds inversed bytes for better performance.
public fun new(bytes: vector<u8>): sui::bcs::BCS
into_remainder_bytesUnpack the BCS struct returning the leftover bytes.
Useful for passing the data further after partial deserialization.
public fun into_remainder_bytes(bcs: sui::bcs::BCS): vector<u8>
public fun into_remainder_bytes(bcs: BCS): vector<u8> {
let BCS { mut bytes } = bcs;
bytes.reverse();
bytes
}
peel_addressRead address from the bcs-serialized bytes.
public fun peel_address(bcs: &mut sui::bcs::BCS): address
public fun peel_address(bcs: &mut BCS): address {
assert!(bcs.bytes.length() >= address::length(), EOutOfRange);
address::from_bytes(vector::tabulate!(address::length(), |_| bcs.bytes.pop_back()))
}
peel_boolRead a bool value from bcs-serialized bytes.
public fun peel_bool(bcs: &mut sui::bcs::BCS): bool
public fun peel_bool(bcs: &mut BCS): bool {
let value = bcs.peel_u8();
if (value == 0) false
else if (value == 1) true
else abort ENotBool
}
peel_u8Read u8 value from bcs-serialized bytes.
public fun peel_u8(bcs: &mut sui::bcs::BCS): u8
public fun peel_u8(bcs: &mut BCS): u8 {
assert!(bcs.bytes.length() >= 1, EOutOfRange);
bcs.bytes.pop_back()
}
peel_nummacro fun peel_num<$I, $T>($bcs: &mut sui::bcs::BCS, $len: u64, $bits: $I): $T
macro fun peel_num<$I, $T>($bcs: &mut BCS, $len: u64, $bits: $I): $T {
let bcs = $bcs;
assert!(bcs.bytes.length() >= $len, EOutOfRange);
let mut value: $T = 0;
let mut i: $I = 0;
let bits = $bits;
while (i < bits) {
let byte = bcs.bytes.pop_back() as $T;
value = value + (byte << (i as u8));
i = i + 8;
};
value
}
peel_u16Read u16 value from bcs-serialized bytes.
public fun peel_u16(bcs: &mut sui::bcs::BCS): u16
peel_u32Read u32 value from bcs-serialized bytes.
public fun peel_u32(bcs: &mut sui::bcs::BCS): u32
peel_u64Read u64 value from bcs-serialized bytes.
public fun peel_u64(bcs: &mut sui::bcs::BCS): u64
peel_u128Read u128 value from bcs-serialized bytes.
public fun peel_u128(bcs: &mut sui::bcs::BCS): u128
peel_u256Read u256 value from bcs-serialized bytes.
public fun peel_u256(bcs: &mut sui::bcs::BCS): u256
peel_vec_lengthRead ULEB bytes expecting a vector length. Result should
then be used to perform peel_* operation LEN times.
In BCS vector length is implemented with ULEB128;
See more here: https://en.wikipedia.org/wiki/LEB128
public fun peel_vec_length(bcs: &mut sui::bcs::BCS): u64
public fun peel_vec_length(bcs: &mut BCS): u64 {
let (mut total, mut shift, mut len) = (0u64, 0, 0);
loop {
assert!(len <= 4, ELenOutOfRange);
let byte = bcs.bytes.pop_back() as u64;
len = len + 1;
total = total | ((byte & 0x7f) << shift);
if ((byte & 0x80) == 0) break;
shift = shift + 7;
};
total
}
peel_vecPeel vector<$T> from serialized bytes, where $peel: |&mut BCS| -> $T gives the
functionality of peeling each value.
public macro fun peel_vec<$T>($bcs: &mut sui::bcs::BCS, $peel: |&mut sui::bcs::BCS| -> $T): vector<$T>
public macro fun peel_vec<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): vector<$T> {
let bcs = $bcs;
vector::tabulate!(bcs.peel_vec_length(), |_| $peel(bcs))
}
peel_vec_addressPeel a vector of address from serialized bytes.
public fun peel_vec_address(bcs: &mut sui::bcs::BCS): vector<address>
public fun peel_vec_address(bcs: &mut BCS): vector<address> {
bcs.peel_vec!(|bcs| bcs.peel_address())
}
peel_vec_boolPeel a vector of address from serialized bytes.
public fun peel_vec_bool(bcs: &mut sui::bcs::BCS): vector<bool>
public fun peel_vec_bool(bcs: &mut BCS): vector<bool> {
bcs.peel_vec!(|bcs| bcs.peel_bool())
}
peel_vec_u8Peel a vector of u8 (eg string) from serialized bytes.
public fun peel_vec_u8(bcs: &mut sui::bcs::BCS): vector<u8>
public fun peel_vec_u8(bcs: &mut BCS): vector<u8> {
bcs.peel_vec!(|bcs| bcs.peel_u8())
}
peel_vec_vec_u8Peel a vector<vector<u8>> (eg vec of string) from serialized bytes.
public fun peel_vec_vec_u8(bcs: &mut sui::bcs::BCS): vector<vector<u8>>
public fun peel_vec_vec_u8(bcs: &mut BCS): vector<vector<u8>> {
bcs.peel_vec!(|bcs| bcs.peel_vec_u8())
}
peel_vec_u16Peel a vector of u16 from serialized bytes.
public fun peel_vec_u16(bcs: &mut sui::bcs::BCS): vector<u16>
public fun peel_vec_u16(bcs: &mut BCS): vector<u16> {
bcs.peel_vec!(|bcs| bcs.peel_u16())
}
peel_vec_u32Peel a vector of u32 from serialized bytes.
public fun peel_vec_u32(bcs: &mut sui::bcs::BCS): vector<u32>
public fun peel_vec_u32(bcs: &mut BCS): vector<u32> {
bcs.peel_vec!(|bcs| bcs.peel_u32())
}
peel_vec_u64Peel a vector of u64 from serialized bytes.
public fun peel_vec_u64(bcs: &mut sui::bcs::BCS): vector<u64>
public fun peel_vec_u64(bcs: &mut BCS): vector<u64> {
bcs.peel_vec!(|bcs| bcs.peel_u64())
}
peel_vec_u128Peel a vector of u128 from serialized bytes.
public fun peel_vec_u128(bcs: &mut sui::bcs::BCS): vector<u128>
public fun peel_vec_u128(bcs: &mut BCS): vector<u128> {
bcs.peel_vec!(|bcs| bcs.peel_u128())
}
peel_vec_u256Peel a vector of u256 from serialized bytes.
public fun peel_vec_u256(bcs: &mut sui::bcs::BCS): vector<u256>
public fun peel_vec_u256(bcs: &mut BCS): vector<u256> {
bcs.peel_vec!(|bcs| bcs.peel_u256())
}
peel_enum_tagPeel enum from serialized bytes, where $f takes a tag value and returns
the corresponding enum variant. Move enums are limited to 127 variants,
however the tag can be any u32 value.
Example:
let my_enum = match (bcs.peel_enum_tag()) {
0 => Enum::Empty,
1 => Enum::U8(bcs.peel_u8()),
2 => Enum::U16(bcs.peel_u16()),
3 => Enum::Struct { a: bcs.peel_address(), b: bcs.peel_u8() },
_ => abort,
};
public fun peel_enum_tag(bcs: &mut sui::bcs::BCS): u32
public fun peel_enum_tag(bcs: &mut BCS): u32 {
let tag = bcs.peel_vec_length();
assert!(tag <= std::u32::max_value!() as u64, EOutOfRange);
tag as u32
}
peel_optionPeel Option<$T> from serialized bytes, where $peel: |&mut BCS| -> $T gives the
functionality of peeling the inner value.
public macro fun peel_option<$T>($bcs: &mut sui::bcs::BCS, $peel: |&mut sui::bcs::BCS| -> $T): std::option::Option<$T>
public macro fun peel_option<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): Option<$T> {
let bcs = $bcs;
if (bcs.peel_bool()) option::some($peel(bcs)) else option::none()
}
peel_option_addressPeel Option<address> from serialized bytes.
public fun peel_option_address(bcs: &mut sui::bcs::BCS): std::option::Option<address>
public fun peel_option_address(bcs: &mut BCS): Option<address> {
bcs.peel_option!(|bcs| bcs.peel_address())
}
peel_option_boolPeel Option<bool> from serialized bytes.
public fun peel_option_bool(bcs: &mut sui::bcs::BCS): std::option::Option<bool>
public fun peel_option_bool(bcs: &mut BCS): Option<bool> {
bcs.peel_option!(|bcs| bcs.peel_bool())
}
peel_option_u8Peel Option<u8> from serialized bytes.
public fun peel_option_u8(bcs: &mut sui::bcs::BCS): std::option::Option<u8>
public fun peel_option_u8(bcs: &mut BCS): Option<u8> {
bcs.peel_option!(|bcs| bcs.peel_u8())
}
peel_option_u16Peel Option<u16> from serialized bytes.
public fun peel_option_u16(bcs: &mut sui::bcs::BCS): std::option::Option<u16>
public fun peel_option_u16(bcs: &mut BCS): Option<u16> {
bcs.peel_option!(|bcs| bcs.peel_u16())
}
peel_option_u32Peel Option<u32> from serialized bytes.
public fun peel_option_u32(bcs: &mut sui::bcs::BCS): std::option::Option<u32>
public fun peel_option_u32(bcs: &mut BCS): Option<u32> {
bcs.peel_option!(|bcs| bcs.peel_u32())
}
peel_option_u64Peel Option<u64> from serialized bytes.
public fun peel_option_u64(bcs: &mut sui::bcs::BCS): std::option::Option<u64>
public fun peel_option_u64(bcs: &mut BCS): Option<u64> {
bcs.peel_option!(|bcs| bcs.peel_u64())
}
peel_option_u128Peel Option<u128> from serialized bytes.
public fun peel_option_u128(bcs: &mut sui::bcs::BCS): std::option::Option<u128>
public fun peel_option_u128(bcs: &mut BCS): Option<u128> {
bcs.peel_option!(|bcs| bcs.peel_u128())
}
peel_option_u256Peel Option<u256> from serialized bytes.
public fun peel_option_u256(bcs: &mut sui::bcs::BCS): std::option::Option<u256>
public fun peel_option_u256(bcs: &mut BCS): Option<u256> {
bcs.peel_option!(|bcs| bcs.peel_u256())
}