mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-23 09:41:38 +00:00
Support nil pointers for Binary.
If the thing does not already have a typebyte declared, a fake one will be given (0x01). A TypeByte of 0x00 is reserved for nil things. No nil-dogs.
This commit is contained in:
@ -15,13 +15,10 @@ import (
|
||||
type TypeInfo struct {
|
||||
Type reflect.Type // The type
|
||||
|
||||
// Custom encoder/decoder
|
||||
// NOTE: Not used.
|
||||
BinaryEncoder Encoder
|
||||
BinaryDecoder Decoder
|
||||
|
||||
// If Type is kind reflect.Interface
|
||||
ConcreteTypes map[byte]reflect.Type
|
||||
// If Type is kind reflect.Interface, is registered
|
||||
IsRegisteredInterface bool
|
||||
ConcreteTypes map[byte]reflect.Type
|
||||
ConcreteTypeBytes map[reflect.Type]byte
|
||||
|
||||
// If Type is concrete
|
||||
HasTypeByte bool
|
||||
@ -104,6 +101,7 @@ func RegisterInterface(o interface{}, args ...interface{}) *TypeInfo {
|
||||
panic("RegisterInterface expects an interface")
|
||||
}
|
||||
concreteTypes := make(map[byte]reflect.Type, 0)
|
||||
concreteTypesReversed := make(map[reflect.Type]byte, 0)
|
||||
for _, arg := range args {
|
||||
switch arg.(type) {
|
||||
case ConcreteType:
|
||||
@ -114,17 +112,23 @@ func RegisterInterface(o interface{}, args ...interface{}) *TypeInfo {
|
||||
if !hasTypeByte {
|
||||
panic(Fmt("Expected concrete type %v to implement HasTypeByte", concreteType))
|
||||
}
|
||||
if typeByte == 0x00 {
|
||||
panic(Fmt("TypeByte of 0x00 is reserved for nil (%v)", concreteType))
|
||||
}
|
||||
if concreteTypes[typeByte] != nil {
|
||||
panic(Fmt("Duplicate TypeByte for type %v and %v", concreteType, concreteTypes[typeByte]))
|
||||
}
|
||||
concreteTypes[typeByte] = concreteType
|
||||
concreteTypesReversed[concreteType] = typeByte
|
||||
default:
|
||||
panic(Fmt("Unexpected argument type %v", reflect.TypeOf(arg)))
|
||||
}
|
||||
}
|
||||
typeInfo := &TypeInfo{
|
||||
Type: it,
|
||||
ConcreteTypes: concreteTypes,
|
||||
Type: it,
|
||||
IsRegisteredInterface: true,
|
||||
ConcreteTypes: concreteTypes,
|
||||
ConcreteTypeBytes: concreteTypesReversed,
|
||||
}
|
||||
typeInfos[it] = typeInfo
|
||||
return typeInfo
|
||||
@ -148,7 +152,8 @@ func RegisterType(info *TypeInfo) *TypeInfo {
|
||||
typeInfos[ptrRt] = info
|
||||
|
||||
// See if the type implements HasTypeByte
|
||||
if rt.Kind() != reflect.Interface && rt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) {
|
||||
if rt.Kind() != reflect.Interface &&
|
||||
rt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) {
|
||||
zero := reflect.Zero(rt)
|
||||
typeByte := zero.Interface().(HasTypeByte).TypeByte()
|
||||
if info.HasTypeByte && info.TypeByte != typeByte {
|
||||
@ -197,35 +202,60 @@ func RegisterType(info *TypeInfo) *TypeInfo {
|
||||
|
||||
func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *error) {
|
||||
|
||||
log.Debug("Read reflect", "type", rt)
|
||||
|
||||
// Get typeInfo
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
|
||||
// Custom decoder
|
||||
if typeInfo.BinaryDecoder != nil {
|
||||
decoded := typeInfo.BinaryDecoder(r, n, err)
|
||||
rv.Set(reflect.ValueOf(decoded))
|
||||
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.ConcreteTypes[typeByte]
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("Unexpected type byte %X for type %v", typeByte, crt))
|
||||
return
|
||||
}
|
||||
crv := reflect.New(crt).Elem()
|
||||
r = NewPrefixedReader([]byte{typeByte}, r)
|
||||
readReflect(crv, crt, r, n, err)
|
||||
rv.Set(crv) // NOTE: orig rv is ignored.
|
||||
return
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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.HasTypeByte {
|
||||
r = NewPrefixedReader([]byte{typeByte}, r)
|
||||
}
|
||||
// continue...
|
||||
}
|
||||
|
||||
// Read TypeByte prefix
|
||||
if typeInfo.HasTypeByte {
|
||||
typeByte := ReadByte(r, n, err)
|
||||
log.Debug("Read typebyte", "typeByte", typeByte)
|
||||
if typeByte != typeInfo.TypeByte {
|
||||
*err = errors.New(Fmt("Expected TypeByte of %X but got %X", typeInfo.TypeByte, typeByte))
|
||||
return
|
||||
@ -233,19 +263,6 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *
|
||||
}
|
||||
|
||||
switch rt.Kind() {
|
||||
case reflect.Interface:
|
||||
typeByte := ReadByte(r, n, err)
|
||||
if *err != nil {
|
||||
return
|
||||
}
|
||||
concreteType, ok := typeInfo.ConcreteTypes[typeByte]
|
||||
if !ok {
|
||||
panic(Fmt("TypeByte %X not registered for interface %v", typeByte, rt))
|
||||
}
|
||||
newRv := reflect.New(concreteType)
|
||||
readReflect(newRv.Elem(), concreteType, NewPrefixedReader([]byte{typeByte}, r), n, err)
|
||||
rv.Set(newRv.Elem())
|
||||
|
||||
case reflect.Slice:
|
||||
elemRt := rt.Elem()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
@ -349,36 +366,66 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *
|
||||
}
|
||||
}
|
||||
|
||||
// rv: the reflection value of the thing to write
|
||||
// rt: the type of rv as declared in the container, not necessarily rv.Type().
|
||||
func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err *error) {
|
||||
|
||||
// Get typeInfo
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
|
||||
// Custom encoder, say for an interface type rt.
|
||||
if typeInfo.BinaryEncoder != nil {
|
||||
typeInfo.BinaryEncoder(rv.Interface(), w, n, err)
|
||||
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.ConcreteTypeBytes[crt]
|
||||
if !ok {
|
||||
switch crt.Kind() {
|
||||
case reflect.Ptr:
|
||||
*err = errors.New(Fmt("Unexpected pointer type %v. Was it registered as a value receiver rather than as a pointer receiver?", crt))
|
||||
case reflect.Struct:
|
||||
*err = errors.New(Fmt("Unexpected struct type %v. Was it registered as a pointer receiver rather than as a value receiver?", crt))
|
||||
default:
|
||||
*err = errors.New(Fmt("Unexpected type %v.", crt))
|
||||
}
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// We support writing unsafely for convenience.
|
||||
}
|
||||
// We don't have to write the typeByte here,
|
||||
// the writeReflect() call below will write it.
|
||||
writeReflect(crv, crt, w, n, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Dereference interface
|
||||
if rt.Kind() == reflect.Interface {
|
||||
rv = rv.Elem()
|
||||
rt = rv.Type()
|
||||
// If interface type, get typeInfo of underlying type.
|
||||
typeInfo = GetTypeInfo(rt)
|
||||
}
|
||||
|
||||
// Dereference pointer
|
||||
if rt.Kind() == reflect.Ptr {
|
||||
rt = rt.Elem()
|
||||
rv = rv.Elem()
|
||||
// Dereference pointer
|
||||
rv, rt = rv.Elem(), rt.Elem()
|
||||
if !rv.IsValid() {
|
||||
WriteByte(0x00, w, n, err)
|
||||
return
|
||||
}
|
||||
if !typeInfo.HasTypeByte {
|
||||
WriteByte(0x01, w, n, err)
|
||||
// continue...
|
||||
} else {
|
||||
// continue...
|
||||
}
|
||||
}
|
||||
|
||||
// Write TypeByte prefix
|
||||
// Write type byte
|
||||
if typeInfo.HasTypeByte {
|
||||
WriteByte(typeInfo.TypeByte, w, n, err)
|
||||
}
|
||||
|
||||
// All other types
|
||||
switch rt.Kind() {
|
||||
case reflect.Slice:
|
||||
elemRt := rt.Elem()
|
||||
@ -478,22 +525,47 @@ func readTypeByteJSON(o interface{}) (typeByte byte, rest interface{}, err error
|
||||
|
||||
func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *error) {
|
||||
|
||||
log.Debug("Read reflect json", "type", rt)
|
||||
|
||||
// Get typeInfo
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
|
||||
// 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
|
||||
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_ := readTypeByteJSON(o)
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
crt, ok := typeInfo.ConcreteTypes[typeByte]
|
||||
if !ok {
|
||||
*err = errors.New(Fmt("TypeByte %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
|
||||
}
|
||||
|
||||
// Dereference pointer
|
||||
// Still addressable, thus settable!
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
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()
|
||||
// continue...
|
||||
}
|
||||
|
||||
// Read TypeByte prefix
|
||||
@ -511,20 +583,6 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro
|
||||
}
|
||||
|
||||
switch rt.Kind() {
|
||||
case reflect.Interface:
|
||||
typeByte, _, err_ := readTypeByteJSON(o)
|
||||
if err_ != nil {
|
||||
*err = err_
|
||||
return
|
||||
}
|
||||
concreteType, ok := typeInfo.ConcreteTypes[typeByte]
|
||||
if !ok {
|
||||
panic(Fmt("TypeByte %X not registered for interface %v", typeByte, rt))
|
||||
}
|
||||
newRv := reflect.New(concreteType)
|
||||
readReflectJSON(newRv.Elem(), concreteType, o, err)
|
||||
rv.Set(newRv.Elem())
|
||||
|
||||
case reflect.Slice:
|
||||
elemRt := rt.Elem()
|
||||
if elemRt.Kind() == reflect.Uint8 {
|
||||
@ -643,25 +701,55 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64,
|
||||
// Get typeInfo
|
||||
typeInfo := GetTypeInfo(rt)
|
||||
|
||||
// Dereference interface
|
||||
if rt.Kind() == reflect.Interface {
|
||||
rv = rv.Elem()
|
||||
rt = rv.Type()
|
||||
// If interface type, get typeInfo of underlying type.
|
||||
typeInfo = GetTypeInfo(rt)
|
||||
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.ConcreteTypeBytes[crt]
|
||||
if !ok {
|
||||
switch crt.Kind() {
|
||||
case reflect.Ptr:
|
||||
*err = errors.New(Fmt("Unexpected pointer type %v. Was it registered as a value receiver rather than as a pointer receiver?", crt))
|
||||
case reflect.Struct:
|
||||
*err = errors.New(Fmt("Unexpected struct type %v. Was it registered as a pointer receiver rather than as a value receiver?", crt))
|
||||
default:
|
||||
*err = errors.New(Fmt("Unexpected type %v.", crt))
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// Dereference pointer
|
||||
if rt.Kind() == reflect.Ptr {
|
||||
rt = rt.Elem()
|
||||
rv = rv.Elem()
|
||||
// Dereference pointer
|
||||
rv, rt = rv.Elem(), rt.Elem()
|
||||
if !rv.IsValid() {
|
||||
WriteTo([]byte("null"), w, n, err)
|
||||
return
|
||||
}
|
||||
// continue...
|
||||
}
|
||||
|
||||
// Write TypeByte prefix
|
||||
// Write TypeByte
|
||||
if typeInfo.HasTypeByte {
|
||||
WriteTo([]byte(Fmt("[%v,", typeInfo.TypeByte)), w, n, err)
|
||||
defer WriteTo([]byte("]"), w, n, err)
|
||||
}
|
||||
|
||||
// All other types
|
||||
switch rt.Kind() {
|
||||
case reflect.Slice:
|
||||
elemRt := rt.Elem()
|
||||
@ -730,10 +818,4 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64,
|
||||
panic(Fmt("Unknown field type %v", rt.Kind()))
|
||||
}
|
||||
|
||||
// Write TypeByte close bracket
|
||||
if typeInfo.HasTypeByte {
|
||||
WriteTo([]byte("]"), w, n, err)
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user