mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
more gob bugs
1) need to send slice and array types (was only sending element types) 2) compatibleType needs to use decoder's type map R=rsc CC=golang-dev https://golang.org/cl/164062
This commit is contained in:
parent
749da968e4
commit
a0f742d343
4 changed files with 69 additions and 25 deletions
|
|
@ -527,7 +527,12 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
|
||||||
op = decUint8Array;
|
op = decUint8Array;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
elemId := wireId.gobType().(*sliceType).Elem;
|
var elemId typeId;
|
||||||
|
if tt, ok := builtinIdToType[wireId]; ok {
|
||||||
|
elemId = tt.(*sliceType).Elem
|
||||||
|
} else {
|
||||||
|
elemId = dec.wireType[wireId].slice.Elem
|
||||||
|
}
|
||||||
elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name);
|
elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
|
@ -614,7 +619,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) (decOp, os.Error) {
|
||||||
// Are these two gob Types compatible?
|
// Are these two gob Types compatible?
|
||||||
// Answers the question for basic types, arrays, and slices.
|
// Answers the question for basic types, arrays, and slices.
|
||||||
// Structs are considered ok; fields will be checked later.
|
// Structs are considered ok; fields will be checked later.
|
||||||
func compatibleType(fr reflect.Type, fw typeId) bool {
|
func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
|
||||||
for {
|
for {
|
||||||
if pt, ok := fr.(*reflect.PtrType); ok {
|
if pt, ok := fr.(*reflect.PtrType); ok {
|
||||||
fr = pt.Elem();
|
fr = pt.Elem();
|
||||||
|
|
@ -660,16 +665,22 @@ func compatibleType(fr reflect.Type, fw typeId) bool {
|
||||||
return fw == tString
|
return fw == tString
|
||||||
case *reflect.ArrayType:
|
case *reflect.ArrayType:
|
||||||
aw, ok := fw.gobType().(*arrayType);
|
aw, ok := fw.gobType().(*arrayType);
|
||||||
return ok && t.Len() == aw.Len && compatibleType(t.Elem(), aw.Elem);
|
return ok && t.Len() == aw.Len && dec.compatibleType(t.Elem(), aw.Elem);
|
||||||
case *reflect.SliceType:
|
case *reflect.SliceType:
|
||||||
// Is it an array of bytes?
|
// Is it an array of bytes?
|
||||||
et := t.Elem();
|
et := t.Elem();
|
||||||
if _, ok := et.(*reflect.Uint8Type); ok {
|
if _, ok := et.(*reflect.Uint8Type); ok {
|
||||||
return fw == tBytes
|
return fw == tBytes
|
||||||
}
|
}
|
||||||
sw, ok := fw.gobType().(*sliceType);
|
// Extract and compare element types.
|
||||||
|
var sw *sliceType;
|
||||||
|
if tt, ok := builtinIdToType[fw]; ok {
|
||||||
|
sw = tt.(*sliceType)
|
||||||
|
} else {
|
||||||
|
sw = dec.wireType[fw].slice
|
||||||
|
}
|
||||||
elem, _ := indirect(t.Elem());
|
elem, _ := indirect(t.Elem());
|
||||||
return ok && compatibleType(elem, sw.Elem);
|
return sw != nil && dec.compatibleType(elem, sw.Elem);
|
||||||
case *reflect.StructType:
|
case *reflect.StructType:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -687,7 +698,7 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng
|
||||||
if !ok1 || !ok2 {
|
if !ok1 || !ok2 {
|
||||||
return nil, errNotStruct
|
return nil, errNotStruct
|
||||||
}
|
}
|
||||||
wireStruct = w.s;
|
wireStruct = w.strct;
|
||||||
}
|
}
|
||||||
engine = new(decEngine);
|
engine = new(decEngine);
|
||||||
engine.instr = make([]decInstr, len(wireStruct.field));
|
engine.instr = make([]decInstr, len(wireStruct.field));
|
||||||
|
|
@ -706,7 +717,7 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng
|
||||||
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl};
|
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !compatibleType(localField.Type, wireField.id) {
|
if !dec.compatibleType(localField.Type, wireField.id) {
|
||||||
details := " (" + wireField.id.String() + " incompatible with " + localField.Type.String() + ") in type " + remoteId.Name();
|
details := " (" + wireField.id.String() + " incompatible with " + localField.Type.String() + ") in type " + remoteId.Name();
|
||||||
return nil, os.ErrorString("gob: wrong type for field " + wireField.name + details);
|
return nil, os.ErrorString("gob: wrong type for field " + wireField.name + details);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -244,17 +244,20 @@ func (enc *Encoder) sendType(origt reflect.Type) {
|
||||||
default:
|
default:
|
||||||
// Basic types do not need to be described.
|
// Basic types do not need to be described.
|
||||||
return
|
return
|
||||||
|
case reflect.ArrayOrSliceType:
|
||||||
|
// If it's []uint8, don't send; it's considered basic.
|
||||||
|
if _, ok := rt.Elem().(*reflect.Uint8Type); ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Otherwise we do send.
|
||||||
|
break;
|
||||||
|
// Struct types are not sent, only their element types.
|
||||||
case *reflect.StructType:
|
case *reflect.StructType:
|
||||||
// Structs do need to be described.
|
|
||||||
break
|
break
|
||||||
case *reflect.ChanType, *reflect.FuncType, *reflect.MapType, *reflect.InterfaceType:
|
case *reflect.ChanType, *reflect.FuncType, *reflect.MapType, *reflect.InterfaceType:
|
||||||
// Probably a bad field in a struct.
|
// Probably a bad field in a struct.
|
||||||
enc.badType(rt);
|
enc.badType(rt);
|
||||||
return;
|
return;
|
||||||
// Array and slice types are not sent, only their element types.
|
|
||||||
case reflect.ArrayOrSliceType:
|
|
||||||
enc.sendType(rt.Elem());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have we already sent this type? This time we ask about the base type.
|
// Have we already sent this type? This time we ask about the base type.
|
||||||
|
|
@ -282,9 +285,13 @@ func (enc *Encoder) sendType(origt reflect.Type) {
|
||||||
// Remember we've sent the top-level, possibly indirect type too.
|
// Remember we've sent the top-level, possibly indirect type too.
|
||||||
enc.sent[origt] = info.id;
|
enc.sent[origt] = info.id;
|
||||||
// Now send the inner types
|
// Now send the inner types
|
||||||
st := rt.(*reflect.StructType);
|
switch st := rt.(type) {
|
||||||
for i := 0; i < st.NumField(); i++ {
|
case *reflect.StructType:
|
||||||
enc.sendType(st.Field(i).Type)
|
for i := 0; i < st.NumField(); i++ {
|
||||||
|
enc.sendType(st.Field(i).Type)
|
||||||
|
}
|
||||||
|
case reflect.ArrayOrSliceType:
|
||||||
|
enc.sendType(st.Elem())
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -213,3 +213,15 @@ func TestTypeToPtrPtrPtrPtrType(t *testing.T) {
|
||||||
t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).a, ****t2.a)
|
t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).a, ****t2.a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSlice(t *testing.T) {
|
||||||
|
// Encode a *T, decode a T
|
||||||
|
type Type3 struct {
|
||||||
|
a []string;
|
||||||
|
}
|
||||||
|
t3p := &Type3{[]string{"hello", "world"}};
|
||||||
|
var t3 Type3;
|
||||||
|
if err := encAndDec(t3, t3p); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,13 +98,13 @@ var tBytes = bootstrapType("bytes", make([]byte, 0), 5)
|
||||||
var tString = bootstrapType("string", "", 6)
|
var tString = bootstrapType("string", "", 6)
|
||||||
|
|
||||||
// Predefined because it's needed by the Decoder
|
// Predefined because it's needed by the Decoder
|
||||||
var tWireType = getTypeInfoNoError(reflect.Typeof(wireType{})).id
|
var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
checkId(7, tWireType);
|
checkId(7, tWireType);
|
||||||
checkId(8, getTypeInfoNoError(reflect.Typeof(structType{})).id);
|
checkId(9, mustGetTypeInfo(reflect.Typeof(commonType{})).id);
|
||||||
checkId(9, getTypeInfoNoError(reflect.Typeof(commonType{})).id);
|
checkId(11, mustGetTypeInfo(reflect.Typeof(structType{})).id);
|
||||||
checkId(10, getTypeInfoNoError(reflect.Typeof(fieldType{})).id);
|
checkId(12, mustGetTypeInfo(reflect.Typeof(fieldType{})).id);
|
||||||
builtinIdToType = make(map[typeId]gobType);
|
builtinIdToType = make(map[typeId]gobType);
|
||||||
for k, v := range idToType {
|
for k, v := range idToType {
|
||||||
builtinIdToType[k] = v
|
builtinIdToType[k] = v
|
||||||
|
|
@ -346,12 +346,16 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
|
||||||
// are built in encode.go's init() function.
|
// are built in encode.go's init() function.
|
||||||
|
|
||||||
type wireType struct {
|
type wireType struct {
|
||||||
s *structType;
|
array *arrayType;
|
||||||
|
slice *sliceType;
|
||||||
|
strct *structType;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *wireType) name() string {
|
func (w *wireType) name() string {
|
||||||
// generalize once we can have non-struct types on the wire.
|
if w.strct != nil {
|
||||||
return w.s.name
|
return w.strct.name
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
type typeInfo struct {
|
type typeInfo struct {
|
||||||
|
|
@ -377,15 +381,25 @@ func getTypeInfo(rt reflect.Type) (*typeInfo, os.Error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
info.id = gt.id();
|
info.id = gt.id();
|
||||||
// assume it's a struct type
|
t := info.id.gobType();
|
||||||
info.wire = &wireType{info.id.gobType().(*structType)};
|
switch typ := rt.(type) {
|
||||||
|
case *reflect.ArrayType:
|
||||||
|
info.wire = &wireType{array: t.(*arrayType)}
|
||||||
|
case *reflect.SliceType:
|
||||||
|
// []byte == []uint8 is a special case handled separately
|
||||||
|
if _, ok := typ.Elem().(*reflect.Uint8Type); !ok {
|
||||||
|
info.wire = &wireType{slice: t.(*sliceType)}
|
||||||
|
}
|
||||||
|
case *reflect.StructType:
|
||||||
|
info.wire = &wireType{strct: t.(*structType)}
|
||||||
|
}
|
||||||
typeInfoMap[rt] = info;
|
typeInfoMap[rt] = info;
|
||||||
}
|
}
|
||||||
return info, nil;
|
return info, nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called only when a panic is acceptable and unexpected.
|
// Called only when a panic is acceptable and unexpected.
|
||||||
func getTypeInfoNoError(rt reflect.Type) *typeInfo {
|
func mustGetTypeInfo(rt reflect.Type) *typeInfo {
|
||||||
t, err := getTypeInfo(rt);
|
t, err := getTypeInfo(rt);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panicln("getTypeInfo:", err.String())
|
panicln("getTypeInfo:", err.String())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue