mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-04 15:17:02 +00:00
Refactor to move common libraries out of project
This commit is contained in:
-138
@@ -1,138 +0,0 @@
|
||||
### 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/wire`
|
||||
|
||||
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 := ReadBinaryPtr(&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 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:
|
||||
|
||||
```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 _ = 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:
|
||||
|
||||
```go
|
||||
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.
|
||||
```
|
||||
@@ -1,68 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
)
|
||||
|
||||
func WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error) {
|
||||
WriteVarint(len(bz), w, n, err)
|
||||
WriteTo(bz, w, n, err)
|
||||
}
|
||||
|
||||
func ReadByteSlice(r io.Reader, n *int64, err *error) []byte {
|
||||
length := ReadVarint(r, n, err)
|
||||
if *err != nil {
|
||||
return nil
|
||||
}
|
||||
if length < 0 {
|
||||
*err = ErrBinaryReadSizeUnderflow
|
||||
return nil
|
||||
}
|
||||
if MaxBinaryReadSize < MaxInt64(int64(length), *n+int64(length)) {
|
||||
*err = ErrBinaryReadSizeOverflow
|
||||
return nil
|
||||
}
|
||||
|
||||
buf := make([]byte, length)
|
||||
ReadFull(buf, r, n, err)
|
||||
return buf
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
func WriteByteSlices(bzz [][]byte, w io.Writer, n *int64, err *error) {
|
||||
WriteVarint(len(bzz), w, n, err)
|
||||
for _, bz := range bzz {
|
||||
WriteByteSlice(bz, w, n, err)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ReadByteSlices(r io.Reader, n *int64, err *error) [][]byte {
|
||||
length := ReadVarint(r, n, err)
|
||||
if *err != nil {
|
||||
return nil
|
||||
}
|
||||
if length < 0 {
|
||||
*err = ErrBinaryReadSizeUnderflow
|
||||
return nil
|
||||
}
|
||||
if MaxBinaryReadSize < MaxInt64(int64(length), *n+int64(length)) {
|
||||
*err = ErrBinaryReadSizeOverflow
|
||||
return nil
|
||||
}
|
||||
|
||||
bzz := make([][]byte, length)
|
||||
for i := 0; i < length; i++ {
|
||||
bz := ReadByteSlice(r, n, err)
|
||||
if *err != nil {
|
||||
return nil
|
||||
}
|
||||
bzz[i] = bz
|
||||
}
|
||||
return bzz
|
||||
}
|
||||
-171
@@ -1,171 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Encoder func(o interface{}, w io.Writer, n *int64, err *error)
|
||||
type Decoder func(r io.Reader, n *int64, err *error) interface{}
|
||||
type Comparator func(o1 interface{}, o2 interface{}) int
|
||||
|
||||
type Codec struct {
|
||||
Encode Encoder
|
||||
Decode Decoder
|
||||
Compare Comparator
|
||||
}
|
||||
|
||||
const (
|
||||
typeByte = byte(0x01)
|
||||
typeInt8 = byte(0x02)
|
||||
// typeUint8 = byte(0x03)
|
||||
typeInt16 = byte(0x04)
|
||||
typeUint16 = byte(0x05)
|
||||
typeInt32 = byte(0x06)
|
||||
typeUint32 = byte(0x07)
|
||||
typeInt64 = byte(0x08)
|
||||
typeUint64 = byte(0x09)
|
||||
typeVarint = byte(0x0A)
|
||||
typeUvarint = byte(0x0B)
|
||||
typeString = byte(0x10)
|
||||
typeByteSlice = byte(0x11)
|
||||
typeTime = byte(0x20)
|
||||
)
|
||||
|
||||
func BasicCodecEncoder(o interface{}, w io.Writer, n *int64, err *error) {
|
||||
switch o := o.(type) {
|
||||
case nil:
|
||||
PanicSanity("nil type unsupported")
|
||||
case byte:
|
||||
WriteByte(typeByte, w, n, err)
|
||||
WriteByte(o, w, n, err)
|
||||
case int8:
|
||||
WriteByte(typeInt8, w, n, err)
|
||||
WriteInt8(o, w, n, err)
|
||||
//case uint8:
|
||||
// WriteByte( typeUint8, w, n, err)
|
||||
// WriteUint8( o, w, n, err)
|
||||
case int16:
|
||||
WriteByte(typeInt16, w, n, err)
|
||||
WriteInt16(o, w, n, err)
|
||||
case uint16:
|
||||
WriteByte(typeUint16, w, n, err)
|
||||
WriteUint16(o, w, n, err)
|
||||
case int32:
|
||||
WriteByte(typeInt32, w, n, err)
|
||||
WriteInt32(o, w, n, err)
|
||||
case uint32:
|
||||
WriteByte(typeUint32, w, n, err)
|
||||
WriteUint32(o, w, n, err)
|
||||
case int64:
|
||||
WriteByte(typeInt64, w, n, err)
|
||||
WriteInt64(o, w, n, err)
|
||||
case uint64:
|
||||
WriteByte(typeUint64, w, n, err)
|
||||
WriteUint64(o, w, n, err)
|
||||
case int:
|
||||
WriteByte(typeVarint, w, n, err)
|
||||
WriteVarint(o, w, n, err)
|
||||
case uint:
|
||||
WriteByte(typeUvarint, w, n, err)
|
||||
WriteUvarint(o, w, n, err)
|
||||
case string:
|
||||
WriteByte(typeString, w, n, err)
|
||||
WriteString(o, w, n, err)
|
||||
case []byte:
|
||||
WriteByte(typeByteSlice, w, n, err)
|
||||
WriteByteSlice(o, w, n, err)
|
||||
case time.Time:
|
||||
WriteByte(typeTime, w, n, err)
|
||||
WriteTime(o, w, n, err)
|
||||
default:
|
||||
PanicSanity(fmt.Sprintf("Unsupported type: %v", reflect.TypeOf(o)))
|
||||
}
|
||||
}
|
||||
|
||||
func BasicCodecDecoder(r io.Reader, n *int64, err *error) (o interface{}) {
|
||||
type_ := ReadByte(r, n, err)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
switch type_ {
|
||||
case typeByte:
|
||||
o = ReadByte(r, n, err)
|
||||
case typeInt8:
|
||||
o = ReadInt8(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 typeInt32:
|
||||
o = ReadInt32(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 typeString:
|
||||
o = ReadString(r, n, err)
|
||||
case typeByteSlice:
|
||||
o = ReadByteSlice(r, n, err)
|
||||
case typeTime:
|
||||
o = ReadTime(r, n, err)
|
||||
default:
|
||||
*err = errors.New(Fmt("Unsupported type byte: %X", type_))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Contract: Caller must ensure that types match.
|
||||
func BasicCodecComparator(o1 interface{}, o2 interface{}) int {
|
||||
switch o1.(type) {
|
||||
case byte:
|
||||
return int(o1.(byte) - o2.(byte))
|
||||
case int8:
|
||||
return int(o1.(int8) - o2.(int8))
|
||||
//case uint8:
|
||||
case int16:
|
||||
return int(o1.(int16) - o2.(int16))
|
||||
case uint16:
|
||||
return int(o1.(uint16) - o2.(uint16))
|
||||
case int32:
|
||||
return int(o1.(int32) - o2.(int32))
|
||||
case uint32:
|
||||
return int(o1.(uint32) - o2.(uint32))
|
||||
case int64:
|
||||
return int(o1.(int64) - o2.(int64))
|
||||
case uint64:
|
||||
return int(o1.(uint64) - o2.(uint64))
|
||||
case int:
|
||||
return o1.(int) - o2.(int)
|
||||
case uint:
|
||||
return int(o1.(uint)) - int(o2.(uint))
|
||||
case string:
|
||||
return bytes.Compare([]byte(o1.(string)), []byte(o2.(string)))
|
||||
case []byte:
|
||||
return bytes.Compare(o1.([]byte), o2.([]byte))
|
||||
case time.Time:
|
||||
return int(o1.(time.Time).UnixNano() - o2.(time.Time).UnixNano())
|
||||
default:
|
||||
PanicSanity(Fmt("Unsupported type: %v", reflect.TypeOf(o1)))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var BasicCodec = Codec{
|
||||
Encode: BasicCodecEncoder,
|
||||
Decode: BasicCodecDecoder,
|
||||
Compare: BasicCodecComparator,
|
||||
}
|
||||
-270
@@ -1,270 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Byte
|
||||
|
||||
func WriteByte(b byte, w io.Writer, n *int64, err *error) {
|
||||
WriteTo([]byte{b}, w, n, err)
|
||||
}
|
||||
|
||||
func ReadByte(r io.Reader, n *int64, err *error) byte {
|
||||
buf := make([]byte, 1)
|
||||
ReadFull(buf, r, n, err)
|
||||
return buf[0]
|
||||
}
|
||||
|
||||
// Int8
|
||||
|
||||
func WriteInt8(i int8, w io.Writer, n *int64, err *error) {
|
||||
WriteByte(byte(i), w, n, err)
|
||||
}
|
||||
|
||||
func ReadInt8(r io.Reader, n *int64, err *error) int8 {
|
||||
return int8(ReadByte(r, n, err))
|
||||
}
|
||||
|
||||
// Uint8
|
||||
|
||||
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 {
|
||||
return uint8(ReadByte(r, n, err))
|
||||
}
|
||||
|
||||
// Int16
|
||||
|
||||
func WriteInt16(i int16, w io.Writer, n *int64, err *error) {
|
||||
buf := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(buf, uint16(i))
|
||||
*n += 2
|
||||
WriteTo(buf, w, n, err)
|
||||
}
|
||||
|
||||
func ReadInt16(r io.Reader, n *int64, err *error) int16 {
|
||||
buf := make([]byte, 2)
|
||||
ReadFull(buf, r, n, err)
|
||||
return int16(binary.BigEndian.Uint16(buf))
|
||||
}
|
||||
|
||||
// Uint16
|
||||
|
||||
func WriteUint16(i uint16, w io.Writer, n *int64, err *error) {
|
||||
buf := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(buf, uint16(i))
|
||||
*n += 2
|
||||
WriteTo(buf, w, n, err)
|
||||
}
|
||||
|
||||
func ReadUint16(r io.Reader, n *int64, err *error) uint16 {
|
||||
buf := make([]byte, 2)
|
||||
ReadFull(buf, r, n, err)
|
||||
return uint16(binary.BigEndian.Uint16(buf))
|
||||
}
|
||||
|
||||
// []Uint16
|
||||
|
||||
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)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if *err != nil {
|
||||
return nil
|
||||
}
|
||||
iz[j] = ii
|
||||
}
|
||||
return iz
|
||||
}
|
||||
|
||||
// Int32
|
||||
|
||||
func WriteInt32(i int32, w io.Writer, n *int64, err *error) {
|
||||
buf := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(buf, uint32(i))
|
||||
*n += 4
|
||||
WriteTo(buf, w, n, err)
|
||||
}
|
||||
|
||||
func ReadInt32(r io.Reader, n *int64, err *error) int32 {
|
||||
buf := make([]byte, 4)
|
||||
ReadFull(buf, r, n, err)
|
||||
return int32(binary.BigEndian.Uint32(buf))
|
||||
}
|
||||
|
||||
// Uint32
|
||||
|
||||
func WriteUint32(i uint32, w io.Writer, n *int64, err *error) {
|
||||
buf := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(buf, uint32(i))
|
||||
*n += 4
|
||||
WriteTo(buf, w, n, err)
|
||||
}
|
||||
|
||||
func ReadUint32(r io.Reader, n *int64, err *error) uint32 {
|
||||
buf := make([]byte, 4)
|
||||
ReadFull(buf, r, n, err)
|
||||
return uint32(binary.BigEndian.Uint32(buf))
|
||||
}
|
||||
|
||||
// Int64
|
||||
|
||||
func WriteInt64(i int64, w io.Writer, n *int64, err *error) {
|
||||
buf := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(buf, uint64(i))
|
||||
*n += 8
|
||||
WriteTo(buf, w, n, err)
|
||||
}
|
||||
|
||||
func ReadInt64(r io.Reader, n *int64, err *error) int64 {
|
||||
buf := make([]byte, 8)
|
||||
ReadFull(buf, r, n, err)
|
||||
return int64(binary.BigEndian.Uint64(buf))
|
||||
}
|
||||
|
||||
// Uint64
|
||||
|
||||
func WriteUint64(i uint64, w io.Writer, n *int64, err *error) {
|
||||
buf := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(buf, uint64(i))
|
||||
*n += 8
|
||||
WriteTo(buf, w, n, err)
|
||||
}
|
||||
|
||||
func ReadUint64(r io.Reader, n *int64, err *error) uint64 {
|
||||
buf := make([]byte, 8)
|
||||
ReadFull(buf, r, n, err)
|
||||
return uint64(binary.BigEndian.Uint64(buf))
|
||||
}
|
||||
|
||||
// Varint
|
||||
|
||||
func uvarintSize(i uint64) int {
|
||||
if i == 0 {
|
||||
return 0
|
||||
}
|
||||
if i < 1<<8 {
|
||||
return 1
|
||||
}
|
||||
if i < 1<<16 {
|
||||
return 2
|
||||
}
|
||||
if i < 1<<24 {
|
||||
return 3
|
||||
}
|
||||
if i < 1<<32 {
|
||||
return 4
|
||||
}
|
||||
if i < 1<<40 {
|
||||
return 5
|
||||
}
|
||||
if i < 1<<48 {
|
||||
return 6
|
||||
}
|
||||
if i < 1<<56 {
|
||||
return 7
|
||||
}
|
||||
return 8
|
||||
}
|
||||
|
||||
func WriteVarint(i int, w io.Writer, n *int64, err *error) {
|
||||
var negate = false
|
||||
if i < 0 {
|
||||
negate = true
|
||||
i = -i
|
||||
}
|
||||
var size = uvarintSize(uint64(i))
|
||||
if negate {
|
||||
// e.g. 0xF1 for a single negative byte
|
||||
WriteUint8(uint8(size+0xF0), w, n, err)
|
||||
} else {
|
||||
WriteUint8(uint8(size), w, n, err)
|
||||
}
|
||||
if size > 0 {
|
||||
buf := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(buf, uint64(i))
|
||||
WriteTo(buf[(8-size):], w, n, err)
|
||||
}
|
||||
*n += int64(1 + size)
|
||||
}
|
||||
|
||||
func ReadVarint(r io.Reader, n *int64, err *error) int {
|
||||
var size = ReadUint8(r, n, err)
|
||||
var negate = false
|
||||
if (size >> 4) == 0xF {
|
||||
negate = true
|
||||
size = size & 0x0F
|
||||
}
|
||||
if size > 8 {
|
||||
setFirstErr(err, errors.New("Varint overflow"))
|
||||
return 0
|
||||
}
|
||||
if size == 0 {
|
||||
if negate {
|
||||
setFirstErr(err, errors.New("Varint does not allow negative zero"))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
buf := make([]byte, 8)
|
||||
ReadFull(buf[(8-size):], r, n, err)
|
||||
*n += int64(1 + size)
|
||||
var i = int(binary.BigEndian.Uint64(buf))
|
||||
if negate {
|
||||
return -i
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
// Uvarint
|
||||
|
||||
func WriteUvarint(i uint, w io.Writer, n *int64, err *error) {
|
||||
var size = uvarintSize(uint64(i))
|
||||
WriteUint8(uint8(size), w, n, err)
|
||||
if size > 0 {
|
||||
buf := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(buf, uint64(i))
|
||||
WriteTo(buf[(8-size):], w, n, err)
|
||||
}
|
||||
*n += int64(1 + size)
|
||||
}
|
||||
|
||||
func ReadUvarint(r io.Reader, n *int64, err *error) uint {
|
||||
var size = ReadUint8(r, n, err)
|
||||
if size > 8 {
|
||||
setFirstErr(err, errors.New("Uvarint overflow"))
|
||||
return 0
|
||||
}
|
||||
if size == 0 {
|
||||
return 0
|
||||
}
|
||||
buf := make([]byte, 8)
|
||||
ReadFull(buf[(8-size):], r, n, err)
|
||||
*n += int64(1 + size)
|
||||
return uint(binary.BigEndian.Uint64(buf))
|
||||
}
|
||||
|
||||
func setFirstErr(err *error, newErr error) {
|
||||
if *err == nil && newErr != nil {
|
||||
*err = newErr
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVarint(t *testing.T) {
|
||||
|
||||
check := func(i int, s string) {
|
||||
buf := new(bytes.Buffer)
|
||||
n, err := new(int64), new(error)
|
||||
WriteVarint(i, buf, n, err)
|
||||
bufBytes := buf.Bytes() // Read before consuming below.
|
||||
i_ := ReadVarint(buf, n, err)
|
||||
if i != i_ {
|
||||
fmt.Println(bufBytes)
|
||||
t.Fatalf("Encoded %v and got %v", i, i_)
|
||||
}
|
||||
if s != "" {
|
||||
if bufHex := fmt.Sprintf("%X", bufBytes); bufHex != s {
|
||||
t.Fatalf("Encoded %v, expected %v", bufHex, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 123457 is some prime.
|
||||
for i := -(2 << 33); i < (2 << 33); i += 123457 {
|
||||
check(i, "")
|
||||
}
|
||||
|
||||
// Near zero
|
||||
check(-1, "F101")
|
||||
check(0, "00")
|
||||
check(1, "0101")
|
||||
// Positives
|
||||
check(1<<32-1, "04FFFFFFFF")
|
||||
check(1<<32+0, "050100000000")
|
||||
check(1<<32+1, "050100000001")
|
||||
check(1<<53-1, "071FFFFFFFFFFFFF")
|
||||
// Negatives
|
||||
check(-1<<32+1, "F4FFFFFFFF")
|
||||
check(-1<<32-0, "F50100000000")
|
||||
check(-1<<32-1, "F50100000001")
|
||||
check(-1<<53+1, "F71FFFFFFFFFFFFF")
|
||||
}
|
||||
|
||||
func TestUvarint(t *testing.T) {
|
||||
|
||||
check := func(i uint, s string) {
|
||||
buf := new(bytes.Buffer)
|
||||
n, err := new(int64), new(error)
|
||||
WriteUvarint(i, buf, n, err)
|
||||
bufBytes := buf.Bytes()
|
||||
i_ := ReadUvarint(buf, n, err)
|
||||
if i != i_ {
|
||||
fmt.Println(buf.Bytes())
|
||||
t.Fatalf("Encoded %v and got %v", i, i_)
|
||||
}
|
||||
if s != "" {
|
||||
if bufHex := fmt.Sprintf("%X", bufBytes); bufHex != s {
|
||||
t.Fatalf("Encoded %v, expected %v", bufHex, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 123457 is some prime.
|
||||
for i := 0; i < (2 << 33); i += 123457 {
|
||||
check(uint(i), "")
|
||||
}
|
||||
|
||||
check(1, "0101")
|
||||
check(1<<32-1, "04FFFFFFFF")
|
||||
check(1<<32+0, "050100000000")
|
||||
check(1<<32+1, "050100000001")
|
||||
check(1<<53-1, "071FFFFFFFFFFFFF")
|
||||
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/tendermint/log15"
|
||||
"github.com/tendermint/tendermint/logger"
|
||||
)
|
||||
|
||||
var log = logger.New("module", "binary")
|
||||
|
||||
func init() {
|
||||
log.SetHandler(
|
||||
log15.LvlFilterHandler(
|
||||
log15.LvlWarn,
|
||||
//log15.LvlDebug,
|
||||
logger.RootHandler(),
|
||||
),
|
||||
)
|
||||
}
|
||||
-954
@@ -1,954 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
)
|
||||
|
||||
const (
|
||||
ReflectSliceChunk = 1024
|
||||
)
|
||||
|
||||
type TypeInfo struct {
|
||||
Type reflect.Type // The type
|
||||
|
||||
// If Type is kind reflect.Interface, is registered
|
||||
IsRegisteredInterface bool
|
||||
ByteToType map[byte]reflect.Type
|
||||
TypeToByte map[reflect.Type]byte
|
||||
|
||||
// If Type is concrete
|
||||
Byte byte
|
||||
|
||||
// If Type is kind reflect.Struct
|
||||
Fields []StructFieldInfo
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
JSONName string // (JSON) Corresponding JSON field name. (override with `json=""`)
|
||||
Varint bool // (Binary) Use length-prefixed encoding for (u)int*
|
||||
}
|
||||
|
||||
func getOptionsFromField(field reflect.StructField) (skip bool, opts Options) {
|
||||
jsonName := field.Tag.Get("json")
|
||||
if jsonName == "-" {
|
||||
skip = true
|
||||
return
|
||||
} else if jsonName == "" {
|
||||
jsonName = field.Name
|
||||
}
|
||||
varint := false
|
||||
binTag := field.Tag.Get("binary")
|
||||
if binTag == "varint" { // TODO: extend
|
||||
varint = true
|
||||
}
|
||||
opts = Options{
|
||||
JSONName: jsonName,
|
||||
Varint: varint,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type StructFieldInfo struct {
|
||||
Index int // Struct field index
|
||||
Type reflect.Type // Struct field type
|
||||
Options // Encoding options
|
||||
}
|
||||
|
||||
func (info StructFieldInfo) unpack() (int, reflect.Type, Options) {
|
||||
return info.Index, info.Type, info.Options
|
||||
}
|
||||
|
||||
// e.g. If o is struct{Foo}{}, return is the Foo reflection type.
|
||||
func GetTypeFromStructDeclaration(o interface{}) reflect.Type {
|
||||
rt := reflect.TypeOf(o)
|
||||
if rt.NumField() != 1 {
|
||||
PanicSanity("Unexpected number of fields in struct-wrapped declaration of type")
|
||||
}
|
||||
return rt.Field(0).Type
|
||||
}
|
||||
|
||||
func SetByteForType(typeByte byte, rt reflect.Type) {
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
if typeInfo.Byte != 0x00 && typeInfo.Byte != typeByte {
|
||||
PanicSanity(Fmt("Type %v already registered with type byte %X", rt, typeByte))
|
||||
}
|
||||
typeInfo.Byte = typeByte
|
||||
// If pointer, we need to set it for the concrete type as well.
|
||||
if rt.Kind() == reflect.Ptr {
|
||||
SetByteForType(typeByte, rt.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
// Predeclaration of common types
|
||||
var (
|
||||
timeType = GetTypeFromStructDeclaration(struct{ time.Time }{})
|
||||
)
|
||||
|
||||
const (
|
||||
iso8601 = "2006-01-02T15:04:05.000Z" // forced microseconds
|
||||
)
|
||||
|
||||
// NOTE: do not access typeInfos directly, but call GetTypeInfo()
|
||||
var typeInfosMtx sync.Mutex
|
||||
var typeInfos = map[reflect.Type]*TypeInfo{}
|
||||
|
||||
func GetTypeInfo(rt reflect.Type) *TypeInfo {
|
||||
typeInfosMtx.Lock()
|
||||
defer typeInfosMtx.Unlock()
|
||||
info := typeInfos[rt]
|
||||
if info == nil {
|
||||
info = MakeTypeInfo(rt)
|
||||
typeInfos[rt] = info
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// For use with the RegisterInterface declaration
|
||||
type ConcreteType struct {
|
||||
O interface{}
|
||||
Byte byte
|
||||
}
|
||||
|
||||
// Must use this to register an interface to properly decode the
|
||||
// underlying concrete type.
|
||||
func RegisterInterface(o interface{}, ctypes ...ConcreteType) *TypeInfo {
|
||||
it := GetTypeFromStructDeclaration(o)
|
||||
if it.Kind() != reflect.Interface {
|
||||
PanicSanity("RegisterInterface expects an interface")
|
||||
}
|
||||
toType := make(map[byte]reflect.Type, 0)
|
||||
toByte := make(map[reflect.Type]byte, 0)
|
||||
for _, ctype := range ctypes {
|
||||
crt := reflect.TypeOf(ctype.O)
|
||||
typeByte := ctype.Byte
|
||||
SetByteForType(typeByte, crt)
|
||||
if typeByte == 0x00 {
|
||||
PanicSanity(Fmt("Byte of 0x00 is reserved for nil (%v)", ctype))
|
||||
}
|
||||
if toType[typeByte] != nil {
|
||||
PanicSanity(Fmt("Duplicate Byte for type %v and %v", ctype, toType[typeByte]))
|
||||
}
|
||||
toType[typeByte] = crt
|
||||
toByte[crt] = typeByte
|
||||
}
|
||||
typeInfo := &TypeInfo{
|
||||
Type: it,
|
||||
IsRegisteredInterface: true,
|
||||
ByteToType: toType,
|
||||
TypeToByte: toByte,
|
||||
}
|
||||
typeInfos[it] = typeInfo
|
||||
return typeInfo
|
||||
}
|
||||
|
||||
func MakeTypeInfo(rt reflect.Type) *TypeInfo {
|
||||
info := &TypeInfo{Type: rt}
|
||||
|
||||
// If struct, register field name options
|
||||
if rt.Kind() == reflect.Struct {
|
||||
numFields := rt.NumField()
|
||||
structFields := []StructFieldInfo{}
|
||||
for i := 0; i < numFields; i++ {
|
||||
field := rt.Field(i)
|
||||
if field.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
skip, opts := getOptionsFromField(field)
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
structFields = append(structFields, StructFieldInfo{
|
||||
Index: i,
|
||||
Type: field.Type,
|
||||
Options: opts,
|
||||
})
|
||||
}
|
||||
info.Fields = structFields
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// Contract: Caller must ensure that rt is supported
|
||||
// (e.g. is recursively composed of supported native types, and structs and slices.)
|
||||
func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Reader, n *int64, err *error) {
|
||||
|
||||
// Get typeInfo
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
|
||||
if rt.Kind() == reflect.Interface {
|
||||
if !typeInfo.IsRegisteredInterface {
|
||||
// There's no way we can read such a thing.
|
||||
*err = errors.New(Fmt("Cannot read unregistered interface type %v", rt))
|
||||
return
|
||||
}
|
||||
typeByte := ReadByte(r, n, err)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
if typeByte == 0x00 {
|
||||
return // nil
|
||||
}
|
||||
crt, ok := typeInfo.ByteToType[typeByte]
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Unexpected type byte %X for type %v", typeByte, rt))
|
||||
return
|
||||
}
|
||||
crv := reflect.New(crt).Elem()
|
||||
r = NewPrefixedReader([]byte{typeByte}, r)
|
||||
readReflectBinary(crv, crt, opts, r, n, err)
|
||||
rv.Set(crv) // NOTE: orig rv is ignored.
|
||||
return
|
||||
}
|
||||
|
||||
if rt.Kind() == reflect.Ptr {
|
||||
typeByte := ReadByte(r, n, err)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
if typeByte == 0x00 {
|
||||
return // nil
|
||||
}
|
||||
// Create new if rv is nil.
|
||||
if rv.IsNil() {
|
||||
newRv := reflect.New(rt.Elem())
|
||||
rv.Set(newRv)
|
||||
rv = newRv
|
||||
}
|
||||
// Dereference pointer
|
||||
rv, rt = rv.Elem(), rt.Elem()
|
||||
typeInfo = GetTypeInfo(rt)
|
||||
if typeInfo.Byte != 0x00 {
|
||||
r = NewPrefixedReader([]byte{typeByte}, r)
|
||||
} else if typeByte != 0x01 {
|
||||
*err = errors.New(Fmt("Unexpected type byte %X for ptr of untyped thing", typeByte))
|
||||
return
|
||||
}
|
||||
// continue...
|
||||
}
|
||||
|
||||
// Read Byte prefix
|
||||
if typeInfo.Byte != 0x00 {
|
||||
typeByte := ReadByte(r, n, err)
|
||||
if typeByte != typeInfo.Byte {
|
||||
*err = errors.New(Fmt("Expected Byte of %X but got %X", typeInfo.Byte, typeByte))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch rt.Kind() {
|
||||
case reflect.Array:
|
||||
elemRt := rt.Elem()
|
||||
length := rt.Len()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
// Special case: Bytearrays
|
||||
buf := make([]byte, length)
|
||||
ReadFull(buf, r, n, err)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
log.Info("Read bytearray", "bytes", buf)
|
||||
reflect.Copy(rv, reflect.ValueOf(buf))
|
||||
} else {
|
||||
for i := 0; i < length; i++ {
|
||||
elemRv := rv.Index(i)
|
||||
readReflectBinary(elemRv, elemRt, opts, r, n, err)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
if MaxBinaryReadSize < *n {
|
||||
*err = ErrBinaryReadSizeOverflow
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Info(Fmt("Read %v-array", elemRt), "length", length)
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
elemRt := rt.Elem()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
// Special case: Byteslices
|
||||
byteslice := ReadByteSlice(r, n, err)
|
||||
log.Info("Read byteslice", "bytes", byteslice)
|
||||
rv.Set(reflect.ValueOf(byteslice))
|
||||
} else {
|
||||
var sliceRv reflect.Value
|
||||
// Read length
|
||||
length := ReadVarint(r, n, err)
|
||||
log.Info(Fmt("Read length: %v", length))
|
||||
sliceRv = reflect.MakeSlice(rt, 0, 0)
|
||||
// read one ReflectSliceChunk at a time and append
|
||||
for i := 0; i*ReflectSliceChunk < length; i++ {
|
||||
l := MinInt(ReflectSliceChunk, length-i*ReflectSliceChunk)
|
||||
tmpSliceRv := reflect.MakeSlice(rt, l, l)
|
||||
for j := 0; j < l; j++ {
|
||||
elemRv := tmpSliceRv.Index(j)
|
||||
readReflectBinary(elemRv, elemRt, opts, r, n, err)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
if MaxBinaryReadSize < *n {
|
||||
*err = ErrBinaryReadSizeOverflow
|
||||
return
|
||||
}
|
||||
}
|
||||
sliceRv = reflect.AppendSlice(sliceRv, tmpSliceRv)
|
||||
}
|
||||
|
||||
rv.Set(sliceRv)
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
if rt == timeType {
|
||||
// Special case: time.Time
|
||||
t := ReadTime(r, n, err)
|
||||
log.Info(Fmt("Read time: %v", t))
|
||||
rv.Set(reflect.ValueOf(t))
|
||||
} else {
|
||||
for _, fieldInfo := range typeInfo.Fields {
|
||||
i, fieldType, opts := fieldInfo.unpack()
|
||||
fieldRv := rv.Field(i)
|
||||
readReflectBinary(fieldRv, fieldType, opts, r, n, err)
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
str := ReadString(r, n, err)
|
||||
log.Info(Fmt("Read string: %v", str))
|
||||
rv.SetString(str)
|
||||
|
||||
case reflect.Int64:
|
||||
if opts.Varint {
|
||||
num := ReadVarint(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetInt(int64(num))
|
||||
} else {
|
||||
num := ReadInt64(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetInt(int64(num))
|
||||
}
|
||||
|
||||
case reflect.Int32:
|
||||
num := ReadUint32(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetInt(int64(num))
|
||||
|
||||
case reflect.Int16:
|
||||
num := ReadUint16(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetInt(int64(num))
|
||||
|
||||
case reflect.Int8:
|
||||
num := ReadUint8(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetInt(int64(num))
|
||||
|
||||
case reflect.Int:
|
||||
num := ReadVarint(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetInt(int64(num))
|
||||
|
||||
case reflect.Uint64:
|
||||
if opts.Varint {
|
||||
num := ReadVarint(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetUint(uint64(num))
|
||||
} else {
|
||||
num := ReadUint64(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetUint(uint64(num))
|
||||
}
|
||||
|
||||
case reflect.Uint32:
|
||||
num := ReadUint32(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetUint(uint64(num))
|
||||
|
||||
case reflect.Uint16:
|
||||
num := ReadUint16(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetUint(uint64(num))
|
||||
|
||||
case reflect.Uint8:
|
||||
num := ReadUint8(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetUint(uint64(num))
|
||||
|
||||
case reflect.Uint:
|
||||
num := ReadVarint(r, n, err)
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetUint(uint64(num))
|
||||
|
||||
case reflect.Bool:
|
||||
num := ReadUint8(r, n, err)
|
||||
log.Info(Fmt("Read bool: %v", num))
|
||||
rv.SetBool(num > 0)
|
||||
|
||||
default:
|
||||
PanicSanity(Fmt("Unknown field type %v", rt.Kind()))
|
||||
}
|
||||
}
|
||||
|
||||
// rv: the reflection value of the thing to write
|
||||
// rt: the type of rv as declared in the container, not necessarily rv.Type().
|
||||
func writeReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, w io.Writer, n *int64, err *error) {
|
||||
|
||||
// Get typeInfo
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
|
||||
if rt.Kind() == reflect.Interface {
|
||||
if rv.IsNil() {
|
||||
// XXX ensure that typeByte 0 is reserved.
|
||||
WriteByte(0x00, w, n, err)
|
||||
return
|
||||
}
|
||||
crv := rv.Elem() // concrete reflection value
|
||||
crt := crv.Type() // concrete reflection type
|
||||
if typeInfo.IsRegisteredInterface {
|
||||
// See if the crt is registered.
|
||||
// If so, we're more restrictive.
|
||||
_, ok := typeInfo.TypeToByte[crt]
|
||||
if !ok {
|
||||
switch crt.Kind() {
|
||||
case reflect.Ptr:
|
||||
*err = errors.New(Fmt("Unexpected pointer type %v for registered interface %v. "+
|
||||
"Was it registered as a value receiver rather than as a pointer receiver?", crt, rt.Name()))
|
||||
case reflect.Struct:
|
||||
*err = errors.New(Fmt("Unexpected struct type %v for registered interface %v. "+
|
||||
"Was it registered as a pointer receiver rather than as a value receiver?", crt, rt.Name()))
|
||||
default:
|
||||
*err = errors.New(Fmt("Unexpected type %v for registered interface %v. "+
|
||||
"If this is intentional, please register it.", crt, rt.Name()))
|
||||
}
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// We support writing unsafely for convenience.
|
||||
}
|
||||
// We don't have to write the typeByte here,
|
||||
// the writeReflectBinary() call below will write it.
|
||||
writeReflectBinary(crv, crt, opts, w, n, err)
|
||||
return
|
||||
}
|
||||
|
||||
if rt.Kind() == reflect.Ptr {
|
||||
// Dereference pointer
|
||||
rv, rt = rv.Elem(), rt.Elem()
|
||||
typeInfo = GetTypeInfo(rt)
|
||||
if !rv.IsValid() {
|
||||
// For better compatibility with other languages,
|
||||
// as far as tendermint/wire is concerned,
|
||||
// pointers to nil values are the same as nil.
|
||||
WriteByte(0x00, w, n, err)
|
||||
return
|
||||
}
|
||||
if typeInfo.Byte == 0x00 {
|
||||
WriteByte(0x01, w, n, err)
|
||||
// continue...
|
||||
} else {
|
||||
// continue...
|
||||
}
|
||||
}
|
||||
|
||||
// Write type byte
|
||||
if typeInfo.Byte != 0x00 {
|
||||
WriteByte(typeInfo.Byte, w, n, err)
|
||||
}
|
||||
|
||||
// All other types
|
||||
switch rt.Kind() {
|
||||
case reflect.Array:
|
||||
elemRt := rt.Elem()
|
||||
length := rt.Len()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
// Special case: Bytearrays
|
||||
if rv.CanAddr() {
|
||||
byteslice := rv.Slice(0, length).Bytes()
|
||||
WriteTo(byteslice, w, n, err)
|
||||
} else {
|
||||
buf := make([]byte, length)
|
||||
reflect.Copy(reflect.ValueOf(buf), rv)
|
||||
WriteTo(buf, w, n, err)
|
||||
}
|
||||
} else {
|
||||
// Write elems
|
||||
for i := 0; i < length; i++ {
|
||||
elemRv := rv.Index(i)
|
||||
writeReflectBinary(elemRv, elemRt, opts, w, n, err)
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
elemRt := rt.Elem()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
// Special case: Byteslices
|
||||
byteslice := rv.Bytes()
|
||||
WriteByteSlice(byteslice, w, n, err)
|
||||
} else {
|
||||
// Write length
|
||||
length := rv.Len()
|
||||
WriteVarint(length, w, n, err)
|
||||
// Write elems
|
||||
for i := 0; i < length; i++ {
|
||||
elemRv := rv.Index(i)
|
||||
writeReflectBinary(elemRv, elemRt, opts, w, n, err)
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
if rt == timeType {
|
||||
// Special case: time.Time
|
||||
WriteTime(rv.Interface().(time.Time), w, n, err)
|
||||
} else {
|
||||
for _, fieldInfo := range typeInfo.Fields {
|
||||
i, fieldType, opts := fieldInfo.unpack()
|
||||
fieldRv := rv.Field(i)
|
||||
writeReflectBinary(fieldRv, fieldType, opts, w, n, err)
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
WriteString(rv.String(), w, n, err)
|
||||
|
||||
case reflect.Int64:
|
||||
if opts.Varint {
|
||||
WriteVarint(int(rv.Int()), w, n, err)
|
||||
} else {
|
||||
WriteInt64(rv.Int(), w, n, err)
|
||||
}
|
||||
|
||||
case reflect.Int32:
|
||||
WriteInt32(int32(rv.Int()), w, n, err)
|
||||
|
||||
case reflect.Int16:
|
||||
WriteInt16(int16(rv.Int()), w, n, err)
|
||||
|
||||
case reflect.Int8:
|
||||
WriteInt8(int8(rv.Int()), w, n, err)
|
||||
|
||||
case reflect.Int:
|
||||
WriteVarint(int(rv.Int()), w, n, err)
|
||||
|
||||
case reflect.Uint64:
|
||||
if opts.Varint {
|
||||
WriteUvarint(uint(rv.Uint()), w, n, err)
|
||||
} else {
|
||||
WriteUint64(rv.Uint(), w, n, err)
|
||||
}
|
||||
|
||||
case reflect.Uint32:
|
||||
WriteUint32(uint32(rv.Uint()), w, n, err)
|
||||
|
||||
case reflect.Uint16:
|
||||
WriteUint16(uint16(rv.Uint()), w, n, err)
|
||||
|
||||
case reflect.Uint8:
|
||||
WriteUint8(uint8(rv.Uint()), w, n, err)
|
||||
|
||||
case reflect.Uint:
|
||||
WriteUvarint(uint(rv.Uint()), w, n, err)
|
||||
|
||||
case reflect.Bool:
|
||||
if rv.Bool() {
|
||||
WriteUint8(uint8(1), w, n, err)
|
||||
} else {
|
||||
WriteUint8(uint8(0), w, n, err)
|
||||
}
|
||||
|
||||
default:
|
||||
PanicSanity(Fmt("Unknown field type %v", rt.Kind()))
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
func readByteJSON(o interface{}) (typeByte byte, rest interface{}, err error) {
|
||||
oSlice, ok := o.([]interface{})
|
||||
if !ok {
|
||||
err = errors.New(Fmt("Expected type [Byte,?] but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
if len(oSlice) != 2 {
|
||||
err = errors.New(Fmt("Expected [Byte,?] len 2 but got len %v", len(oSlice)))
|
||||
return
|
||||
}
|
||||
typeByte_, ok := oSlice[0].(float64)
|
||||
typeByte = byte(typeByte_)
|
||||
rest = oSlice[1]
|
||||
return
|
||||
}
|
||||
|
||||
// Contract: Caller must ensure that rt is supported
|
||||
// (e.g. is recursively composed of supported native types, and structs and slices.)
|
||||
// rv and rt refer to the object we're unmarhsaling into, whereas o is the result of naiive json unmarshal (map[string]interface{})
|
||||
func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *error) {
|
||||
|
||||
// Get typeInfo
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
|
||||
if rt.Kind() == reflect.Interface {
|
||||
if !typeInfo.IsRegisteredInterface {
|
||||
// There's no way we can read such a thing.
|
||||
*err = errors.New(Fmt("Cannot read unregistered interface type %v", rt))
|
||||
return
|
||||
}
|
||||
if o == nil {
|
||||
return // nil
|
||||
}
|
||||
typeByte, _, err_ := readByteJSON(o)
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
crt, ok := typeInfo.ByteToType[typeByte]
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Byte %X not registered for interface %v", typeByte, rt))
|
||||
return
|
||||
}
|
||||
crv := reflect.New(crt).Elem()
|
||||
readReflectJSON(crv, crt, o, err)
|
||||
rv.Set(crv) // NOTE: orig rv is ignored.
|
||||
return
|
||||
}
|
||||
|
||||
if rt.Kind() == reflect.Ptr {
|
||||
if o == nil {
|
||||
return // nil
|
||||
}
|
||||
// Create new struct if rv is nil.
|
||||
if rv.IsNil() {
|
||||
newRv := reflect.New(rt.Elem())
|
||||
rv.Set(newRv)
|
||||
rv = newRv
|
||||
}
|
||||
// Dereference pointer
|
||||
rv, rt = rv.Elem(), rt.Elem()
|
||||
typeInfo = GetTypeInfo(rt)
|
||||
// continue...
|
||||
}
|
||||
|
||||
// Read Byte prefix
|
||||
if typeInfo.Byte != 0x00 {
|
||||
typeByte, rest, err_ := readByteJSON(o)
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
if typeByte != typeInfo.Byte {
|
||||
*err = errors.New(Fmt("Expected Byte of %X but got %X", typeInfo.Byte, byte(typeByte)))
|
||||
return
|
||||
}
|
||||
o = rest
|
||||
}
|
||||
|
||||
switch rt.Kind() {
|
||||
case reflect.Array:
|
||||
elemRt := rt.Elem()
|
||||
length := rt.Len()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
// Special case: Bytearrays
|
||||
oString, ok := o.(string)
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
buf, err_ := hex.DecodeString(oString)
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
if len(buf) != length {
|
||||
*err = errors.New(Fmt("Expected bytearray of length %v but got %v", length, len(buf)))
|
||||
return
|
||||
}
|
||||
log.Info("Read bytearray", "bytes", buf)
|
||||
reflect.Copy(rv, reflect.ValueOf(buf))
|
||||
} else {
|
||||
oSlice, ok := o.([]interface{})
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected array of %v but got type %v", rt, reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
if len(oSlice) != length {
|
||||
*err = errors.New(Fmt("Expected array of length %v but got %v", length, len(oSlice)))
|
||||
return
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
elemRv := rv.Index(i)
|
||||
readReflectJSON(elemRv, elemRt, oSlice[i], err)
|
||||
}
|
||||
log.Info(Fmt("Read %v-array", elemRt), "length", length)
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
elemRt := rt.Elem()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
// Special case: Byteslices
|
||||
oString, ok := o.(string)
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
byteslice, err_ := hex.DecodeString(oString)
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
log.Info("Read byteslice", "bytes", byteslice)
|
||||
rv.Set(reflect.ValueOf(byteslice))
|
||||
} else {
|
||||
// Read length
|
||||
oSlice, ok := o.([]interface{})
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected array of %v but got type %v", rt, reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
length := len(oSlice)
|
||||
log.Info(Fmt("Read length: %v", length))
|
||||
sliceRv := reflect.MakeSlice(rt, length, length)
|
||||
// Read elems
|
||||
for i := 0; i < length; i++ {
|
||||
elemRv := sliceRv.Index(i)
|
||||
readReflectJSON(elemRv, elemRt, oSlice[i], err)
|
||||
}
|
||||
rv.Set(sliceRv)
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
if rt == timeType {
|
||||
// Special case: time.Time
|
||||
str, ok := o.(string)
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
log.Info(Fmt("Read time: %v", str))
|
||||
t, err_ := time.Parse(iso8601, str)
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
rv.Set(reflect.ValueOf(t))
|
||||
} else {
|
||||
oMap, ok := o.(map[string]interface{})
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected map but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
// TODO: ensure that all fields are set?
|
||||
// TODO: disallow unknown oMap fields?
|
||||
for _, fieldInfo := range typeInfo.Fields {
|
||||
i, fieldType, opts := fieldInfo.unpack()
|
||||
value, ok := oMap[opts.JSONName]
|
||||
if !ok {
|
||||
continue // Skip missing fields.
|
||||
}
|
||||
fieldRv := rv.Field(i)
|
||||
readReflectJSON(fieldRv, fieldType, value, err)
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
str, ok := o.(string)
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
log.Info(Fmt("Read string: %v", str))
|
||||
rv.SetString(str)
|
||||
|
||||
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
|
||||
num, ok := o.(float64)
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected numeric but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetInt(int64(num))
|
||||
|
||||
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
|
||||
num, ok := o.(float64)
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected numeric but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
if num < 0 {
|
||||
*err = errors.New(Fmt("Expected unsigned numeric but got %v", num))
|
||||
return
|
||||
}
|
||||
log.Info(Fmt("Read num: %v", num))
|
||||
rv.SetUint(uint64(num))
|
||||
|
||||
case reflect.Bool:
|
||||
bl, ok := o.(bool)
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Expected boolean but got type %v", reflect.TypeOf(o)))
|
||||
return
|
||||
}
|
||||
log.Info(Fmt("Read boolean: %v", bl))
|
||||
rv.SetBool(bl)
|
||||
|
||||
default:
|
||||
PanicSanity(Fmt("Unknown field type %v", rt.Kind()))
|
||||
}
|
||||
}
|
||||
|
||||
func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err *error) {
|
||||
log.Info(Fmt("writeReflectJSON(%v, %v, %v, %v, %v)", rv, rt, w, n, err))
|
||||
|
||||
// Get typeInfo
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
|
||||
if rt.Kind() == reflect.Interface {
|
||||
if rv.IsNil() {
|
||||
// XXX ensure that typeByte 0 is reserved.
|
||||
WriteTo([]byte("null"), w, n, err)
|
||||
return
|
||||
}
|
||||
crv := rv.Elem() // concrete reflection value
|
||||
crt := crv.Type() // concrete reflection type
|
||||
if typeInfo.IsRegisteredInterface {
|
||||
// See if the crt is registered.
|
||||
// If so, we're more restrictive.
|
||||
_, ok := typeInfo.TypeToByte[crt]
|
||||
if !ok {
|
||||
switch crt.Kind() {
|
||||
case reflect.Ptr:
|
||||
*err = errors.New(Fmt("Unexpected pointer type %v for registered interface %v. "+
|
||||
"Was it registered as a value receiver rather than as a pointer receiver?", crt, rt.Name()))
|
||||
case reflect.Struct:
|
||||
*err = errors.New(Fmt("Unexpected struct type %v for registered interface %v. "+
|
||||
"Was it registered as a pointer receiver rather than as a value receiver?", crt, rt.Name()))
|
||||
default:
|
||||
*err = errors.New(Fmt("Unexpected type %v for registered interface %v. "+
|
||||
"If this is intentional, please register it.", crt, rt.Name()))
|
||||
}
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// We support writing unsafely for convenience.
|
||||
}
|
||||
// We don't have to write the typeByte here,
|
||||
// the writeReflectJSON() call below will write it.
|
||||
writeReflectJSON(crv, crt, w, n, err)
|
||||
return
|
||||
}
|
||||
|
||||
if rt.Kind() == reflect.Ptr {
|
||||
// Dereference pointer
|
||||
rv, rt = rv.Elem(), rt.Elem()
|
||||
typeInfo = GetTypeInfo(rt)
|
||||
if !rv.IsValid() {
|
||||
// For better compatibility with other languages,
|
||||
// as far as tendermint/wire is concerned,
|
||||
// pointers to nil values are the same as nil.
|
||||
WriteTo([]byte("null"), w, n, err)
|
||||
return
|
||||
}
|
||||
// continue...
|
||||
}
|
||||
|
||||
// Write Byte
|
||||
if typeInfo.Byte != 0x00 {
|
||||
WriteTo([]byte(Fmt("[%v,", typeInfo.Byte)), w, n, err)
|
||||
defer WriteTo([]byte("]"), w, n, err)
|
||||
}
|
||||
|
||||
// All other types
|
||||
switch rt.Kind() {
|
||||
case reflect.Array:
|
||||
elemRt := rt.Elem()
|
||||
length := rt.Len()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
// Special case: Bytearray
|
||||
bytearray := reflect.ValueOf(make([]byte, length))
|
||||
reflect.Copy(bytearray, rv)
|
||||
WriteTo([]byte(Fmt("\"%X\"", bytearray.Interface())), w, n, err)
|
||||
} else {
|
||||
WriteTo([]byte("["), w, n, err)
|
||||
// Write elems
|
||||
for i := 0; i < length; i++ {
|
||||
elemRv := rv.Index(i)
|
||||
writeReflectJSON(elemRv, elemRt, w, n, err)
|
||||
if i < length-1 {
|
||||
WriteTo([]byte(","), w, n, err)
|
||||
}
|
||||
}
|
||||
WriteTo([]byte("]"), w, n, err)
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
elemRt := rt.Elem()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
// Special case: Byteslices
|
||||
byteslice := rv.Bytes()
|
||||
WriteTo([]byte(Fmt("\"%X\"", byteslice)), w, n, err)
|
||||
} else {
|
||||
WriteTo([]byte("["), w, n, err)
|
||||
// Write elems
|
||||
length := rv.Len()
|
||||
for i := 0; i < length; i++ {
|
||||
elemRv := rv.Index(i)
|
||||
writeReflectJSON(elemRv, elemRt, w, n, err)
|
||||
if i < length-1 {
|
||||
WriteTo([]byte(","), w, n, err)
|
||||
}
|
||||
}
|
||||
WriteTo([]byte("]"), w, n, err)
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
if rt == timeType {
|
||||
// Special case: time.Time
|
||||
t := rv.Interface().(time.Time).UTC()
|
||||
str := t.Format(iso8601)
|
||||
jsonBytes, err_ := json.Marshal(str)
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
WriteTo(jsonBytes, w, n, err)
|
||||
} else {
|
||||
WriteTo([]byte("{"), w, n, err)
|
||||
wroteField := false
|
||||
for _, fieldInfo := range typeInfo.Fields {
|
||||
i, fieldType, opts := fieldInfo.unpack()
|
||||
fieldRv := rv.Field(i)
|
||||
if wroteField {
|
||||
WriteTo([]byte(","), w, n, err)
|
||||
} else {
|
||||
wroteField = true
|
||||
}
|
||||
WriteTo([]byte(Fmt("\"%v\":", opts.JSONName)), w, n, err)
|
||||
writeReflectJSON(fieldRv, fieldType, w, n, err)
|
||||
}
|
||||
WriteTo([]byte("}"), w, n, err)
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
fallthrough
|
||||
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
|
||||
fallthrough
|
||||
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
|
||||
fallthrough
|
||||
case reflect.Bool:
|
||||
jsonBytes, err_ := json.Marshal(rv.Interface())
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
WriteTo(jsonBytes, w, n, err)
|
||||
|
||||
default:
|
||||
PanicSanity(Fmt("Unknown field type %v", rt.Kind()))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,508 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
)
|
||||
|
||||
type SimpleStruct struct {
|
||||
String string
|
||||
Bytes []byte
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
type Animal interface{}
|
||||
|
||||
const (
|
||||
AnimalTypeCat = byte(0x01)
|
||||
AnimalTypeDog = byte(0x02)
|
||||
AnimalTypeSnake = byte(0x03)
|
||||
AnimalTypeViper = byte(0x04)
|
||||
)
|
||||
|
||||
// Implements Animal
|
||||
type Cat struct {
|
||||
SimpleStruct
|
||||
}
|
||||
|
||||
// Implements Animal
|
||||
type Dog struct {
|
||||
SimpleStruct
|
||||
}
|
||||
|
||||
// Implements Animal
|
||||
type Snake []byte
|
||||
|
||||
// Implements Animal
|
||||
type Viper struct {
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
var _ = RegisterInterface(
|
||||
struct{ Animal }{},
|
||||
ConcreteType{Cat{}, AnimalTypeCat},
|
||||
ConcreteType{Dog{}, AnimalTypeDog},
|
||||
ConcreteType{Snake{}, AnimalTypeSnake},
|
||||
ConcreteType{&Viper{}, AnimalTypeViper},
|
||||
)
|
||||
|
||||
// TODO: add assertions here ...
|
||||
func TestAnimalInterface(t *testing.T) {
|
||||
var foo Animal
|
||||
|
||||
// Type of pointer to Animal
|
||||
rt := reflect.TypeOf(&foo)
|
||||
fmt.Printf("rt: %v\n", rt)
|
||||
|
||||
// Type of Animal itself.
|
||||
// NOTE: normally this is acquired through other means
|
||||
// like introspecting on method signatures, or struct fields.
|
||||
rte := rt.Elem()
|
||||
fmt.Printf("rte: %v\n", rte)
|
||||
|
||||
// Get a new pointer to the interface
|
||||
// NOTE: calling .Interface() is to get the actual value,
|
||||
// instead of reflection values.
|
||||
ptr := reflect.New(rte).Interface()
|
||||
fmt.Printf("ptr: %v", ptr)
|
||||
|
||||
// Make a binary byteslice that represents a *snake.
|
||||
foo = Snake([]byte("snake"))
|
||||
snakeBytes := BinaryBytes(foo)
|
||||
snakeReader := bytes.NewReader(snakeBytes)
|
||||
|
||||
// Now you can read it.
|
||||
n, err := new(int64), new(error)
|
||||
it := ReadBinary(foo, snakeReader, n, err).(Animal)
|
||||
fmt.Println(it, reflect.TypeOf(it))
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type Constructor func() interface{}
|
||||
type Instantiator func() (o interface{}, ptr interface{})
|
||||
type Validator func(o interface{}, t *testing.T)
|
||||
|
||||
type TestCase struct {
|
||||
Constructor
|
||||
Instantiator
|
||||
Validator
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
func constructBasic() interface{} {
|
||||
cat := Cat{
|
||||
SimpleStruct{
|
||||
String: "String",
|
||||
Bytes: []byte("Bytes"),
|
||||
Time: time.Unix(123, 456789999),
|
||||
},
|
||||
}
|
||||
return cat
|
||||
}
|
||||
|
||||
func instantiateBasic() (interface{}, interface{}) {
|
||||
return Cat{}, &Cat{}
|
||||
}
|
||||
|
||||
func validateBasic(o interface{}, t *testing.T) {
|
||||
cat := o.(Cat)
|
||||
if cat.String != "String" {
|
||||
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
|
||||
}
|
||||
if string(cat.Bytes) != "Bytes" {
|
||||
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
|
||||
}
|
||||
if cat.Time.UnixNano() != 123456000000 { // Only milliseconds
|
||||
t.Errorf("Expected cat.Time.UnixNano() == 123456000000, got %v", cat.Time.UnixNano())
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type NilTestStruct struct {
|
||||
IntPtr *int
|
||||
CatPtr *Cat
|
||||
Animal Animal
|
||||
}
|
||||
|
||||
func constructNilTestStruct() interface{} {
|
||||
return NilTestStruct{}
|
||||
}
|
||||
|
||||
func instantiateNilTestStruct() (interface{}, interface{}) {
|
||||
return NilTestStruct{}, &NilTestStruct{}
|
||||
}
|
||||
|
||||
func validateNilTestStruct(o interface{}, t *testing.T) {
|
||||
nts := o.(NilTestStruct)
|
||||
if nts.IntPtr != nil {
|
||||
t.Errorf("Expected nts.IntPtr to be nil, got %v", nts.IntPtr)
|
||||
}
|
||||
if nts.CatPtr != nil {
|
||||
t.Errorf("Expected nts.CatPtr to be nil, got %v", nts.CatPtr)
|
||||
}
|
||||
if nts.Animal != nil {
|
||||
t.Errorf("Expected nts.Animal to be nil, got %v", nts.Animal)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type ComplexStruct struct {
|
||||
Name string
|
||||
Animal Animal
|
||||
}
|
||||
|
||||
func constructComplex() interface{} {
|
||||
c := ComplexStruct{
|
||||
Name: "Complex",
|
||||
Animal: constructBasic(),
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func instantiateComplex() (interface{}, interface{}) {
|
||||
return ComplexStruct{}, &ComplexStruct{}
|
||||
}
|
||||
|
||||
func validateComplex(o interface{}, t *testing.T) {
|
||||
c2 := o.(ComplexStruct)
|
||||
if cat, ok := c2.Animal.(Cat); ok {
|
||||
validateBasic(cat, t)
|
||||
} else {
|
||||
t.Errorf("Expected c2.Animal to be of type cat, got %v", reflect.ValueOf(c2.Animal).Elem().Type())
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type ComplexStruct2 struct {
|
||||
Cat Cat
|
||||
Dog *Dog
|
||||
Snake Snake
|
||||
Snake2 *Snake
|
||||
Viper Viper
|
||||
Viper2 *Viper
|
||||
}
|
||||
|
||||
func constructComplex2() interface{} {
|
||||
snake_ := Snake([]byte("hiss"))
|
||||
snakePtr_ := &snake_
|
||||
|
||||
c := ComplexStruct2{
|
||||
Cat: Cat{
|
||||
SimpleStruct{
|
||||
String: "String",
|
||||
Bytes: []byte("Bytes"),
|
||||
},
|
||||
},
|
||||
Dog: &Dog{
|
||||
SimpleStruct{
|
||||
String: "Woof",
|
||||
Bytes: []byte("Bark"),
|
||||
},
|
||||
},
|
||||
Snake: Snake([]byte("hiss")),
|
||||
Snake2: snakePtr_,
|
||||
Viper: Viper{Bytes: []byte("hizz")},
|
||||
Viper2: &Viper{Bytes: []byte("hizz")},
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func instantiateComplex2() (interface{}, interface{}) {
|
||||
return ComplexStruct2{}, &ComplexStruct2{}
|
||||
}
|
||||
|
||||
func validateComplex2(o interface{}, t *testing.T) {
|
||||
c2 := o.(ComplexStruct2)
|
||||
cat := c2.Cat
|
||||
if cat.String != "String" {
|
||||
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
|
||||
}
|
||||
if string(cat.Bytes) != "Bytes" {
|
||||
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
|
||||
}
|
||||
|
||||
dog := c2.Dog
|
||||
if dog.String != "Woof" {
|
||||
t.Errorf("Expected dog.String == 'Woof', got %v", dog.String)
|
||||
}
|
||||
if string(dog.Bytes) != "Bark" {
|
||||
t.Errorf("Expected dog.Bytes == 'Bark', got %X", dog.Bytes)
|
||||
}
|
||||
|
||||
snake := c2.Snake
|
||||
if string(snake) != "hiss" {
|
||||
t.Errorf("Expected string(snake) == 'hiss', got %v", string(snake))
|
||||
}
|
||||
|
||||
snake2 := c2.Snake2
|
||||
if string(*snake2) != "hiss" {
|
||||
t.Errorf("Expected string(snake2) == 'hiss', got %v", string(*snake2))
|
||||
}
|
||||
|
||||
viper := c2.Viper
|
||||
if string(viper.Bytes) != "hizz" {
|
||||
t.Errorf("Expected string(viper.Bytes) == 'hizz', got %v", string(viper.Bytes))
|
||||
}
|
||||
|
||||
viper2 := c2.Viper2
|
||||
if string(viper2.Bytes) != "hizz" {
|
||||
t.Errorf("Expected string(viper2.Bytes) == 'hizz', got %v", string(viper2.Bytes))
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type ComplexStructArray struct {
|
||||
Animals []Animal
|
||||
Bytes [5]byte
|
||||
Ints [5]int
|
||||
Array SimpleArray
|
||||
}
|
||||
|
||||
func constructComplexArray() interface{} {
|
||||
c := ComplexStructArray{
|
||||
Animals: []Animal{
|
||||
Cat{
|
||||
SimpleStruct{
|
||||
String: "String",
|
||||
Bytes: []byte("Bytes"),
|
||||
},
|
||||
},
|
||||
Dog{
|
||||
SimpleStruct{
|
||||
String: "Woof",
|
||||
Bytes: []byte("Bark"),
|
||||
},
|
||||
},
|
||||
Snake([]byte("hiss")),
|
||||
&Viper{
|
||||
Bytes: []byte("hizz"),
|
||||
},
|
||||
},
|
||||
Bytes: [5]byte{1, 10, 50, 100, 200},
|
||||
Ints: [5]int{1, 2, 3, 4, 5},
|
||||
Array: SimpleArray([5]byte{1, 10, 50, 100, 200}),
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func instantiateComplexArray() (interface{}, interface{}) {
|
||||
return ComplexStructArray{}, &ComplexStructArray{}
|
||||
}
|
||||
|
||||
func validateComplexArray(o interface{}, t *testing.T) {
|
||||
c2 := o.(ComplexStructArray)
|
||||
if cat, ok := c2.Animals[0].(Cat); ok {
|
||||
if cat.String != "String" {
|
||||
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
|
||||
}
|
||||
if string(cat.Bytes) != "Bytes" {
|
||||
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Expected c2.Animals[0] to be of type cat, got %v", reflect.ValueOf(c2.Animals[0]).Elem().Type())
|
||||
}
|
||||
|
||||
if dog, ok := c2.Animals[1].(Dog); ok {
|
||||
if dog.String != "Woof" {
|
||||
t.Errorf("Expected dog.String == 'Woof', got %v", dog.String)
|
||||
}
|
||||
if string(dog.Bytes) != "Bark" {
|
||||
t.Errorf("Expected dog.Bytes == 'Bark', got %X", dog.Bytes)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Expected c2.Animals[1] to be of type dog, got %v", reflect.ValueOf(c2.Animals[1]).Elem().Type())
|
||||
}
|
||||
|
||||
if snake, ok := c2.Animals[2].(Snake); ok {
|
||||
if string(snake) != "hiss" {
|
||||
t.Errorf("Expected string(snake) == 'hiss', got %v", string(snake))
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Expected c2.Animals[2] to be of type Snake, got %v", reflect.ValueOf(c2.Animals[2]).Elem().Type())
|
||||
}
|
||||
|
||||
if viper, ok := c2.Animals[3].(*Viper); ok {
|
||||
if string(viper.Bytes) != "hizz" {
|
||||
t.Errorf("Expected string(viper.Bytes) == 'hizz', got %v", string(viper.Bytes))
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Expected c2.Animals[3] to be of type *Viper, got %v", reflect.ValueOf(c2.Animals[3]).Elem().Type())
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
var testCases = []TestCase{}
|
||||
|
||||
func init() {
|
||||
testCases = append(testCases, TestCase{constructBasic, instantiateBasic, validateBasic})
|
||||
testCases = append(testCases, TestCase{constructComplex, instantiateComplex, validateComplex})
|
||||
testCases = append(testCases, TestCase{constructComplex2, instantiateComplex2, validateComplex2})
|
||||
testCases = append(testCases, TestCase{constructComplexArray, instantiateComplexArray, validateComplexArray})
|
||||
testCases = append(testCases, TestCase{constructNilTestStruct, instantiateNilTestStruct, validateNilTestStruct})
|
||||
}
|
||||
|
||||
func TestBinary(t *testing.T) {
|
||||
|
||||
for i, testCase := range testCases {
|
||||
|
||||
log.Notice(fmt.Sprintf("Running test case %v", i))
|
||||
|
||||
// Construct an object
|
||||
o := testCase.Constructor()
|
||||
|
||||
// Write the object
|
||||
data := BinaryBytes(o)
|
||||
t.Logf("Binary: %X", data)
|
||||
|
||||
instance, instancePtr := testCase.Instantiator()
|
||||
|
||||
// Read onto a struct
|
||||
n, err := new(int64), new(error)
|
||||
res := ReadBinary(instance, bytes.NewReader(data), n, err)
|
||||
if *err != nil {
|
||||
t.Fatalf("Failed to read into instance: %v", *err)
|
||||
}
|
||||
|
||||
// Validate object
|
||||
testCase.Validator(res, t)
|
||||
|
||||
// Read onto a pointer
|
||||
n, err = new(int64), new(error)
|
||||
res = ReadBinaryPtr(instancePtr, bytes.NewReader(data), n, err)
|
||||
if *err != nil {
|
||||
t.Fatalf("Failed to read into instance: %v", *err)
|
||||
}
|
||||
|
||||
if res != instancePtr {
|
||||
t.Errorf("Expected pointer to pass through")
|
||||
}
|
||||
|
||||
// Validate object
|
||||
testCase.Validator(reflect.ValueOf(res).Elem().Interface(), t)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestJSON(t *testing.T) {
|
||||
|
||||
for i, testCase := range testCases {
|
||||
|
||||
log.Notice(fmt.Sprintf("Running test case %v", i))
|
||||
|
||||
// Construct an object
|
||||
o := testCase.Constructor()
|
||||
|
||||
// Write the object
|
||||
data := JSONBytes(o)
|
||||
t.Logf("JSON: %v", string(data))
|
||||
|
||||
instance, instancePtr := testCase.Instantiator()
|
||||
|
||||
// Read onto a struct
|
||||
err := new(error)
|
||||
res := ReadJSON(instance, data, err)
|
||||
if *err != nil {
|
||||
t.Fatalf("Failed to read cat: %v", *err)
|
||||
}
|
||||
|
||||
// Validate object
|
||||
testCase.Validator(res, t)
|
||||
|
||||
// Read onto a pointer
|
||||
res = ReadJSON(instancePtr, data, err)
|
||||
if *err != nil {
|
||||
t.Fatalf("Failed to read cat: %v", *err)
|
||||
}
|
||||
|
||||
if res != instancePtr {
|
||||
t.Errorf("Expected pointer to pass through")
|
||||
}
|
||||
|
||||
// Validate object
|
||||
testCase.Validator(reflect.ValueOf(res).Elem().Interface(), t)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type Foo struct {
|
||||
FieldA string `json:"fieldA"` // json field name is "fieldA"
|
||||
FieldB string // json field name is "FieldB"
|
||||
fieldC string // not exported, not serialized.
|
||||
}
|
||||
|
||||
func TestJSONFieldNames(t *testing.T) {
|
||||
for i := 0; i < 20; i++ { // Try to ensure deterministic success.
|
||||
foo := Foo{"a", "b", "c"}
|
||||
stringified := string(JSONBytes(foo))
|
||||
expected := `{"fieldA":"a","FieldB":"b"}`
|
||||
if stringified != expected {
|
||||
t.Fatalf("JSONFieldNames error: expected %v, got %v",
|
||||
expected, stringified)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func TestBadAlloc(t *testing.T) {
|
||||
n, err := new(int64), new(error)
|
||||
instance := new([]byte)
|
||||
data := RandBytes(100 * 1024)
|
||||
b := new(bytes.Buffer)
|
||||
// this slice of data claims to be much bigger than it really is
|
||||
WriteUvarint(uint(10000000000000000), b, n, err)
|
||||
b.Write(data)
|
||||
res := ReadBinary(instance, b, n, err)
|
||||
fmt.Println(res, *err)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type SimpleArray [5]byte
|
||||
|
||||
func TestSimpleArray(t *testing.T) {
|
||||
var foo SimpleArray
|
||||
|
||||
// Type of pointer to array
|
||||
rt := reflect.TypeOf(&foo)
|
||||
fmt.Printf("rt: %v\n", rt) // *binary.SimpleArray
|
||||
|
||||
// Type of array itself.
|
||||
// NOTE: normally this is acquired through other means
|
||||
// like introspecting on method signatures, or struct fields.
|
||||
rte := rt.Elem()
|
||||
fmt.Printf("rte: %v\n", rte) // binary.SimpleArray
|
||||
|
||||
// Get a new pointer to the array
|
||||
// NOTE: calling .Interface() is to get the actual value,
|
||||
// instead of reflection values.
|
||||
ptr := reflect.New(rte).Interface()
|
||||
fmt.Printf("ptr: %v\n", ptr) // &[0 0 0 0 0]
|
||||
|
||||
// Make a simple int aray
|
||||
fooArray := SimpleArray([5]byte{1, 10, 50, 100, 200})
|
||||
fooBytes := BinaryBytes(fooArray)
|
||||
fooReader := bytes.NewReader(fooBytes)
|
||||
|
||||
// Now you can read it.
|
||||
n, err := new(int64), new(error)
|
||||
it := ReadBinary(foo, fooReader, n, err).(SimpleArray)
|
||||
|
||||
if !bytes.Equal(it[:], fooArray[:]) {
|
||||
t.Errorf("Expected %v but got %v", fooArray, it)
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
)
|
||||
|
||||
// String
|
||||
|
||||
func WriteString(s string, w io.Writer, n *int64, err *error) {
|
||||
WriteVarint(len(s), w, n, err)
|
||||
WriteTo([]byte(s), w, n, err)
|
||||
}
|
||||
|
||||
func ReadString(r io.Reader, n *int64, err *error) string {
|
||||
length := ReadVarint(r, n, err)
|
||||
if *err != nil {
|
||||
return ""
|
||||
}
|
||||
if length < 0 {
|
||||
*err = ErrBinaryReadSizeUnderflow
|
||||
return ""
|
||||
}
|
||||
if MaxBinaryReadSize < MaxInt64(int64(length), *n+int64(length)) {
|
||||
*err = ErrBinaryReadSizeOverflow
|
||||
return ""
|
||||
}
|
||||
|
||||
buf := make([]byte, length)
|
||||
ReadFull(buf, r, n, err)
|
||||
return string(buf)
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
)
|
||||
|
||||
/*
|
||||
Writes nanoseconds since epoch but with millisecond precision.
|
||||
This is to ease compatibility with Javascript etc.
|
||||
*/
|
||||
|
||||
func WriteTime(t time.Time, w io.Writer, n *int64, err *error) {
|
||||
nanosecs := t.UnixNano()
|
||||
millisecs := nanosecs / 1000000
|
||||
WriteInt64(millisecs*1000000, w, n, err)
|
||||
}
|
||||
|
||||
func ReadTime(r io.Reader, n *int64, err *error) time.Time {
|
||||
t := ReadInt64(r, n, err)
|
||||
if t%1000000 != 0 {
|
||||
PanicSanity("Time cannot have sub-millisecond precision")
|
||||
}
|
||||
return time.Unix(0, t)
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
)
|
||||
|
||||
func BinaryBytes(o interface{}) []byte {
|
||||
w, n, err := new(bytes.Buffer), new(int64), new(error)
|
||||
WriteBinary(o, w, n, err)
|
||||
if *err != nil {
|
||||
PanicSanity(*err)
|
||||
}
|
||||
return w.Bytes()
|
||||
}
|
||||
|
||||
func JSONBytes(o interface{}) []byte {
|
||||
w, n, err := new(bytes.Buffer), new(int64), new(error)
|
||||
WriteJSON(o, w, n, err)
|
||||
if *err != nil {
|
||||
PanicSanity(*err)
|
||||
}
|
||||
return w.Bytes()
|
||||
}
|
||||
|
||||
// NOTE: inefficient
|
||||
func JSONBytesPretty(o interface{}) []byte {
|
||||
jsonBytes := JSONBytes(o)
|
||||
var object interface{}
|
||||
err := json.Unmarshal(jsonBytes, &object)
|
||||
if err != nil {
|
||||
PanicSanity(err)
|
||||
}
|
||||
jsonBytes, err = json.MarshalIndent(object, "", "\t")
|
||||
if err != nil {
|
||||
PanicSanity(err)
|
||||
}
|
||||
return jsonBytes
|
||||
}
|
||||
|
||||
// NOTE: does not care about the type, only the binary representation.
|
||||
func BinaryEqual(a, b interface{}) bool {
|
||||
aBytes := BinaryBytes(a)
|
||||
bBytes := BinaryBytes(b)
|
||||
return bytes.Equal(aBytes, bBytes)
|
||||
}
|
||||
|
||||
// NOTE: does not care about the type, only the binary representation.
|
||||
func BinaryCompare(a, b interface{}) int {
|
||||
aBytes := BinaryBytes(a)
|
||||
bBytes := BinaryBytes(b)
|
||||
return bytes.Compare(aBytes, bBytes)
|
||||
}
|
||||
|
||||
// NOTE: only use this if you need 32 bytes.
|
||||
func BinarySha256(o interface{}) []byte {
|
||||
hasher, n, err := sha256.New(), new(int64), new(error)
|
||||
WriteBinary(o, hasher, n, err)
|
||||
if *err != nil {
|
||||
PanicSanity(*err)
|
||||
}
|
||||
return hasher.Sum(nil)
|
||||
}
|
||||
|
||||
// NOTE: The default hash function is Ripemd160.
|
||||
func BinaryRipemd160(o interface{}) []byte {
|
||||
hasher, n, err := ripemd160.New(), new(int64), new(error)
|
||||
WriteBinary(o, hasher, n, err)
|
||||
if *err != nil {
|
||||
PanicSanity(*err)
|
||||
}
|
||||
return hasher.Sum(nil)
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
package wire
|
||||
|
||||
const Version = "0.5.0"
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
)
|
||||
|
||||
// TODO document and maybe make it configurable.
|
||||
const MaxBinaryReadSize = 21 * 1024 * 1024
|
||||
|
||||
var ErrBinaryReadSizeOverflow = errors.New("Error: binary read size overflow")
|
||||
var ErrBinaryReadSizeUnderflow = errors.New("Error: binary read size underflow")
|
||||
|
||||
func ReadBinary(o interface{}, r io.Reader, n *int64, err *error) interface{} {
|
||||
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
// This allows ReadBinaryObject() to return a nil pointer,
|
||||
// if the value read is nil.
|
||||
rvPtr := reflect.New(rt)
|
||||
ReadBinaryPtr(rvPtr.Interface(), r, n, err)
|
||||
return rvPtr.Elem().Interface()
|
||||
} else {
|
||||
readReflectBinary(rv, rt, Options{}, r, n, err)
|
||||
return o
|
||||
}
|
||||
} else {
|
||||
ptrRv := reflect.New(rt)
|
||||
readReflectBinary(ptrRv.Elem(), rt, Options{}, r, n, err)
|
||||
return ptrRv.Elem().Interface()
|
||||
}
|
||||
}
|
||||
|
||||
func ReadBinaryPtr(o interface{}, r io.Reader, n *int64, err *error) interface{} {
|
||||
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
readReflectBinary(rv.Elem(), rt.Elem(), Options{}, r, n, err)
|
||||
} else {
|
||||
PanicSanity("ReadBinaryPtr expects o to be a pointer")
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func WriteBinary(o interface{}, w io.Writer, n *int64, err *error) {
|
||||
rv := reflect.ValueOf(o)
|
||||
rt := reflect.TypeOf(o)
|
||||
writeReflectBinary(rv, rt, Options{}, w, n, err)
|
||||
}
|
||||
|
||||
func ReadJSON(o interface{}, bytes []byte, err *error) interface{} {
|
||||
var object interface{}
|
||||
*err = json.Unmarshal(bytes, &object)
|
||||
if *err != nil {
|
||||
return o
|
||||
}
|
||||
|
||||
return ReadJSONObject(o, object, err)
|
||||
}
|
||||
|
||||
func ReadJSONPtr(o interface{}, bytes []byte, err *error) interface{} {
|
||||
var object interface{}
|
||||
*err = json.Unmarshal(bytes, &object)
|
||||
if *err != nil {
|
||||
return o
|
||||
}
|
||||
|
||||
return ReadJSONObjectPtr(o, object, err)
|
||||
}
|
||||
|
||||
// o is the ultimate destination, object is the result of json unmarshal
|
||||
func ReadJSONObject(o interface{}, object interface{}, err *error) interface{} {
|
||||
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
// This allows ReadJSONObject() to return a nil pointer
|
||||
// if the value read is nil.
|
||||
rvPtr := reflect.New(rt)
|
||||
ReadJSONObjectPtr(rvPtr.Interface(), object, err)
|
||||
return rvPtr.Elem().Interface()
|
||||
} else {
|
||||
readReflectJSON(rv, rt, object, err)
|
||||
return o
|
||||
}
|
||||
} else {
|
||||
ptrRv := reflect.New(rt)
|
||||
readReflectJSON(ptrRv.Elem(), rt, object, err)
|
||||
return ptrRv.Elem().Interface()
|
||||
}
|
||||
}
|
||||
|
||||
func ReadJSONObjectPtr(o interface{}, object interface{}, err *error) interface{} {
|
||||
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
readReflectJSON(rv.Elem(), rt.Elem(), object, err)
|
||||
} else {
|
||||
PanicSanity("ReadJSON(Object)Ptr expects o to be a pointer")
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func WriteJSON(o interface{}, w io.Writer, n *int64, err *error) {
|
||||
rv := reflect.ValueOf(o)
|
||||
rt := reflect.TypeOf(o)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
rv, rt = rv.Elem(), rt.Elem()
|
||||
}
|
||||
writeReflectJSON(rv, rt, w, n, err)
|
||||
}
|
||||
|
||||
// Write all of bz to w
|
||||
// Increment n and set err accordingly.
|
||||
func WriteTo(bz []byte, w io.Writer, n *int64, err *error) {
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
n_, err_ := w.Write(bz)
|
||||
*n += int64(n_)
|
||||
*err = err_
|
||||
}
|
||||
|
||||
// Read len(buf) from r
|
||||
// Increment n and set err accordingly.
|
||||
func ReadFull(buf []byte, r io.Reader, n *int64, err *error) {
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
n_, err_ := io.ReadFull(r, buf)
|
||||
*n += int64(n_)
|
||||
*err = err_
|
||||
}
|
||||
Reference in New Issue
Block a user