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.
 
 
 
 
 
 
Jae Kwon cc715e0ee3 Everything is an RPCResponse 10 years ago
..
README.md RegisterInterface() so we can implement custom JSON codec 10 years ago
binary.go When using JSONRPC, do not double-encode JSON. 10 years ago
byteslice.go Added README docs for account/binary and renamed UInt -> Uint etc. 10 years ago
codec.go Dot import -> named import 10 years ago
int.go Dot import -> named import 10 years ago
log.go tendermint2 10 years ago
reflect.go Everything is an RPCResponse 10 years ago
reflect_test.go add support for `json=""` in reflection binary/* thing 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 binary/reflect handles JSON 10 years ago

README.md

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.