]> Cypherpunks repositories - gostls13.git/commitdiff
gob: use new Implements and AssignableTo methods in reflect
authorRob Pike <r@golang.org>
Wed, 20 Apr 2011 21:07:13 +0000 (14:07 -0700)
committerRob Pike <r@golang.org>
Wed, 20 Apr 2011 21:07:13 +0000 (14:07 -0700)
to improve the code and removea  TODO.

R=rsc
CC=golang-dev
https://golang.org/cl/4443054

src/pkg/gob/decode.go
src/pkg/gob/type.go

index b6d7cbea81b3c6e20d2186be8ea6d4c2566f17d8..531285e40d70da7853f6f686bafb02ef6353ade2 100644 (file)
@@ -667,18 +667,12 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
        dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
 }
 
-// setInterfaceValue sets an interface value to a concrete value through
-// reflection.  If the concrete value does not implement the interface, the
-// 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.
+// setInterfaceValue sets an interface value to a concrete value,
+// but first it checks that the assignment will succeed.
 func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
-       defer func() {
-               if e := recover(); e != nil {
-                       error(e.(os.Error))
-               }
-       }()
+       if !value.Type().AssignableTo(ivalue.Type()) {
+               errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type())
+       }
        ivalue.Set(value)
 }
 
index 8fd174841bfa269157837b794a078f7424f09c59..c337e40e853e7e675973804774874dada1a0a475 100644 (file)
@@ -74,8 +74,8 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
                }
                ut.indir++
        }
-       ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderCheck)
-       ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderCheck)
+       ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderInterfaceType)
+       ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderInterfaceType)
        userTypeCache[rt] = ut
        return
 }
@@ -85,32 +85,16 @@ const (
        gobDecodeMethodName = "GobDecode"
 )
 
-// implements returns whether the type implements the interface, as encoded
-// in the check function.
-func implements(typ reflect.Type, check func(typ reflect.Type) bool) bool {
-       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
-}
+var (
+       gobEncoderInterfaceType = reflect.Typeof(new(GobEncoder)).Elem()
+       gobDecoderInterfaceType = reflect.Typeof(new(GobDecoder)).Elem()
+)
 
 // 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
 // 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 {
                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
        // dereferencing to the base type until we find an implementation.
        for {
-               if implements(rt, check) {
+               if rt.Implements(gobEncDecType) {
                        return true, indir
                }
                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.
        if typ.Kind() != reflect.Ptr {
                // Not a pointer, but does the pointer work?
-               if implements(reflect.PtrTo(typ), check) {
+               if reflect.PtrTo(typ).Implements(gobEncDecType) {
                        return true, -1
                }
        }