Added README docs for account/binary and renamed UInt -> Uint etc.

This commit is contained in:
Jae Kwon
2014-12-22 17:38:16 -08:00
parent 61d1635085
commit 383335d93c
21 changed files with 324 additions and 137 deletions

167
binary/README.md Normal file
View File

@ -0,0 +1,167 @@
# `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`
```go
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`
```go
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:
```go
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:
```go
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.
```go
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.
```go
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 with "Unknown field type interface"
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.
In this case, the user must define a custom encoder/decoder as follows:
```go
const (
GreeterTypeDog = byte(0x01)
GreeterTypeCat = byte(0x02)
)
func GreeterEncoder(o interface{}, w io.Writer, n *int64, err *error) {
switch o.(type) {
case Dog:
WriteByte(GreeterTypeDog, w, n, err)
WriteBinary(o, w, n, err)
case Cat:
WriteByte(GreeterTypeCat, w, n, err)
WriteBinary(o, w, n, err)
default:
*err = errors.New(fmt.Sprintf("Unknown greeter type %v", o))
}
}
func GreeterDecoder(r io.Reader, n *int64, err *error) interface{} {
switch t := ReadByte(r, n, err); t {
case GreeterTypeDog:
return ReadBinary(Dog{}, r, n, err)
case GreeterTypeCat:
return ReadBinary(Cat{}, r, n, err)
default:
*err = errors.New(fmt.Sprintf("Unknown greeter type byte %X", t))
return nil
}
}
// This tells the reflection system to use the custom encoder/decoder functions
// for encoding/decoding interface struct-field types.
var _ = RegisterType(&TypeInfo{
Type: reflect.TypeOf((*Greeter)(nil)).Elem(),
Encoder: GreeterEncoder,
Decoder: GreeterDecoder,
})
```
Sometimes you want to always prefix a globally unique type byte while encoding,
whether or not the declared type is an interface or concrete type.
In this case, you can declare a "TypeByte() byte" function on the struct (as
a value receiver, not a pointer receiver!), and you can skip the declaration of
a custom decoder.
```go
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 _ = RegisterType(&TypeInfo{
Type: reflect.TypeOf((*Greeter)(nil)).Elem(),
Decoder: GreeterDecoder,
})
```

View File

@ -5,12 +5,12 @@ import (
)
func WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error) {
WriteUVarInt(uint(len(bz)), w, n, err)
WriteUvarint(uint(len(bz)), w, n, err)
WriteTo(bz, w, n, err)
}
func ReadByteSlice(r io.Reader, n *int64, err *error) []byte {
length := ReadUVarInt(r, n, err)
length := ReadUvarint(r, n, err)
if *err != nil {
return nil
}
@ -22,7 +22,7 @@ func ReadByteSlice(r io.Reader, n *int64, err *error) []byte {
//-----------------------------------------------------------------------------
func WriteByteSlices(bzz [][]byte, w io.Writer, n *int64, err *error) {
WriteUVarInt(uint(len(bzz)), w, n, err)
WriteUvarint(uint(len(bzz)), w, n, err)
for _, bz := range bzz {
WriteByteSlice(bz, w, n, err)
if *err != nil {
@ -32,7 +32,7 @@ func WriteByteSlices(bzz [][]byte, w io.Writer, n *int64, err *error) {
}
func ReadByteSlices(r io.Reader, n *int64, err *error) [][]byte {
length := ReadUVarInt(r, n, err)
length := ReadUvarint(r, n, err)
if *err != nil {
return nil
}

View File

@ -21,15 +21,15 @@ type Codec struct {
const (
typeByte = byte(0x01)
typeInt8 = byte(0x02)
// typeUInt8 = byte(0x03)
// typeUint8 = byte(0x03)
typeInt16 = byte(0x04)
typeUInt16 = byte(0x05)
typeUint16 = byte(0x05)
typeInt32 = byte(0x06)
typeUInt32 = byte(0x07)
typeUint32 = byte(0x07)
typeInt64 = byte(0x08)
typeUInt64 = byte(0x09)
typeVarInt = byte(0x0A)
typeUVarInt = byte(0x0B)
typeUint64 = byte(0x09)
typeVarint = byte(0x0A)
typeUvarint = byte(0x0B)
typeString = byte(0x10)
typeByteSlice = byte(0x11)
typeTime = byte(0x20)
@ -46,32 +46,32 @@ func BasicCodecEncoder(o interface{}, w io.Writer, n *int64, err *error) {
WriteByte(typeInt8, w, n, err)
WriteInt8(o.(int8), w, n, err)
//case uint8:
// WriteByte( typeUInt8, w, n, err)
// WriteUInt8( o.(uint8), w, n, err)
// WriteByte( typeUint8, w, n, err)
// WriteUint8( o.(uint8), w, n, err)
case int16:
WriteByte(typeInt16, w, n, err)
WriteInt16(o.(int16), w, n, err)
case uint16:
WriteByte(typeUInt16, w, n, err)
WriteUInt16(o.(uint16), w, n, err)
WriteByte(typeUint16, w, n, err)
WriteUint16(o.(uint16), w, n, err)
case int32:
WriteByte(typeInt32, w, n, err)
WriteInt32(o.(int32), w, n, err)
case uint32:
WriteByte(typeUInt32, w, n, err)
WriteUInt32(o.(uint32), w, n, err)
WriteByte(typeUint32, w, n, err)
WriteUint32(o.(uint32), w, n, err)
case int64:
WriteByte(typeInt64, w, n, err)
WriteInt64(o.(int64), w, n, err)
case uint64:
WriteByte(typeUInt64, w, n, err)
WriteUInt64(o.(uint64), w, n, err)
WriteByte(typeUint64, w, n, err)
WriteUint64(o.(uint64), w, n, err)
case int:
WriteByte(typeVarInt, w, n, err)
WriteVarInt(o.(int), w, n, err)
WriteByte(typeVarint, w, n, err)
WriteVarint(o.(int), w, n, err)
case uint:
WriteByte(typeUVarInt, w, n, err)
WriteUVarInt(o.(uint), w, n, err)
WriteByte(typeUvarint, w, n, err)
WriteUvarint(o.(uint), w, n, err)
case string:
WriteByte(typeString, w, n, err)
WriteString(o.(string), w, n, err)
@ -93,24 +93,24 @@ func BasicCodecDecoder(r io.Reader, n *int64, err *error) (o interface{}) {
o = ReadByte(r, n, err)
case typeInt8:
o = ReadInt8(r, n, err)
//case typeUInt8:
// o = ReadUInt8(r, n, err)
//case typeUint8:
// o = ReadUint8(r, n, err)
case typeInt16:
o = ReadInt16(r, n, err)
case typeUInt16:
o = ReadUInt16(r, n, err)
case typeUint16:
o = ReadUint16(r, n, err)
case typeInt32:
o = ReadInt32(r, n, err)
case typeUInt32:
o = ReadUInt32(r, n, err)
case typeUint32:
o = ReadUint32(r, n, err)
case typeInt64:
o = ReadInt64(r, n, err)
case typeUInt64:
o = ReadUInt64(r, n, err)
case typeVarInt:
o = ReadVarInt(r, n, err)
case typeUVarInt:
o = ReadUVarInt(r, n, err)
case typeUint64:
o = ReadUint64(r, n, err)
case typeVarint:
o = ReadVarint(r, n, err)
case typeUvarint:
o = ReadUvarint(r, n, err)
case typeString:
o = ReadString(r, n, err)
case typeByteSlice:

View File

@ -28,13 +28,13 @@ func ReadInt8(r io.Reader, n *int64, err *error) int8 {
return int8(ReadByte(r, n, err))
}
// UInt8
// Uint8
func WriteUInt8(i uint8, w io.Writer, n *int64, err *error) {
func WriteUint8(i uint8, w io.Writer, n *int64, err *error) {
WriteByte(byte(i), w, n, err)
}
func ReadUInt8(r io.Reader, n *int64, err *error) uint8 {
func ReadUint8(r io.Reader, n *int64, err *error) uint8 {
return uint8(ReadByte(r, n, err))
}
@ -53,41 +53,41 @@ func ReadInt16(r io.Reader, n *int64, err *error) int16 {
return int16(binary.LittleEndian.Uint16(buf))
}
// UInt16
// Uint16
func WriteUInt16(i uint16, w io.Writer, n *int64, err *error) {
func WriteUint16(i uint16, w io.Writer, n *int64, err *error) {
buf := make([]byte, 2)
binary.LittleEndian.PutUint16(buf, uint16(i))
*n += 2
WriteTo(buf, w, n, err)
}
func ReadUInt16(r io.Reader, n *int64, err *error) uint16 {
func ReadUint16(r io.Reader, n *int64, err *error) uint16 {
buf := make([]byte, 2)
ReadFull(buf, r, n, err)
return uint16(binary.LittleEndian.Uint16(buf))
}
// []UInt16
// []Uint16
func WriteUInt16s(iz []uint16, w io.Writer, n *int64, err *error) {
WriteUInt32(uint32(len(iz)), w, n, err)
func WriteUint16s(iz []uint16, w io.Writer, n *int64, err *error) {
WriteUint32(uint32(len(iz)), w, n, err)
for _, i := range iz {
WriteUInt16(i, w, n, err)
WriteUint16(i, w, n, err)
if *err != nil {
return
}
}
}
func ReadUInt16s(r io.Reader, n *int64, err *error) []uint16 {
length := ReadUInt32(r, n, err)
func ReadUint16s(r io.Reader, n *int64, err *error) []uint16 {
length := ReadUint32(r, n, err)
if *err != nil {
return nil
}
iz := make([]uint16, length)
for j := uint32(0); j < length; j++ {
ii := ReadUInt16(r, n, err)
ii := ReadUint16(r, n, err)
if *err != nil {
return nil
}
@ -111,16 +111,16 @@ func ReadInt32(r io.Reader, n *int64, err *error) int32 {
return int32(binary.LittleEndian.Uint32(buf))
}
// UInt32
// Uint32
func WriteUInt32(i uint32, w io.Writer, n *int64, err *error) {
func WriteUint32(i uint32, w io.Writer, n *int64, err *error) {
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(i))
*n += 4
WriteTo(buf, w, n, err)
}
func ReadUInt32(r io.Reader, n *int64, err *error) uint32 {
func ReadUint32(r io.Reader, n *int64, err *error) uint32 {
buf := make([]byte, 4)
ReadFull(buf, r, n, err)
return uint32(binary.LittleEndian.Uint32(buf))
@ -141,47 +141,47 @@ func ReadInt64(r io.Reader, n *int64, err *error) int64 {
return int64(binary.LittleEndian.Uint64(buf))
}
// UInt64
// Uint64
func WriteUInt64(i uint64, w io.Writer, n *int64, err *error) {
func WriteUint64(i uint64, w io.Writer, n *int64, err *error) {
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, uint64(i))
*n += 8
WriteTo(buf, w, n, err)
}
func ReadUInt64(r io.Reader, n *int64, err *error) uint64 {
func ReadUint64(r io.Reader, n *int64, err *error) uint64 {
buf := make([]byte, 8)
ReadFull(buf, r, n, err)
return uint64(binary.LittleEndian.Uint64(buf))
}
// VarInt
// Varint
func WriteVarInt(i int, w io.Writer, n *int64, err *error) {
func WriteVarint(i int, w io.Writer, n *int64, err *error) {
buf := make([]byte, 9)
n_ := int64(binary.PutVarint(buf, int64(i)))
*n += n_
WriteTo(buf[:n_], w, n, err)
}
func ReadVarInt(r io.Reader, n *int64, err *error) int {
func ReadVarint(r io.Reader, n *int64, err *error) int {
res, n_, err_ := readVarint(r)
*n += n_
*err = err_
return int(res)
}
// UVarInt
// Uvarint
func WriteUVarInt(i uint, w io.Writer, n *int64, err *error) {
func WriteUvarint(i uint, w io.Writer, n *int64, err *error) {
buf := make([]byte, 9)
n_ := int64(binary.PutUvarint(buf, uint64(i)))
*n += n_
WriteTo(buf[:n_], w, n, err)
}
func ReadUVarInt(r io.Reader, n *int64, err *error) uint {
func ReadUvarint(r io.Reader, n *int64, err *error) uint {
res, n_, err_ := readUvarint(r)
*n += n_
*err = err_

View File

@ -105,7 +105,7 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *
rv.Set(reflect.ValueOf(byteslice))
} else {
// Read length
length := int(ReadUVarInt(r, n, err))
length := int(ReadUvarint(r, n, err))
sliceRv := reflect.MakeSlice(rt, length, length)
// Read elems
for i := 0; i < length; i++ {
@ -131,43 +131,43 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *
rv.SetString(str)
case reflect.Int64:
num := ReadUInt64(r, n, err)
num := ReadUint64(r, n, err)
rv.SetInt(int64(num))
case reflect.Int32:
num := ReadUInt32(r, n, err)
num := ReadUint32(r, n, err)
rv.SetInt(int64(num))
case reflect.Int16:
num := ReadUInt16(r, n, err)
num := ReadUint16(r, n, err)
rv.SetInt(int64(num))
case reflect.Int8:
num := ReadUInt8(r, n, err)
num := ReadUint8(r, n, err)
rv.SetInt(int64(num))
case reflect.Int:
num := ReadUVarInt(r, n, err)
num := ReadUvarint(r, n, err)
rv.SetInt(int64(num))
case reflect.Uint64:
num := ReadUInt64(r, n, err)
num := ReadUint64(r, n, err)
rv.SetUint(uint64(num))
case reflect.Uint32:
num := ReadUInt32(r, n, err)
num := ReadUint32(r, n, err)
rv.SetUint(uint64(num))
case reflect.Uint16:
num := ReadUInt16(r, n, err)
num := ReadUint16(r, n, err)
rv.SetUint(uint64(num))
case reflect.Uint8:
num := ReadUInt8(r, n, err)
num := ReadUint8(r, n, err)
rv.SetUint(uint64(num))
case reflect.Uint:
num := ReadUVarInt(r, n, err)
num := ReadUvarint(r, n, err)
rv.SetUint(uint64(num))
default:
@ -220,7 +220,7 @@ func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err
} else {
// Write length
length := rv.Len()
WriteUVarInt(uint(length), w, n, err)
WriteUvarint(uint(length), w, n, err)
// Write elems
for i := 0; i < length; i++ {
elemRv := rv.Index(i)
@ -255,22 +255,22 @@ func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err
WriteInt8(int8(rv.Int()), w, n, err)
case reflect.Int:
WriteVarInt(int(rv.Int()), w, n, err)
WriteVarint(int(rv.Int()), w, n, err)
case reflect.Uint64:
WriteUInt64(rv.Uint(), w, n, err)
WriteUint64(rv.Uint(), w, n, err)
case reflect.Uint32:
WriteUInt32(uint32(rv.Uint()), w, n, err)
WriteUint32(uint32(rv.Uint()), w, n, err)
case reflect.Uint16:
WriteUInt16(uint16(rv.Uint()), w, n, err)
WriteUint16(uint16(rv.Uint()), w, n, err)
case reflect.Uint8:
WriteUInt8(uint8(rv.Uint()), w, n, err)
WriteUint8(uint8(rv.Uint()), w, n, err)
case reflect.Uint:
WriteUVarInt(uint(rv.Uint()), w, n, err)
WriteUvarint(uint(rv.Uint()), w, n, err)
default:
panic(fmt.Sprintf("Unknown field type %v", rt.Kind()))

View File

@ -5,12 +5,12 @@ import "io"
// String
func WriteString(s string, w io.Writer, n *int64, err *error) {
WriteUInt32(uint32(len(s)), w, n, err)
WriteUvarint(uint(len(s)), w, n, err)
WriteTo([]byte(s), w, n, err)
}
func ReadString(r io.Reader, n *int64, err *error) string {
length := ReadUInt32(r, n, err)
length := ReadUvarint(r, n, err)
if *err != nil {
return ""
}