Documentation ¶
Overview ¶
Package bcs implements Binary Canonical Serialization BCS.
The bcs package can be used to serialize and deserialize complex types into a binary canonical format that is non-self describing. Meaning that you will need to know the format ahead of time in order to serialize and deserialize. Check out Serializer for serialization and Deserializer for deserialization.
Index ¶
- func Deserialize(dest Unmarshaler, bytes []byte) error
- func DeserializeOption[T any](des *Deserializer, deserialize func(des *Deserializer, out *T)) *T
- func DeserializeSequence[T any](des *Deserializer) []T
- func DeserializeSequenceWithFunction[T any](des *Deserializer, deserialize func(des *Deserializer, out *T)) []T
- func Serialize(value Marshaler) (bytes []byte, err error)
- func SerializeBool(input bool) ([]byte, error)
- func SerializeBytes(input []byte) ([]byte, error)
- func SerializeOption[T any](ser *Serializer, input *T, serialize func(ser *Serializer, item T))
- func SerializeSequence[AT []T, T any](array AT, ser *Serializer)
- func SerializeSequenceOnly[AT []T, T any](input AT) ([]byte, error)
- func SerializeSequenceWithFunction[AT []T, T any](array AT, ser *Serializer, serialize func(ser *Serializer, item T))
- func SerializeSingle(marshal func(ser *Serializer)) (bytes []byte, err error)
- func SerializeU128(input big.Int) ([]byte, error)
- func SerializeU16(input uint16) ([]byte, error)
- func SerializeU256(input big.Int) ([]byte, error)
- func SerializeU32(input uint32) ([]byte, error)
- func SerializeU64(input uint64) ([]byte, error)
- func SerializeU8(input uint8) ([]byte, error)
- type Deserializer
- func (des *Deserializer) Bool() bool
- func (des *Deserializer) Error() error
- func (des *Deserializer) ReadBytes() []byte
- func (des *Deserializer) ReadFixedBytes(length int) []byte
- func (des *Deserializer) ReadFixedBytesInto(dest []byte)
- func (des *Deserializer) ReadString() string
- func (des *Deserializer) Remaining() int
- func (des *Deserializer) SetError(err error)
- func (des *Deserializer) Struct(v Unmarshaler)
- func (des *Deserializer) U128() big.Int
- func (des *Deserializer) U16() uint16
- func (des *Deserializer) U256() big.Int
- func (des *Deserializer) U32() uint32
- func (des *Deserializer) U64() uint64
- func (des *Deserializer) U8() uint8
- func (des *Deserializer) Uleb128() uint32
- type Marshaler
- type Serializer
- func (ser *Serializer) Bool(v bool)
- func (ser *Serializer) Error() error
- func (ser *Serializer) FixedBytes(v []byte)
- func (ser *Serializer) Reset()
- func (ser *Serializer) SetError(err error)
- func (ser *Serializer) Struct(v Marshaler)
- func (ser *Serializer) ToBytes() []byte
- func (ser *Serializer) U128(v big.Int)
- func (ser *Serializer) U16(v uint16)
- func (ser *Serializer) U256(v big.Int)
- func (ser *Serializer) U32(v uint32)
- func (ser *Serializer) U64(v uint64)
- func (ser *Serializer) U8(v uint8)
- func (ser *Serializer) Uleb128(val uint32)
- func (ser *Serializer) WriteBytes(v []byte)
- func (ser *Serializer) WriteString(v string)
- type Struct
- type Unmarshaler
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Deserialize ¶
func Deserialize(dest Unmarshaler, bytes []byte) error
Deserialize deserializes a single item from bytes.
This function will error if there are remaining bytes.
func DeserializeOption ¶ added in v1.2.0
func DeserializeOption[T any](des *Deserializer, deserialize func(des *Deserializer, out *T)) *T
DeserializeOption deserializes an optional value
Under the hood, this is represented as a 0 or 1 length array ¶
Here's an example for handling an optional value:
// For a Some(10) value bytes == []byte{0x01, 0x0A} des := NewDeserializer(bytes) output := DeserializeOption(des, nil, func(des *Deserializer, out *uint8) { out = des.U8() }) // output == &10 // For a None value bytes2 == []byte{0x00} des2 := NewDeserializer(bytes2) output := DeserializeOption(des2, nil, func(des *Deserializer, out *uint8) { out = des.U8() }) // output == nil
func DeserializeSequence ¶
func DeserializeSequence[T any](des *Deserializer) []T
DeserializeSequence deserializes an Unmarshaler implementation array
This lets you deserialize a whole sequence of Unmarshaler, and will fail if any member fails. All sequences are prefixed with an Uleb128 length.
func DeserializeSequenceWithFunction ¶
func DeserializeSequenceWithFunction[T any](des *Deserializer, deserialize func(des *Deserializer, out *T)) []T
DeserializeSequenceWithFunction deserializes any array with the given function
This lets you deserialize a whole sequence of any type, and will fail if any member fails. All sequences are prefixed with an Uleb128 length.
func Serialize ¶
Serialize serializes a single item
type MyStruct struct { num uint64 } func (str *MyStruct) MarshalBCS(ser *Serialize) { ser.U64(num) } struct := &MyStruct{ num: 100 } bytes, _ := Serialize(struct)
func SerializeBytes ¶
SerializeBytes Serializes a single byte array
input := []byte{0x1, 0x2} bytes, _ := SerializeBytes(input)
func SerializeOption ¶ added in v1.2.0
func SerializeOption[T any](ser *Serializer, input *T, serialize func(ser *Serializer, item T))
SerializeOption serializes an optional value
Under the hood, this is represented as a 0 or 1 length array ¶
Here's an example for handling an optional value:
// For a Some(10) value input := uint8(10) ser := &Serializer{} bytes, _ := SerializeOption(ser, &input, func(ser *Serializer, item uint8) { ser.U8(item) }) // bytes == []byte{0x01,0x0A} // For a None value ser2 := &Serializer{} bytes2, _ := SerializeOption(ser2, nil, func(ser *Serializer, item uint8) { ser.U8(item) }) // bytes2 == []byte{0x00}
func SerializeSequence ¶
func SerializeSequence[AT []T, T any](array AT, ser *Serializer)
SerializeSequence serializes a sequence of Marshaler implemented types. Prefixed with the length of the sequence.
It works with both array values by reference and by value:
type MyStruct struct { num uint64 } func (str *MyStruct) MarshalBCS(ser *Serialize) { ser.U64(num) } myArray := []MyStruct{ MyStruct{num: 0}, MyStruct{num: 1}, MyStruct{num: 2}, } serializer := &Serializer{} SerializeSequence(myArray, ser) bytes := serializer.ToBytes()
func SerializeSequenceOnly ¶
SerializeSequenceOnly serializes a sequence into a single value using SerializeSequence
type MyStruct struct { num uint64 } func (str *MyStruct) MarshalBCS(ser *Serialize) { ser.U64(num) } myArray := []MyStruct{ MyStruct{num: 0}, MyStruct{num: 1}, MyStruct{num: 2}, } bytes, err := SerializeSequenceOnly(myArray)
func SerializeSequenceWithFunction ¶
func SerializeSequenceWithFunction[AT []T, T any](array AT, ser *Serializer, serialize func(ser *Serializer, item T))
SerializeSequenceWithFunction allows custom serialization of a sequence, which can be useful for non-bcs.Struct types
array := []string{"hello", "blockchain"} SerializeSequenceWithFunction(array, func(ser *Serializer, item string) { ser.WriteString(item) }
func SerializeSingle ¶
func SerializeSingle(marshal func(ser *Serializer)) (bytes []byte, err error)
SerializeSingle is a convenience function, to not have to create a serializer to serialize one value
Here's an example for handling a nested byte array
input := [][]byte{[]byte{0x1}, []byte{0x2}} bytes, _ := SerializeSingle(func(ser *Serializer) { ser.Uleb128(len(input)) for _, list := range input { ser.WriteBytes(list) } })
func SerializeU128 ¶
SerializeU128 Serializes a single uint128
u128 := big.NewInt(1) bytes, _ := SerializeU128(u128)
func SerializeU256 ¶
SerializeU256 Serializes a single uint256
u256 := big.NewInt(1) bytes, _ := SerializeU256(u256)
Types ¶
type Deserializer ¶
type Deserializer struct {
// contains filtered or unexported fields
}
Deserializer is a type to deserialize a known set of bytes. The reader must know the types, as the format is not self-describing.
Use NewDeserializer to initialize the Deserializer
bytes := []byte{0x01} deserializer := NewDeserializer(bytes) num := deserializer.U8() if deserializer.Error() != nil { return deserializer.Error() }
func NewDeserializer ¶
func NewDeserializer(bytes []byte) *Deserializer
NewDeserializer creates a new Deserializer from a byte array.
func (*Deserializer) Bool ¶
func (des *Deserializer) Bool() bool
Bool deserializes a single byte as a bool
func (*Deserializer) Error ¶
func (des *Deserializer) Error() error
Error If there has been any error, return it
func (*Deserializer) ReadBytes ¶
func (des *Deserializer) ReadBytes() []byte
ReadBytes reads bytes prefixed with a length
func (*Deserializer) ReadFixedBytes ¶
func (des *Deserializer) ReadFixedBytes(length int) []byte
ReadFixedBytes reads bytes not-prefixed with a length
func (*Deserializer) ReadFixedBytesInto ¶
func (des *Deserializer) ReadFixedBytesInto(dest []byte)
ReadFixedBytesInto reads bytes not-prefixed with a length into a byte array
func (*Deserializer) ReadString ¶
func (des *Deserializer) ReadString() string
ReadString reads UTF-8 bytes prefixed with a length
func (*Deserializer) Remaining ¶
func (des *Deserializer) Remaining() int
Remaining tells the remaining bytes, which can be useful if there were more bytes than expected
bytes := []byte{0x01, 0x02} deserializer := NewDeserializer(bytes) num := deserializer.U8() deserializer.Remaining == 1
func (*Deserializer) SetError ¶
func (des *Deserializer) SetError(err error)
SetError If the data is well-formed but nonsense, UnmarshalBCS() code can set error
func (*Deserializer) Struct ¶
func (des *Deserializer) Struct(v Unmarshaler)
Struct reads an Unmarshaler implementation from bcs bytes
This is used for handling types outside the provided primitives
func (*Deserializer) U128 ¶
func (des *Deserializer) U128() big.Int
U128 deserializes a single unsigned 128-bit integer
func (*Deserializer) U16 ¶
func (des *Deserializer) U16() uint16
U16 deserializes a single unsigned 16-bit integer
func (*Deserializer) U256 ¶
func (des *Deserializer) U256() big.Int
U256 deserializes a single unsigned 256-bit integer
func (*Deserializer) U32 ¶
func (des *Deserializer) U32() uint32
U32 deserializes a single unsigned 32-bit integer
func (*Deserializer) U64 ¶
func (des *Deserializer) U64() uint64
func (*Deserializer) U8 ¶
func (des *Deserializer) U8() uint8
U8 deserializes a single unsigned 8-bit integer
func (*Deserializer) Uleb128 ¶
func (des *Deserializer) Uleb128() uint32
Uleb128 deserializes a 32-bit integer from a variable length Unsigned LEB128
type Marshaler ¶
type Marshaler interface { // MarshalBCS implements a way to serialize the type into BCS. Note that the error will need to be directly set // using [Serializer.SetError] on the [Serializer]. If using this function, you will need to use [Serializer.Error] // to retrieve the error. MarshalBCS(ser *Serializer) }
Marshaler is an interface for any type that can be serialized into BCS
It's highly suggested to implement on a pointer to a type, and not the type directly. For example, you could implement a simple Marshaler for a given struct.
type MyStruct struct { num uint8 boolean bool } func (str *MyStruct) MarshalBCS(ser *Serializer) { ser.U8(str.num) ser.Bool(str.boolean) }
Additionally, if there is expected data, you can add errors to serialization. It's suggested to stop serialization after any errors.
type MyStruct struct { num uint8 // Only allowed to be 0-10 boolean bool } func (str *MyStruct) MarshalBCS(ser *Serializer) { if str.num > 10 { ser.SetError(fmt.Error("Cannot serialize MyStruct, num is greater than 10: %d", str.num) return } ser.U8(str.num) ser.Bool(str.boolean) }
type Serializer ¶
type Serializer struct {
// contains filtered or unexported fields
}
Serializer is a holding type to serialize a set of items into one shared buffer
serializer := &Serializer{} serializer.U64(uint64(10)) serializedBytes := serializer.ToBytes()
func (*Serializer) Bool ¶
func (ser *Serializer) Bool(v bool)
Bool serialize a bool into a single byte, 0x01 for true and 0x00 for false
func (*Serializer) Error ¶
func (ser *Serializer) Error() error
Error the error if serialization has failed at any point
func (*Serializer) FixedBytes ¶
func (ser *Serializer) FixedBytes(v []byte)
FixedBytes similar to Serializer.WriteBytes, but it forgoes the length header. This is useful if you know the fixed length size of the data, such as AccountAddress
func (*Serializer) SetError ¶
func (ser *Serializer) SetError(err error)
SetError If the data is well-formed but nonsense, [Marshaler.MarshalBCS] code can set the error.
func (*Serializer) Struct ¶
func (ser *Serializer) Struct(v Marshaler)
Struct uses custom serialization for a Marshaler implementation.
func (*Serializer) ToBytes ¶
func (ser *Serializer) ToBytes() []byte
ToBytes outputs the encoded bytes
func (*Serializer) U128 ¶
func (ser *Serializer) U128(v big.Int)
U128 serialize an unsigned 128-bit integer in little-endian format
func (*Serializer) U16 ¶
func (ser *Serializer) U16(v uint16)
U16 serialize an unsigned 16-bit integer in little-endian format
func (*Serializer) U256 ¶
func (ser *Serializer) U256(v big.Int)
U256 serialize an unsigned 256-bit integer in little-endian format
func (*Serializer) U32 ¶
func (ser *Serializer) U32(v uint32)
U32 serialize an unsigned 32-bit integer in little-endian format
func (*Serializer) U64 ¶
func (ser *Serializer) U64(v uint64)
U64 serialize an unsigned 64-bit integer in little-endian format
func (*Serializer) Uleb128 ¶
func (ser *Serializer) Uleb128(val uint32)
Uleb128 serialize an unsigned 32-bit integer as an Uleb128. This is used specifically for sequence lengths, and enums.
func (*Serializer) WriteBytes ¶
func (ser *Serializer) WriteBytes(v []byte)
WriteBytes serialize an array of bytes with its length first as an Uleb128.
func (*Serializer) WriteString ¶
func (ser *Serializer) WriteString(v string)
WriteString similar to Serializer.WriteBytes using the UTF-8 byte representation of the string
type Struct ¶
type Struct interface { Marshaler Unmarshaler }
Struct is an interface for an on-chain type. It must be able to be both Marshaler and Unmarshaler for BCS
type Unmarshaler ¶
type Unmarshaler interface { // UnmarshalBCS implements a way to deserialize the type into BCS. Note that the error will need to be directly set // using [Deserializer.SetError] on the [Deserializer]. If using this function, you will need to use [Deserializer.Error] // to retrieve the error. UnmarshalBCS(des *Deserializer) }
Unmarshaler is an interface for any type that can be deserialized from BCS
It's highly suggested to implement on a pointer to a type, and not the type directly. For example, you could implement a simple Unmarshaler for a given struct. You will need to add any appropriate error handling.
type MyStruct struct { num uint8 boolean bool } func (str *MyStruct) UnmarshalBCS(des *Deserializer) { str.num = des.U8() str.boolean = des.Bool() }
Additionally, if there is expected formatting errors, you can add errors to deserialization. It's suggested to stop serialization after any errors.
type MyStruct struct { num uint8 // Only allowed to be 0-10 boolean bool } func (str *MyStruct) UnmarshalBCS(des *Deserializer) { str.num = des.U8() if des.Error() { // End early, since deserialization failed return } if str.num > 10 { ser.SetError(fmt.Error("Cannot deserialize MyStruct, num is greater than 10: %d", str.num) return } str.boolean = des.Bool() }