diff options
Diffstat (limited to 'src/pkg/gob/encode.go')
-rw-r--r-- | src/pkg/gob/encode.go | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go index 195d6c647..fbea891b9 100644 --- a/src/pkg/gob/encode.go +++ b/src/pkg/gob/encode.go @@ -22,7 +22,7 @@ const uint64Size = unsafe.Sizeof(uint64(0)) type encoderState struct { b *bytes.Buffer err os.Error // error encountered during encoding. - inArray bool // encoding an array element + inArray bool // encoding an array element or map key/value pair fieldnum int // the last field number written. buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation. } @@ -297,7 +297,7 @@ func encodeStruct(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error { return state.err } -func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, length int, elemIndir int) os.Error { +func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) os.Error { state := new(encoderState) state.b = b state.fieldnum = -1 @@ -319,6 +319,39 @@ func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, length i return state.err } +func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) { + for i := 0; i < indir && v != nil; i++ { + v = reflect.Indirect(v) + } + if v == nil { + state.err = os.ErrorString("gob: encodeMap: nil element") + return + } + op(nil, state, unsafe.Pointer(v.Addr())) +} + +func encodeMap(b *bytes.Buffer, rt reflect.Type, p uintptr, keyOp, elemOp encOp, keyIndir, elemIndir int) os.Error { + state := new(encoderState) + state.b = b + state.fieldnum = -1 + state.inArray = true + // Maps cannot be accessed by moving addresses around the way + // that slices etc. can. We must recover a full reflection value for + // the iteration. + v := reflect.NewValue(unsafe.Unreflect(rt, unsafe.Pointer((p)))) + mv := reflect.Indirect(v).(*reflect.MapValue) + keys := mv.Keys() + encodeUint(state, uint64(len(keys))) + for _, key := range keys { + if state.err != nil { + break + } + encodeReflectValue(state, key, keyOp, keyIndir) + encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir) + } + return state.err +} + var encOpMap = map[reflect.Type]encOp{ valueKind(false): encBool, valueKind(int(0)): encInt, @@ -344,7 +377,6 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) { typ, indir := indirect(rt) op, ok := encOpMap[reflect.Typeof(typ)] if !ok { - typ, _ := indirect(rt) // Special cases switch t := typ.(type) { case *reflect.SliceType: @@ -363,7 +395,7 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) { return } state.update(i) - state.err = encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), int(slice.Len), indir) + state.err = encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), indir, int(slice.Len)) } case *reflect.ArrayType: // True arrays have size in the type. @@ -373,7 +405,20 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) { } op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { state.update(i) - state.err = encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), t.Len(), indir) + state.err = encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len()) + } + case *reflect.MapType: + keyOp, keyIndir, err := encOpFor(t.Key()) + if err != nil { + return nil, 0, err + } + elemOp, elemIndir, err := encOpFor(t.Elem()) + if err != nil { + return nil, 0, err + } + op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { + state.update(i) + state.err = encodeMap(state.b, typ, uintptr(p), keyOp, elemOp, keyIndir, elemIndir) } case *reflect.StructType: // Generate a closure that calls out to the engine for the nested type. |