tendermint/binary/reflect.go

317 lines
7.5 KiB
Go
Raw Normal View History

package binary
import (
2014-12-17 01:37:13 -08:00
"errors"
"fmt"
"io"
"reflect"
2014-12-28 17:10:03 -08:00
"sync"
2014-12-29 18:09:06 -08:00
. "github.com/tendermint/tendermint/common"
)
type TypeInfo struct {
Type reflect.Type // The type
Encoder Encoder // Optional custom encoder function
Decoder Decoder // Optional custom decoder function
2014-12-17 01:37:13 -08:00
HasTypeByte bool
TypeByte byte
}
// If a type implements TypeByte, the byte is included
// as the first byte for encoding. This is used to encode
// interfaces/union types. In this case the decoding should
// be done manually with a switch statement, and so the
// reflection-based decoder provided here does not expect this
// prefix byte.
// See the reactor implementations for use-cases.
type HasTypeByte interface {
TypeByte() byte
}
2014-12-28 17:10:03 -08:00
// NOTE: do not access typeInfos directly, but call GetTypeInfo()
var typeInfosMtx sync.Mutex
var typeInfos = map[reflect.Type]*TypeInfo{}
2014-12-28 17:10:03 -08:00
func GetTypeInfo(rt reflect.Type) *TypeInfo {
typeInfosMtx.Lock()
defer typeInfosMtx.Unlock()
info := typeInfos[rt]
if info == nil {
info = &TypeInfo{Type: rt}
RegisterType(info)
}
return info
}
// Registers and possibly modifies the TypeInfo.
// NOTE: not goroutine safe, so only call upon program init.
2014-12-17 01:37:13 -08:00
func RegisterType(info *TypeInfo) *TypeInfo {
// Also register the underlying struct's info, if info.Type is a pointer.
2014-12-17 01:37:13 -08:00
// Or, if info.Type is not a pointer, register the pointer.
2014-12-29 15:14:54 -08:00
var rt, ptrRt reflect.Type
if info.Type.Kind() == reflect.Ptr {
2014-12-29 15:14:54 -08:00
rt, ptrRt = info.Type.Elem(), info.Type
2014-12-17 01:37:13 -08:00
} else {
2014-12-29 15:14:54 -08:00
rt, ptrRt = info.Type, reflect.PtrTo(info.Type)
2014-12-17 01:37:13 -08:00
}
2014-12-29 15:14:54 -08:00
// Register the type info
typeInfos[rt] = info
typeInfos[ptrRt] = info
2014-12-17 01:37:13 -08:00
// See if the type implements HasTypeByte
2014-12-29 15:14:54 -08:00
if rt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) {
zero := reflect.Zero(rt)
typeByte := zero.Interface().(HasTypeByte).TypeByte()
if info.HasTypeByte && info.TypeByte != typeByte {
panic(fmt.Sprintf("Type %v expected TypeByte of %X", rt, typeByte))
} else {
info.HasTypeByte = true
info.TypeByte = typeByte
}
} else if ptrRt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) {
zero := reflect.Zero(ptrRt)
2014-12-17 01:37:13 -08:00
typeByte := zero.Interface().(HasTypeByte).TypeByte()
if info.HasTypeByte && info.TypeByte != typeByte {
2014-12-29 15:14:54 -08:00
panic(fmt.Sprintf("Type %v expected TypeByte of %X", ptrRt, typeByte))
} else {
info.HasTypeByte = true
info.TypeByte = typeByte
2014-12-17 01:37:13 -08:00
}
}
2014-12-17 01:37:13 -08:00
return info
}
2014-12-29 15:14:54 -08:00
func readReflect(rv reflect.Value, rt reflect.Type, r Unreader, n *int64, err *error) {
2014-12-29 19:41:46 -08:00
log.Debug("Read reflect", "type", rt)
// First, create a new struct if rv is nil pointer.
if rt.Kind() == reflect.Ptr && rv.IsNil() {
newRv := reflect.New(rt.Elem())
rv.Set(newRv)
rv = newRv
}
// Dereference pointer
// Still addressable, thus settable!
if rv.Kind() == reflect.Ptr {
rv, rt = rv.Elem(), rt.Elem()
}
2014-12-17 01:37:13 -08:00
// Get typeInfo
2014-12-28 17:10:03 -08:00
typeInfo := GetTypeInfo(rt)
2014-12-17 01:37:13 -08:00
// Custom decoder
if typeInfo.Decoder != nil {
decoded := typeInfo.Decoder(r, n, err)
decodedRv := reflect.Indirect(reflect.ValueOf(decoded))
rv.Set(decodedRv)
return
}
2014-12-17 01:37:13 -08:00
// Read TypeByte prefix
if typeInfo.HasTypeByte {
typeByte := ReadByte(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug("Read typebyte", "typeByte", typeByte)
2014-12-17 01:37:13 -08:00
if typeByte != typeInfo.TypeByte {
*err = errors.New(fmt.Sprintf("Expected TypeByte of %X but got %X", typeInfo.TypeByte, typeByte))
return
}
}
switch rt.Kind() {
case reflect.Slice:
elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 {
// Special case: Byteslices
byteslice := ReadByteSlice(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug("Read byteslice", "bytes", byteslice)
rv.Set(reflect.ValueOf(byteslice))
} else {
// Read length
length := int(ReadUvarint(r, n, err))
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read length: %v", length))
sliceRv := reflect.MakeSlice(rt, length, length)
// Read elems
for i := 0; i < length; i++ {
elemRv := sliceRv.Index(i)
readReflect(elemRv, elemRt, r, n, err)
}
rv.Set(sliceRv)
}
case reflect.Struct:
numFields := rt.NumField()
for i := 0; i < numFields; i++ {
field := rt.Field(i)
2014-12-17 01:37:13 -08:00
if field.PkgPath != "" {
continue
}
fieldRv := rv.Field(i)
readReflect(fieldRv, field.Type, r, n, err)
}
case reflect.String:
str := ReadString(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read string: %v", str))
rv.SetString(str)
2014-12-17 01:37:13 -08:00
case reflect.Int64:
num := ReadUint64(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
2014-12-17 01:37:13 -08:00
rv.SetInt(int64(num))
case reflect.Int32:
num := ReadUint32(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
2014-12-17 01:37:13 -08:00
rv.SetInt(int64(num))
case reflect.Int16:
num := ReadUint16(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
2014-12-17 01:37:13 -08:00
rv.SetInt(int64(num))
case reflect.Int8:
num := ReadUint8(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
2014-12-17 01:37:13 -08:00
rv.SetInt(int64(num))
case reflect.Int:
num := ReadUvarint(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
2014-12-17 01:37:13 -08:00
rv.SetInt(int64(num))
case reflect.Uint64:
num := ReadUint64(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
rv.SetUint(uint64(num))
case reflect.Uint32:
num := ReadUint32(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
rv.SetUint(uint64(num))
case reflect.Uint16:
num := ReadUint16(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
rv.SetUint(uint64(num))
case reflect.Uint8:
num := ReadUint8(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
rv.SetUint(uint64(num))
case reflect.Uint:
num := ReadUvarint(r, n, err)
2014-12-29 18:09:06 -08:00
log.Debug(Fmt("Read num: %v", num))
rv.SetUint(uint64(num))
default:
panic(fmt.Sprintf("Unknown field type %v", rt.Kind()))
}
}
func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err *error) {
2014-12-17 01:37:13 -08:00
// Get typeInfo
2014-12-28 17:10:03 -08:00
typeInfo := GetTypeInfo(rt)
2014-12-17 01:37:13 -08:00
// Custom encoder, say for an interface type rt.
if typeInfo.Encoder != nil {
typeInfo.Encoder(rv.Interface(), w, n, err)
return
}
2014-12-28 16:26:53 -08:00
// Dereference interface
if rt.Kind() == reflect.Interface {
rv = rv.Elem()
rt = rv.Type()
2014-12-17 01:37:13 -08:00
// If interface type, get typeInfo of underlying type.
2014-12-28 17:10:03 -08:00
typeInfo = GetTypeInfo(rt)
}
2014-12-28 16:26:53 -08:00
// Dereference pointer
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
rv = rv.Elem()
// RegisterType registers the ptr type,
// so typeInfo is already for the ptr.
}
// Write TypeByte prefix
2014-12-17 01:37:13 -08:00
if typeInfo.HasTypeByte {
WriteByte(typeInfo.TypeByte, w, n, err)
}
switch rt.Kind() {
case reflect.Slice:
elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 {
// Special case: Byteslices
2014-12-28 16:26:53 -08:00
byteslice := rv.Bytes()
WriteByteSlice(byteslice, w, n, err)
} else {
// Write length
length := rv.Len()
WriteUvarint(uint(length), w, n, err)
// Write elems
for i := 0; i < length; i++ {
elemRv := rv.Index(i)
writeReflect(elemRv, elemRt, w, n, err)
}
}
case reflect.Struct:
numFields := rt.NumField()
for i := 0; i < numFields; i++ {
field := rt.Field(i)
2014-12-17 01:37:13 -08:00
if field.PkgPath != "" {
continue
}
fieldRv := rv.Field(i)
writeReflect(fieldRv, field.Type, w, n, err)
}
case reflect.String:
WriteString(rv.String(), w, n, err)
2014-12-17 01:37:13 -08:00
case reflect.Int64:
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)
2014-12-17 01:37:13 -08:00
case reflect.Uint64:
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)
default:
panic(fmt.Sprintf("Unknown field type %v", rt.Kind()))
}
}