Documentation
¶
Overview ¶
bcs (binary canonical serialization) or lcs (libra canonical serialization) is developed from the shuttered libra/diem block chain project.
bcs defines how a struct in rust-lang can be serialized into bytes, and supports features that are unavaibable in golang, such as tagged union or enum.
By "canonical", it means the serialization is deterministic and unique. On many move-lang based blockchains, bcs is the serialization scheme for the struct in move.
Index ¶
- Constants
- func Marshal(v any) ([]byte, error)
- func MustMarshal(v any) []byte
- func NewBigIntFromUint64(i uint64) *big.Int
- func ULEB128Decode[T ULEB128SupportedTypes](r io.Reader) (T, int, error)
- func ULEB128Encode[T ULEB128SupportedTypes](input T) []byte
- func Unmarshal(data []byte, v any) (int, error)
- func UnmarshalAll(data []byte, v any) error
- type Decoder
- type Encoder
- type Enum
- type Marshaler
- type Option
- type ULEB128SupportedTypes
- type Uint128
- func (i Uint128) Big() *big.Int
- func (i *Uint128) Cmp(j *Uint128) int
- func (i Uint128) MarshalBCS() ([]byte, error)
- func (i Uint128) MarshalJSON() ([]byte, error)
- func (i *Uint128) SetBigInt(bigI *big.Int) error
- func (u Uint128) String() string
- func (i *Uint128) UnmarshalBCS(r io.Reader) (int, error)
- func (i *Uint128) UnmarshalJSON(data []byte) error
- func (i *Uint128) UnmarshalText(data []byte) error
- type Unmarshaler
Examples ¶
Constants ¶
const MaxUleb128Length = 10
MaxUleb128Length is the max possible number of bytes for an ULEB128 encoded integer. Go's widest integer is uint64, so the length is 10.
Variables ¶
This section is empty.
Functions ¶
func Marshal ¶
Marshal a value into bcs bytes.
Many constructs supported by bcs don't exist in golang or move-lang.
- Enum is used to simulate the effects of rust enum.
- Use tag `optional` to indicate an optional value in rust. the field must be pointer or interface.
- Use tag `-` to ignore fields.
- Unexported fields are ignored.
Note that bcs doesn't have schema, and field names are irrelevant. The fields of struct are serialized in the order that they are defined.
Pointers are serialized as the type they point to. Nil pointers will be serialized as zero value of the type they point to unless it's marked as `optional`.
Arrays are serialized as fixed length vector (or serialize the each object individually without prefixing the length of the array).
Vanilla maps are not supported, however, the code will error if map is encountered to call out they are not supported and either ignore or provide a customized marshal function.
Channels, functions are silently ignored.
During marshalling process, how v is marshalled depends on if v implemented Marshaler or Enum
func NewBigIntFromUint64 ¶
func ULEB128Decode ¶
func ULEB128Decode[T ULEB128SupportedTypes](r io.Reader) (T, int, error)
ULEB128Decode decodes io.Reader into an integer, returns the resulted value, the number of byte read, and a possible error.
binary.ReadUvarint is not used here because
- it doesn't support returning the number of bytes read.
- it accepts only io.ByteReader, but the recommended way of creating one from bufio.NewReader will read more than 1 byte at the to fill the buffer.
func ULEB128Encode ¶
func ULEB128Encode[T ULEB128SupportedTypes](input T) []byte
ULEB128Encode converts an integer into []byte (see wikipedia and bcs)
This reuses binary.PutUvarint in standard library.
func Unmarshal ¶
Unmarshal unmarshals the bcs serialized data into v.
Refer to notes in Marshal for details how data serialized/deserialized.
During the unmarshalling process
- if Unmarshaler, use "UnmarshalBCS" method.
- if not Unmarshaler but Enum, use the specialization for Enum.
- otherwise standard process.
func UnmarshalAll ¶ added in v0.8.2
UnmarshalAll is like Unmarshal, but will additionally error if the input bytes are not completely consumed by the call to Unmarshal.
This is useful for ensuring that a particular set of bytes *completely* represents the data it is decoded to (i.e. no bytes are left over after decoding).
Types ¶
type Decoder ¶ added in v0.2.0
type Decoder struct {
// contains filtered or unexported fields
}
Decoder takes an io.Reader and decodes value from it.
func NewDecoder ¶ added in v0.2.0
func (*Decoder) Decode ¶ added in v0.2.0
DecodeWithSize decodes a value from the decoder, and returns the number of bytes it consumed from the decoder.
- If the value is Unmarshaler, the corresponding UnmarshalBCS will be called.
- If the value is Enum, it will be special handled for Enum
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder takes an io.Writer and encodes value into it.
func NewEncoder ¶
type Enum ¶
type Enum interface {
// IsBcsEnum doesn't do anything. Its function is to indicate this is an enum for bcs de/serialization.
IsBcsEnum()
}
Enum emulates the rust enum, contains only one method, IsBcsEnum, to indicate this is an enum in bcs.
All the fields of the enum type must be pointers or interfaces except those ignored by "-". The index of the field in the field list is the integer value of the enum.
type AEnum struct { V0 *uint8 // variant 0 V1 *uint16 `bcs:"-"` // ignored, so variant 1 is invalid V2 int `bcs:"-"` // cannot be set to nil, so variant 2 is invalid V3 *uint8 // variant 3 v4 uint32 // Unexported, so ignored. } // IsBcsEnum doesn't do anything besides indicating this is an Enum for BCS. func (a AEnum) IsBcsEnum() {}
If there are mulitple non-nil fields when marshalling, the first one encountered will be serialized.
The method IsBcsEnum doesn't actually do anything besides acting as an indicator.
Example ¶
package main import ( "fmt" "github.com/fardream/go-bcs/bcs" ) type AnotherStruct struct { S string } type EnumExample struct { V0 *uint8 V1 *uint16 `bcs:"-"` V2 *uint32 v3 uint8 V4 *AnotherStruct } // IsBcsEnum tells this is an enum func (e EnumExample) IsBcsEnum() {} func main() { // an enum v0 := &EnumExample{ V0: new(uint8), } *v0.V0 = 42 v0m, err := bcs.Marshal(v0) if err != nil { panic(err) } fmt.Println("v0:", v0m) // first value will be picked up v1 := &EnumExample{ V0: new(uint8), V2: new(uint32), } *v1.V0 = 0 *v1.V2 = 10 v1m, err := bcs.Marshal(v1) if err != nil { panic(err) } fmt.Println("v1:", v1m) // enum must be set v2 := &EnumExample{} _, err = bcs.Marshal(v2) if err == nil { panic(fmt.Errorf("unset enum should error out")) } // setting V1, which is ignored, and v3, which is unexported, should be ignored v3 := &EnumExample{ V1: new(uint16), v3: 90, V4: &AnotherStruct{ S: "abc", }, } v3m, err := bcs.Marshal(v3) if err != nil { panic(err) } // print [4 3 97 98 99], which is 4 (enum int), 3 (size of the bytes of the string), 97=a, 98=b, 99=c fmt.Println("v3:", v3m) }
Output: v0: [0 42] v1: [0 0] v3: [4 3 97 98 99]
type Option ¶ added in v0.6.0
func (*Option[T]) MarshalBCS ¶ added in v0.6.0
type ULEB128SupportedTypes ¶
type ULEB128SupportedTypes interface { ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uint | ~int8 | ~int16 | ~int32 | ~int64 | ~int }
ULEB128SupportedTypes is a contraint interface that limits the input to ULEB128Encode and ULEB128Decode to signed and unsigned integers.
type Uint128 ¶
type Uint128 struct {
// contains filtered or unexported fields
}
Uint128 is like `u128` in move.
func NewUint128 ¶
func NewUint128FromUint64 ¶
func (Uint128) MarshalBCS ¶
func (Uint128) MarshalJSON ¶
func (*Uint128) UnmarshalBCS ¶ added in v0.3.0
func (*Uint128) UnmarshalJSON ¶
func (*Uint128) UnmarshalText ¶
type Unmarshaler ¶
Unmarshaler customizes the unmarshalling behavior for a type.
Compared with other Unmarshalers in golang, the Unmarshaler here takes a io.Reader instead of []byte, since it is difficult to delimit the byte streams without unmarshalling. Method [UnmarshalBCS] returns the number of bytes read, and potentially an error.