You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
Ethan Buchman 8aaa918143 Merge branch 'develop' of https://github.com/tendermint/tendermint into develop 10 years ago
..
README.md Include peer round states in the dump_consensus_state RPC call. 10 years ago
binary.go Begin writing debora 10 years ago
byteslice.go binary: prevent runaway alloc 10 years ago
codec.go Dot import -> named import 10 years ago
int.go Dot import -> named import 10 years ago
log.go Package import path change 10 years ago
reflect.go binary: prevent runaway alloc 10 years ago
reflect_test.go binary: prevent runaway alloc 10 years ago
string.go Added README docs for account/binary and renamed UInt -> Uint etc. 10 years ago
time.go Refactor Tx, Validator, and Account structure 10 years ago
util.go Support nil pointers for Binary. 10 years ago

README.md

NOTICE

This documentation is out of date.

  • 0x00 is reserved as a nil byte for RegisterInterface
  • moved TypeByte() into RegisterInterface/ConcreteType
  • Pointers that don't have a declared TypeByte() are encoded with a leading 0x00 (nil) or 0x01.

tendermint/binary

The binary submodule encodes primary types and structs into bytes.

Primary types

uint*, int*, string, time, byteslice and byteslice-slice types can be encoded and decoded with the following methods:

The following writes o uint64 to w io.Writer, and increments n and/or sets err

WriteUint64(o uint64, w io.Writer, n *int64, err *error)

// Typical usage:
buf, n, err := new(bytes.Buffer), new(int64), new(error)
WriteUint64(uint64(x), buf, n, err)
if *err != nil {
    panic(err)
}

The following reads a uint64 from r io.Reader, and increments n and/or sets err

var o = ReadUint64(r io.Reader, n *int64, err *error)

Similar methods for uint32, uint16, uint8, int64, int32, int16, int8 exist. Protobuf variable length encoding is done with uint and int types:

WriteUvarint(o uint, w io.Writer, n *int64, err *error)
var o = ReadUvarint(r io.Reader, n *int64, err *error)

Byteslices can be written with:

WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error)

Byteslices (and all slices such as byteslice-slices) are prepended with uvarint encoded length, so ReadByteSlice() knows how many bytes to read.

Note that there is no type information encoded -- the caller is assumed to know what types to decode.

Struct Types

Struct types can be automatically encoded with reflection. Unlike json-encoding, no field name or type information is encoded. Field values are simply encoded in order.

type Foo struct {
    MyString        string
    MyUint32        uint32
    myPrivateBytes  []byte
}

foo := Foo{"my string", math.MaxUint32, []byte("my private bytes")}

buf, n, err := new(bytes.Buffer), new(int64), new(error)
WriteBinary(foo, buf, n, err)

// fmt.Printf("%X", buf.Bytes()) gives:
// 096D7920737472696E67FFFFFFFF
// 09:                           uvarint encoded length of string "my string"
//   6D7920737472696E67:         bytes of string "my string"
//                     FFFFFFFF: bytes for MaxUint32 
// Note that the unexported "myPrivateBytes" isn't encoded.

foo2 := ReadBinary(Foo{}, buf, n, err).(Foo)

// Or, to decode onto a pointer:
foo2 := ReadBinary(&Foo{}, buf, n, err).(*Foo)

WriteBinary and ReadBinary can encode/decode structs recursively. However, interface field values are a bit more complicated.

type Greeter interface {
	Greet() string
}

type Dog struct{}
func (d Dog) Greet() string { return "Woof!" }

type Cat struct{}
func (c Cat) Greet() string { return "Meow!" }

type Foo struct {
	Greeter
}

foo := Foo{Dog{}}

buf, n, err := new(bytes.Buffer), new(int64), new(error)
WriteBinary(foo, buf, n, err)

// This errors because we don't know whether to read a Dog or Cat.
foo2 := ReadBinary(Foo{}, buf, n, err)

In the above example, ReadBinary() fails because the Greeter field for Foo{} is ambiguous -- it could be either a Dog{} or a Cat{}, like a union structure. The solution is to declare the concrete implementation types for interfaces:

type Dog struct{}
func (d Dog) TypeByte() byte { return GreeterTypeDog }
func (d Dog) Greet() string { return "Woof!" }

type Cat struct{}
func (c Cat) TypeByte() byte { return GreeterTypeCat }
func (c Cat) Greet() string { return "Meow!" }

var _ = RegisterInterface(
	struct{Greeter}{},
	ConcreteType{Dog{}},
	ConcreteType{Cat{}},
})

NOTE: The TypeByte() is written and expected to be read even when the struct is encoded or decoded directly:

WriteBinary(Dog{}, buf, n, err)        // Writes GreeterTypeDog byte
dog_ := ReadBinary(Dog{}, buf, n, err) // Expects to read GreeterTypeDog byte
dog := dog_.(Dog)                      // ok if *err != nil, otherwise dog_ == nil.