Index: src/pkg/encoding/gob/type.go |
=================================================================== |
--- a/src/pkg/encoding/gob/type.go |
+++ b/src/pkg/encoding/gob/type.go |
@@ -5,6 +5,7 @@ |
package gob |
import ( |
+ "encoding" |
"errors" |
"fmt" |
"os" |
@@ -18,15 +19,22 @@ |
// to the package. It's computed once and stored in a map keyed by reflection |
// type. |
type userTypeInfo struct { |
- user reflect.Type // the type the user handed us |
- base reflect.Type // the base type after all indirections |
- indir int // number of indirections to reach the base type |
- isGobEncoder bool // does the type implement GobEncoder? |
- isGobDecoder bool // does the type implement GobDecoder? |
- encIndir int8 // number of indirections to reach the receiver type; may be negative |
- decIndir int8 // number of indirections to reach the receiver type; may be negative |
+ user reflect.Type // the type the user handed us |
+ base reflect.Type // the base type after all indirections |
+ indir int // number of indirections to reach the base type |
+ externalEnc int // xGob, xBinary, or xText |
+ externalDec int // xGob, xBinary or xText |
+ encIndir int8 // number of indirections to reach the receiver type; may be negative |
+ decIndir int8 // number of indirections to reach the receiver type; may be negative |
} |
+// externalEncoding bits |
+const ( |
+ xGob = 1 + iota // GobEncoder or GobDecoder |
+ xBinary // encoding.BinaryMarshaler or encoding.BinaryUnmarshaler |
+ xText // encoding.TextMarshaler or encoding.TextUnmarshaler |
+) |
+ |
var ( |
// Protected by an RWMutex because we read it a lot and write |
// it only when we see a new type, typically when compiling. |
@@ -75,15 +83,34 @@ |
} |
ut.indir++ |
} |
- ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderInterfaceType) |
- ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderInterfaceType) |
+ |
+ if ok, indir := implementsInterface(ut.user, gobEncoderInterfaceType); ok { |
+ ut.externalEnc, ut.encIndir = xGob, indir |
+ } else if ok, indir := implementsInterface(ut.user, binaryMarshalerInterfaceType); ok { |
+ ut.externalEnc, ut.encIndir = xBinary, indir |
+ } else if ok, indir := implementsInterface(ut.user, textMarshalerInterfaceType); ok { |
+ ut.externalEnc, ut.encIndir = xText, indir |
+ } |
+ |
+ if ok, indir := implementsInterface(ut.user, gobDecoderInterfaceType); ok { |
+ ut.externalDec, ut.decIndir = xGob, indir |
+ } else if ok, indir := implementsInterface(ut.user, binaryUnmarshalerInterfaceType); ok { |
+ ut.externalDec, ut.decIndir = xBinary, indir |
+ } else if ok, indir := implementsInterface(ut.user, textUnmarshalerInterfaceType); ok { |
+ ut.externalDec, ut.decIndir = xText, indir |
+ } |
+ |
userTypeCache[rt] = ut |
return |
} |
var ( |
- gobEncoderInterfaceType = reflect.TypeOf((*GobEncoder)(nil)).Elem() |
- gobDecoderInterfaceType = reflect.TypeOf((*GobDecoder)(nil)).Elem() |
+ gobEncoderInterfaceType = reflect.TypeOf((*GobEncoder)(nil)).Elem() |
+ gobDecoderInterfaceType = reflect.TypeOf((*GobDecoder)(nil)).Elem() |
+ binaryMarshalerInterfaceType = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem() |
+ binaryUnmarshalerInterfaceType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem() |
+ textMarshalerInterfaceType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() |
+ textUnmarshalerInterfaceType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() |
) |
// implementsInterface reports whether the type implements the |
@@ -412,7 +439,7 @@ |
// works through typeIds and userTypeInfos alone. |
func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) { |
// Does this type implement GobEncoder? |
- if ut.isGobEncoder { |
+ if ut.externalEnc != 0 { |
return newGobEncoderType(name), nil |
} |
var err error |
@@ -593,11 +620,13 @@ |
// To maintain binary compatibility, if you extend this type, always put |
// the new fields last. |
type wireType struct { |
- ArrayT *arrayType |
- SliceT *sliceType |
- StructT *structType |
- MapT *mapType |
- GobEncoderT *gobEncoderType |
+ ArrayT *arrayType |
+ SliceT *sliceType |
+ StructT *structType |
+ MapT *mapType |
+ GobEncoderT *gobEncoderType |
+ BinaryMarshalerT *gobEncoderType |
+ TextMarshalerT *gobEncoderType |
} |
func (w *wireType) string() string { |
@@ -616,6 +645,10 @@ |
return w.MapT.Name |
case w.GobEncoderT != nil: |
return w.GobEncoderT.Name |
+ case w.BinaryMarshalerT != nil: |
+ return w.BinaryMarshalerT.Name |
+ case w.TextMarshalerT != nil: |
+ return w.TextMarshalerT.Name |
} |
return unknown |
} |
@@ -631,7 +664,7 @@ |
// typeLock must be held. |
func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) { |
rt := ut.base |
- if ut.isGobEncoder { |
+ if ut.externalEnc != 0 { |
// We want the user type, not the base type. |
rt = ut.user |
} |
@@ -646,12 +679,20 @@ |
} |
info.id = gt.id() |
- if ut.isGobEncoder { |
+ if ut.externalEnc != 0 { |
userType, err := getType(rt.Name(), ut, rt) |
if err != nil { |
return nil, err |
} |
- info.wire = &wireType{GobEncoderT: userType.id().gobType().(*gobEncoderType)} |
+ gt := userType.id().gobType().(*gobEncoderType) |
+ switch ut.externalEnc { |
+ case xGob: |
+ info.wire = &wireType{GobEncoderT: gt} |
+ case xBinary: |
+ info.wire = &wireType{BinaryMarshalerT: gt} |
+ case xText: |
+ info.wire = &wireType{TextMarshalerT: gt} |
+ } |
typeInfoMap[ut.user] = info |
return info, nil |
} |