mirror of
https://github.com/golang/go
synced 2024-11-21 23:44:39 -07:00
gob: use new Implements and AssignableTo methods in reflect
to improve the code and removea TODO. R=rsc CC=golang-dev https://golang.org/cl/4443054
This commit is contained in:
parent
8dad7fec1d
commit
220f83134a
@ -667,18 +667,12 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
|
|||||||
dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
|
dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// setInterfaceValue sets an interface value to a concrete value through
|
// setInterfaceValue sets an interface value to a concrete value,
|
||||||
// reflection. If the concrete value does not implement the interface, the
|
// but first it checks that the assignment will succeed.
|
||||||
// setting will panic. This routine turns the panic into an error return.
|
|
||||||
// This dance avoids manually checking that the value satisfies the
|
|
||||||
// interface.
|
|
||||||
// TODO(rsc): avoid panic+recover after fixing issue 327.
|
|
||||||
func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
|
func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
|
||||||
defer func() {
|
if !value.Type().AssignableTo(ivalue.Type()) {
|
||||||
if e := recover(); e != nil {
|
errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type())
|
||||||
error(e.(os.Error))
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
ivalue.Set(value)
|
ivalue.Set(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
|
|||||||
}
|
}
|
||||||
ut.indir++
|
ut.indir++
|
||||||
}
|
}
|
||||||
ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderCheck)
|
ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderInterfaceType)
|
||||||
ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderCheck)
|
ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderInterfaceType)
|
||||||
userTypeCache[rt] = ut
|
userTypeCache[rt] = ut
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -85,32 +85,16 @@ const (
|
|||||||
gobDecodeMethodName = "GobDecode"
|
gobDecodeMethodName = "GobDecode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// implements returns whether the type implements the interface, as encoded
|
var (
|
||||||
// in the check function.
|
gobEncoderInterfaceType = reflect.Typeof(new(GobEncoder)).Elem()
|
||||||
func implements(typ reflect.Type, check func(typ reflect.Type) bool) bool {
|
gobDecoderInterfaceType = reflect.Typeof(new(GobDecoder)).Elem()
|
||||||
if typ.NumMethod() == 0 { // avoid allocations etc. unless there's some chance
|
)
|
||||||
return false
|
|
||||||
}
|
|
||||||
return check(typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gobEncoderCheck makes the type assertion a boolean function.
|
|
||||||
func gobEncoderCheck(typ reflect.Type) bool {
|
|
||||||
_, ok := reflect.Zero(typ).Interface().(GobEncoder)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// gobDecoderCheck makes the type assertion a boolean function.
|
|
||||||
func gobDecoderCheck(typ reflect.Type) bool {
|
|
||||||
_, ok := reflect.Zero(typ).Interface().(GobDecoder)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// implementsInterface reports whether the type implements the
|
// implementsInterface reports whether the type implements the
|
||||||
// interface. (The actual check is done through the provided function.)
|
// gobEncoder/gobDecoder interface.
|
||||||
// It also returns the number of indirections required to get to the
|
// It also returns the number of indirections required to get to the
|
||||||
// implementation.
|
// implementation.
|
||||||
func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (success bool, indir int8) {
|
func implementsInterface(typ, gobEncDecType reflect.Type) (success bool, indir int8) {
|
||||||
if typ == nil {
|
if typ == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -118,7 +102,7 @@ func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (s
|
|||||||
// The type might be a pointer and we need to keep
|
// The type might be a pointer and we need to keep
|
||||||
// dereferencing to the base type until we find an implementation.
|
// dereferencing to the base type until we find an implementation.
|
||||||
for {
|
for {
|
||||||
if implements(rt, check) {
|
if rt.Implements(gobEncDecType) {
|
||||||
return true, indir
|
return true, indir
|
||||||
}
|
}
|
||||||
if p := rt; p.Kind() == reflect.Ptr {
|
if p := rt; p.Kind() == reflect.Ptr {
|
||||||
@ -134,7 +118,7 @@ func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (s
|
|||||||
// No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
|
// No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
|
||||||
if typ.Kind() != reflect.Ptr {
|
if typ.Kind() != reflect.Ptr {
|
||||||
// Not a pointer, but does the pointer work?
|
// Not a pointer, but does the pointer work?
|
||||||
if implements(reflect.PtrTo(typ), check) {
|
if reflect.PtrTo(typ).Implements(gobEncDecType) {
|
||||||
return true, -1
|
return true, -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user