mirror of
https://github.com/golang/go
synced 2024-11-20 05:54:43 -07:00
clean up the code, flow errors out to decoder.
R=rsc DELTA=99 (32 added, 22 deleted, 45 changed) OCL=31759 CL=31759
This commit is contained in:
parent
1737157189
commit
be2cf952a8
@ -17,6 +17,11 @@ import (
|
|||||||
"unsafe";
|
"unsafe";
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrRange = os.ErrorString("gob: internal error: field numbers out of bounds");
|
||||||
|
ErrNotStruct = os.ErrorString("gob: TODO: can only handle structs")
|
||||||
|
)
|
||||||
|
|
||||||
// The global execution state of an instance of the decoder.
|
// The global execution state of an instance of the decoder.
|
||||||
type decodeState struct {
|
type decodeState struct {
|
||||||
b *bytes.Buffer;
|
b *bytes.Buffer;
|
||||||
@ -342,7 +347,8 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer,
|
|||||||
}
|
}
|
||||||
fieldnum := state.fieldnum + delta;
|
fieldnum := state.fieldnum + delta;
|
||||||
if fieldnum >= len(engine.instr) {
|
if fieldnum >= len(engine.instr) {
|
||||||
panicln("TODO(r): field number out of range", fieldnum, len(engine.instr));
|
state.err = ErrRange;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
instr := &engine.instr[fieldnum];
|
instr := &engine.instr[fieldnum];
|
||||||
p := unsafe.Pointer(basep+instr.offset);
|
p := unsafe.Pointer(basep+instr.offset);
|
||||||
@ -452,11 +458,11 @@ var decIgnoreOpMap = map[TypeId] decOp {
|
|||||||
tString: ignoreUint8Array,
|
tString: ignoreUint8Array,
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDecEnginePtr(wireId TypeId, rt reflect.Type) **decEngine
|
func getDecEnginePtr(wireId TypeId, rt reflect.Type) (enginePtr **decEngine, err os.Error)
|
||||||
|
|
||||||
// Return the decoding op for the base type under rt and
|
// Return the decoding op for the base type under rt and
|
||||||
// the indirection count to reach it.
|
// the indirection count to reach it.
|
||||||
func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int) {
|
func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int, os.Error) {
|
||||||
typ, indir := indirect(rt);
|
typ, indir := indirect(rt);
|
||||||
op, ok := decOpMap[reflect.Typeof(typ)];
|
op, ok := decOpMap[reflect.Typeof(typ)];
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -468,21 +474,30 @@ func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
elemId := wireId.gobType().(*sliceType).Elem;
|
elemId := wireId.gobType().(*sliceType).Elem;
|
||||||
elemOp, elemIndir := decOpFor(elemId, t.Elem());
|
elemOp, elemIndir, err := decOpFor(elemId, t.Elem());
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
||||||
state.err = decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir);
|
state.err = decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir);
|
||||||
};
|
};
|
||||||
|
|
||||||
case *reflect.ArrayType:
|
case *reflect.ArrayType:
|
||||||
elemId := wireId.gobType().(*arrayType).Elem;
|
elemId := wireId.gobType().(*arrayType).Elem;
|
||||||
elemOp, elemIndir := decOpFor(elemId, t.Elem());
|
elemOp, elemIndir, err := decOpFor(elemId, t.Elem());
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
||||||
state.err = decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir);
|
state.err = decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir);
|
||||||
};
|
};
|
||||||
|
|
||||||
case *reflect.StructType:
|
case *reflect.StructType:
|
||||||
// Generate a closure that calls out to the engine for the nested type.
|
// Generate a closure that calls out to the engine for the nested type.
|
||||||
enginePtr := getDecEnginePtr(wireId, typ);
|
enginePtr, err := getDecEnginePtr(wireId, typ);
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
||||||
// indirect through info to delay evaluation for recursive structs
|
// indirect through info to delay evaluation for recursive structs
|
||||||
state.err = decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
|
state.err = decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
|
||||||
@ -490,27 +505,33 @@ func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if op == nil {
|
if op == nil {
|
||||||
panicln("decode can't handle type", rt.String());
|
return nil, 0, os.ErrorString("gob: decode can't handle type " + rt.String());
|
||||||
}
|
}
|
||||||
return op, indir
|
return op, indir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the decoding op for a field that has no destination.
|
// Return the decoding op for a field that has no destination.
|
||||||
func decIgnoreOpFor(wireId TypeId) decOp {
|
func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
|
||||||
op, ok := decIgnoreOpMap[wireId];
|
op, ok := decIgnoreOpMap[wireId];
|
||||||
if !ok {
|
if !ok {
|
||||||
// Special cases
|
// Special cases
|
||||||
switch t := wireId.gobType().(type) {
|
switch t := wireId.gobType().(type) {
|
||||||
case *sliceType:
|
case *sliceType:
|
||||||
elemId := wireId.gobType().(*sliceType).Elem;
|
elemId := wireId.gobType().(*sliceType).Elem;
|
||||||
elemOp := decIgnoreOpFor(elemId);
|
elemOp, err := decIgnoreOpFor(elemId);
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
||||||
state.err = ignoreSlice(state, elemOp);
|
state.err = ignoreSlice(state, elemOp);
|
||||||
};
|
};
|
||||||
|
|
||||||
case *arrayType:
|
case *arrayType:
|
||||||
elemId := wireId.gobType().(*arrayType).Elem;
|
elemId := wireId.gobType().(*arrayType).Elem;
|
||||||
elemOp := decIgnoreOpFor(elemId);
|
elemOp, err := decIgnoreOpFor(elemId);
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
|
||||||
state.err = ignoreArray(state, elemOp, t.Len);
|
state.err = ignoreArray(state, elemOp, t.Len);
|
||||||
};
|
};
|
||||||
@ -520,9 +541,9 @@ func decIgnoreOpFor(wireId TypeId) decOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if op == nil {
|
if op == nil {
|
||||||
panicln("decode can't handle type", wireId.gobType().String());
|
return nil, os.ErrorString("ignore can't handle type " + wireId.String());
|
||||||
}
|
}
|
||||||
return op;
|
return op, nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are these two gob Types compatible?
|
// Are these two gob Types compatible?
|
||||||
@ -588,48 +609,46 @@ func compatibleType(fr reflect.Type, fw TypeId) bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileDec(wireId TypeId, rt reflect.Type) *decEngine {
|
func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error) {
|
||||||
srt, ok1 := rt.(*reflect.StructType);
|
srt, ok1 := rt.(*reflect.StructType);
|
||||||
wireStruct, ok2 := wireId.gobType().(*structType);
|
wireStruct, ok2 := wireId.gobType().(*structType);
|
||||||
if !ok1 || !ok2 {
|
if !ok1 || !ok2 {
|
||||||
panicln("gob: TODO: can't handle non-structs");
|
return nil, ErrNotStruct
|
||||||
}
|
}
|
||||||
engine := new(decEngine);
|
engine = new(decEngine);
|
||||||
engine.instr = make([]decInstr, len(wireStruct.field));
|
engine.instr = make([]decInstr, len(wireStruct.field));
|
||||||
// Loop over the fields of the wire type.
|
// Loop over the fields of the wire type.
|
||||||
for fieldnum := 0; fieldnum < len(wireStruct.field); fieldnum++ {
|
for fieldnum := 0; fieldnum < len(wireStruct.field); fieldnum++ {
|
||||||
wireField := wireStruct.field[fieldnum];
|
wireField := wireStruct.field[fieldnum];
|
||||||
// Find the field of the local type with the same name.
|
// Find the field of the local type with the same name.
|
||||||
// TODO: put this as a method in reflect
|
localField, present := srt.FieldByName(wireField.name);
|
||||||
var localField reflect.StructField;
|
|
||||||
for lfn := 0; lfn < srt.NumField(); lfn++ {
|
|
||||||
if srt.Field(lfn).Name == wireField.name {
|
|
||||||
localField = srt.Field(lfn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO(r): anonymous names
|
// TODO(r): anonymous names
|
||||||
if localField.Anonymous || localField.Name == "" {
|
if !present || localField.Anonymous {
|
||||||
println("no matching field", wireField.name, "in type", wireId.String());
|
println("no matching field", wireField.name, "in type", wireId.String());
|
||||||
op := decIgnoreOpFor(wireField.typeId);
|
op, err := decIgnoreOpFor(wireField.typeId);
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0};
|
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !compatibleType(localField.Type, wireField.typeId) {
|
if !compatibleType(localField.Type, wireField.typeId) {
|
||||||
panicln("TODO: wrong type for field", wireField.name, "in type", wireId.String());
|
return nil, os.ErrorString("gob: TODO: wrong type for field " + wireField.name + " in type " + wireId.String());
|
||||||
|
}
|
||||||
|
op, indir, err := decOpFor(wireField.typeId, localField.Type);
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
op, indir := decOpFor(wireField.typeId, localField.Type);
|
|
||||||
engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset)};
|
engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset)};
|
||||||
engine.numInstr++;
|
engine.numInstr++;
|
||||||
}
|
}
|
||||||
return engine;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// typeLock must be held.
|
// typeLock must be held.
|
||||||
func getDecEnginePtr(wireId TypeId, rt reflect.Type) **decEngine {
|
func getDecEnginePtr(wireId TypeId, rt reflect.Type) (enginePtr **decEngine, err os.Error) {
|
||||||
info := getTypeInfo(rt); // TODO: eliminate this; creates a gobType you don't need.
|
info := getTypeInfo(rt); // TODO: eliminate this; creates a gobType you don't need.
|
||||||
var enginePtr **decEngine;
|
|
||||||
var ok bool;
|
var ok bool;
|
||||||
if enginePtr, ok = info.decoderPtr[wireId]; !ok {
|
if enginePtr, ok = info.decoderPtr[wireId]; !ok {
|
||||||
if info.typeId.gobType() == nil {
|
if info.typeId.gobType() == nil {
|
||||||
@ -639,9 +658,12 @@ func getDecEnginePtr(wireId TypeId, rt reflect.Type) **decEngine {
|
|||||||
// mark this engine as underway before compiling to handle recursive types.
|
// mark this engine as underway before compiling to handle recursive types.
|
||||||
enginePtr = new(*decEngine);
|
enginePtr = new(*decEngine);
|
||||||
info.decoderPtr[wireId] = enginePtr;
|
info.decoderPtr[wireId] = enginePtr;
|
||||||
*enginePtr = compileDec(wireId, rt);
|
*enginePtr, err = compileDec(wireId, rt);
|
||||||
|
if err != nil {
|
||||||
|
info.decoderPtr[wireId] = nil, false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return enginePtr
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode(b *bytes.Buffer, wireId TypeId, e interface{}) os.Error {
|
func decode(b *bytes.Buffer, wireId TypeId, e interface{}) os.Error {
|
||||||
@ -657,11 +679,15 @@ func decode(b *bytes.Buffer, wireId TypeId, e interface{}) os.Error {
|
|||||||
return os.ErrorString("gob: decode can't handle " + rt.String())
|
return os.ErrorString("gob: decode can't handle " + rt.String())
|
||||||
}
|
}
|
||||||
typeLock.Lock();
|
typeLock.Lock();
|
||||||
engine := *getDecEnginePtr(wireId, rt);
|
enginePtr, err := getDecEnginePtr(wireId, rt);
|
||||||
typeLock.Unlock();
|
typeLock.Unlock();
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
engine := *enginePtr;
|
||||||
if engine.numInstr == 0 && st.NumField() > 0 {
|
if engine.numInstr == 0 && st.NumField() > 0 {
|
||||||
path, name := rt.Name();
|
path, name := rt.Name();
|
||||||
return os.ErrorString("no fields matched compiling decoder for " + name)
|
return os.ErrorString("type mismatch: no fields matched compiling decoder for " + name)
|
||||||
}
|
}
|
||||||
return decodeStruct(engine, rt.(*reflect.StructType), b, uintptr(v.Addr()), 0);
|
return decodeStruct(engine, rt.(*reflect.StructType), b, uintptr(v.Addr()), 0);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
|
|||||||
// Receive a type id.
|
// Receive a type id.
|
||||||
id := TypeId(decodeInt(dec.state));
|
id := TypeId(decodeInt(dec.state));
|
||||||
if dec.state.err != nil {
|
if dec.state.err != nil {
|
||||||
return dec.state.err
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is it a new type?
|
// Is it a new type?
|
||||||
@ -91,28 +91,14 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
|
|||||||
// If the id is negative, we have a type.
|
// If the id is negative, we have a type.
|
||||||
dec.recvType(-id);
|
dec.recvType(-id);
|
||||||
if dec.state.err != nil {
|
if dec.state.err != nil {
|
||||||
return dec.state.err
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No, it's a value.
|
// No, it's a value.
|
||||||
typeLock.Lock();
|
dec.state.err = decode(dec.state.b, id, e);
|
||||||
info := getTypeInfo(rt);
|
break;
|
||||||
typeLock.Unlock();
|
|
||||||
|
|
||||||
// Check type compatibility.
|
|
||||||
// TODO(r): need to make the decoder work correctly if the wire type is compatible
|
|
||||||
// but not equal to the local type (e.g, extra fields).
|
|
||||||
if info.wire.name() != dec.seen[id].name() {
|
|
||||||
dec.state.err = os.ErrorString("gob decode: incorrect type for wire value: want " + info.wire.name() + "; received " + dec.seen[id].name());
|
|
||||||
return dec.state.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive a value.
|
|
||||||
decode(dec.state.b, id, e);
|
|
||||||
|
|
||||||
return dec.state.err
|
|
||||||
}
|
}
|
||||||
return nil // silence compiler
|
return dec.state.err
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ func encOpFor(rt reflect.Type) (encOp, int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if op == nil {
|
if op == nil {
|
||||||
panicln("encode can't handle type", rt.String());
|
panicln("can't happen: encode type", rt.String());
|
||||||
}
|
}
|
||||||
return op, indir
|
return op, indir
|
||||||
}
|
}
|
||||||
@ -381,7 +381,7 @@ func encOpFor(rt reflect.Type) (encOp, int) {
|
|||||||
func compileEnc(rt reflect.Type) *encEngine {
|
func compileEnc(rt reflect.Type) *encEngine {
|
||||||
srt, ok := rt.(*reflect.StructType);
|
srt, ok := rt.(*reflect.StructType);
|
||||||
if !ok {
|
if !ok {
|
||||||
panicln("TODO: can't handle non-structs");
|
panicln("can't happen: non-struct");
|
||||||
}
|
}
|
||||||
engine := new(encEngine);
|
engine := new(encEngine);
|
||||||
engine.instr = make([]encInstr, srt.NumField()+1); // +1 for terminator
|
engine.instr = make([]encInstr, srt.NumField()+1); // +1 for terminator
|
||||||
|
@ -38,11 +38,9 @@ type ET4 struct {
|
|||||||
next *ET2;
|
next *ET2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like ET1 but with a different type for a self-referencing field
|
// Has different type for a self-referencing field compared to ET1
|
||||||
type ET5 struct {
|
type ET5 struct {
|
||||||
a int;
|
next *ET2;
|
||||||
et2 *ET2;
|
|
||||||
next *ET1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBasicEncoder(t *testing.T) {
|
func TestBasicEncoder(t *testing.T) {
|
||||||
@ -227,7 +225,7 @@ func badTypeCheck(e interface{}, msg string, t *testing.T) {
|
|||||||
|
|
||||||
// Test that we recognize a bad type the first time.
|
// Test that we recognize a bad type the first time.
|
||||||
func TestWrongTypeDecoder(t *testing.T) {
|
func TestWrongTypeDecoder(t *testing.T) {
|
||||||
badTypeCheck(new(ET2), "different number of fields", t);
|
badTypeCheck(new(ET2), "no fields in common", t);
|
||||||
badTypeCheck(new(ET3), "different name of field", t);
|
badTypeCheck(new(ET3), "different name of field", t);
|
||||||
badTypeCheck(new(ET4), "different type of field", t);
|
badTypeCheck(new(ET4), "different type of field", t);
|
||||||
badTypeCheck(new(ET5), "different type of self-reference field", t);
|
badTypeCheck(new(ET5), "different type of self-reference field", t);
|
||||||
|
Loading…
Reference in New Issue
Block a user