1
0
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:
Rob Pike 2011-04-20 14:07:13 -07:00
parent 8dad7fec1d
commit 220f83134a
2 changed files with 15 additions and 37 deletions

View File

@ -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)
} }

View File

@ -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
} }
} }