mirror of
				https://github.com/golang/go.git
				synced 2025-11-04 02:30:57 +00:00 
			
		
		
		
	gob: allow transmission of things other than structs at the top level.
also fix a bug handling nil maps: before, would needlessly send empty map R=rsc CC=golang-dev https://golang.org/cl/1739043
This commit is contained in:
		
							parent
							
								
									e0334ab798
								
							
						
					
					
						commit
						a26ab29ab8
					
				
					 6 changed files with 234 additions and 113 deletions
				
			
		| 
						 | 
				
			
			@ -271,7 +271,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 or map key/value pair
 | 
			
		||||
	sendZero bool                 // encoding an array element or map key/value pair; send zero values
 | 
			
		||||
	fieldnum int                  // the last field number written.
 | 
			
		||||
	buf      [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -352,7 +352,7 @@ func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
 | 
			
		|||
 | 
			
		||||
func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	b := *(*bool)(p)
 | 
			
		||||
	if b || state.inArray {
 | 
			
		||||
	if b || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		if b {
 | 
			
		||||
			encodeUint(state, 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -364,7 +364,7 @@ func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := int64(*(*int)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeInt(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -372,7 +372,7 @@ func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := uint64(*(*uint)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -380,7 +380,7 @@ func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := int64(*(*int8)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeInt(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -388,7 +388,7 @@ func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := uint64(*(*uint8)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -396,7 +396,7 @@ func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := int64(*(*int16)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeInt(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +404,7 @@ func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := uint64(*(*uint16)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -412,7 +412,7 @@ func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := int64(*(*int32)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeInt(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -420,7 +420,7 @@ func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := uint64(*(*uint32)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -428,7 +428,7 @@ func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := *(*int64)(p)
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeInt(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -436,7 +436,7 @@ func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := *(*uint64)(p)
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -444,7 +444,7 @@ func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	v := uint64(*(*uintptr)(p))
 | 
			
		||||
	if v != 0 || state.inArray {
 | 
			
		||||
	if v != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -468,7 +468,7 @@ func floatBits(f float64) uint64 {
 | 
			
		|||
 | 
			
		||||
func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	f := *(*float)(p)
 | 
			
		||||
	if f != 0 || state.inArray {
 | 
			
		||||
	if f != 0 || state.sendZero {
 | 
			
		||||
		v := floatBits(float64(f))
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
| 
						 | 
				
			
			@ -477,7 +477,7 @@ func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	f := *(*float32)(p)
 | 
			
		||||
	if f != 0 || state.inArray {
 | 
			
		||||
	if f != 0 || state.sendZero {
 | 
			
		||||
		v := floatBits(float64(f))
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
| 
						 | 
				
			
			@ -486,7 +486,7 @@ func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	f := *(*float64)(p)
 | 
			
		||||
	if f != 0 || state.inArray {
 | 
			
		||||
	if f != 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		v := floatBits(f)
 | 
			
		||||
		encodeUint(state, v)
 | 
			
		||||
| 
						 | 
				
			
			@ -496,7 +496,7 @@ func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
// Complex numbers are just a pair of floating-point numbers, real part first.
 | 
			
		||||
func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	c := *(*complex)(p)
 | 
			
		||||
	if c != 0+0i || state.inArray {
 | 
			
		||||
	if c != 0+0i || state.sendZero {
 | 
			
		||||
		rpart := floatBits(float64(real(c)))
 | 
			
		||||
		ipart := floatBits(float64(imag(c)))
 | 
			
		||||
		state.update(i)
 | 
			
		||||
| 
						 | 
				
			
			@ -507,7 +507,7 @@ func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	c := *(*complex64)(p)
 | 
			
		||||
	if c != 0+0i || state.inArray {
 | 
			
		||||
	if c != 0+0i || state.sendZero {
 | 
			
		||||
		rpart := floatBits(float64(real(c)))
 | 
			
		||||
		ipart := floatBits(float64(imag(c)))
 | 
			
		||||
		state.update(i)
 | 
			
		||||
| 
						 | 
				
			
			@ -518,7 +518,7 @@ func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
 | 
			
		||||
func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	c := *(*complex128)(p)
 | 
			
		||||
	if c != 0+0i || state.inArray {
 | 
			
		||||
	if c != 0+0i || state.sendZero {
 | 
			
		||||
		rpart := floatBits(real(c))
 | 
			
		||||
		ipart := floatBits(imag(c))
 | 
			
		||||
		state.update(i)
 | 
			
		||||
| 
						 | 
				
			
			@ -530,7 +530,7 @@ func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
// Byte arrays are encoded as an unsigned count followed by the raw bytes.
 | 
			
		||||
func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	b := *(*[]byte)(p)
 | 
			
		||||
	if len(b) > 0 || state.inArray {
 | 
			
		||||
	if len(b) > 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, uint64(len(b)))
 | 
			
		||||
		state.b.Write(b)
 | 
			
		||||
| 
						 | 
				
			
			@ -540,7 +540,7 @@ func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		|||
// Strings are encoded as an unsigned count followed by the raw bytes.
 | 
			
		||||
func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
	s := *(*string)(p)
 | 
			
		||||
	if len(s) > 0 || state.inArray {
 | 
			
		||||
	if len(s) > 0 || state.sendZero {
 | 
			
		||||
		state.update(i)
 | 
			
		||||
		encodeUint(state, uint64(len(s)))
 | 
			
		||||
		io.WriteString(state.b, s)
 | 
			
		||||
| 
						 | 
				
			
			@ -560,6 +560,26 @@ type encEngine struct {
 | 
			
		|||
	instr []encInstr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const singletonField = 0
 | 
			
		||||
 | 
			
		||||
func encodeSingle(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
 | 
			
		||||
	state := new(encoderState)
 | 
			
		||||
	state.b = b
 | 
			
		||||
	state.fieldnum = singletonField
 | 
			
		||||
	// There is no surrounding struct to frame the transmission, so we must
 | 
			
		||||
	// generate data even if the item is zero.  To do this, set sendZero.
 | 
			
		||||
	state.sendZero = true
 | 
			
		||||
	instr := &engine.instr[singletonField]
 | 
			
		||||
	p := unsafe.Pointer(basep) // offset will be zero
 | 
			
		||||
	if instr.indir > 0 {
 | 
			
		||||
		if p = encIndirect(p, instr.indir); p == nil {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	instr.op(instr, state, p)
 | 
			
		||||
	return state.err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func encodeStruct(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
 | 
			
		||||
	state := new(encoderState)
 | 
			
		||||
	state.b = b
 | 
			
		||||
| 
						 | 
				
			
			@ -584,7 +604,7 @@ func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndi
 | 
			
		|||
	state := new(encoderState)
 | 
			
		||||
	state.b = b
 | 
			
		||||
	state.fieldnum = -1
 | 
			
		||||
	state.inArray = true
 | 
			
		||||
	state.sendZero = true
 | 
			
		||||
	encodeUint(state, uint64(length))
 | 
			
		||||
	for i := 0; i < length && state.err == nil; i++ {
 | 
			
		||||
		elemp := p
 | 
			
		||||
| 
						 | 
				
			
			@ -607,22 +627,17 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in
 | 
			
		|||
		v = reflect.Indirect(v)
 | 
			
		||||
	}
 | 
			
		||||
	if v == nil {
 | 
			
		||||
		state.err = os.ErrorString("gob: encodeMap: nil element")
 | 
			
		||||
		state.err = os.ErrorString("gob: encodeReflectValue: 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 {
 | 
			
		||||
func encodeMap(b *bytes.Buffer, mv *reflect.MapValue, 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)
 | 
			
		||||
	state.sendZero = true
 | 
			
		||||
	keys := mv.Keys()
 | 
			
		||||
	encodeUint(state, uint64(len(keys)))
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
| 
						 | 
				
			
			@ -694,6 +709,10 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) {
 | 
			
		|||
				return nil, 0, err
 | 
			
		||||
			}
 | 
			
		||||
			op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
				slice := (*reflect.SliceHeader)(p)
 | 
			
		||||
				if slice.Len == 0 {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				state.update(i)
 | 
			
		||||
				state.err = encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len())
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -707,8 +726,16 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) {
 | 
			
		|||
				return nil, 0, err
 | 
			
		||||
			}
 | 
			
		||||
			op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
 | 
			
		||||
				// 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(t, unsafe.Pointer((p))))
 | 
			
		||||
				mv := reflect.Indirect(v).(*reflect.MapValue)
 | 
			
		||||
				if mv.Len() == 0 {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				state.update(i)
 | 
			
		||||
				state.err = encodeMap(state.b, typ, uintptr(p), keyOp, elemOp, keyIndir, elemIndir)
 | 
			
		||||
				state.err = encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir)
 | 
			
		||||
			}
 | 
			
		||||
		case *reflect.StructType:
 | 
			
		||||
			// Generate a closure that calls out to the engine for the nested type.
 | 
			
		||||
| 
						 | 
				
			
			@ -732,21 +759,27 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) {
 | 
			
		|||
 | 
			
		||||
// The local Type was compiled from the actual value, so we know it's compatible.
 | 
			
		||||
func compileEnc(rt reflect.Type) (*encEngine, os.Error) {
 | 
			
		||||
	srt, ok := rt.(*reflect.StructType)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		panic("can't happen: non-struct")
 | 
			
		||||
	}
 | 
			
		||||
	srt, isStruct := rt.(*reflect.StructType)
 | 
			
		||||
	engine := new(encEngine)
 | 
			
		||||
	engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator
 | 
			
		||||
	for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ {
 | 
			
		||||
		f := srt.Field(fieldnum)
 | 
			
		||||
		op, indir, err := encOpFor(f.Type)
 | 
			
		||||
	if isStruct {
 | 
			
		||||
		engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator
 | 
			
		||||
		for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ {
 | 
			
		||||
			f := srt.Field(fieldnum)
 | 
			
		||||
			op, indir, err := encOpFor(f.Type)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)}
 | 
			
		||||
		}
 | 
			
		||||
		engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0}
 | 
			
		||||
	} else {
 | 
			
		||||
		engine.instr = make([]encInstr, 1)
 | 
			
		||||
		op, indir, err := encOpFor(rt)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)}
 | 
			
		||||
		engine.instr[0] = encInstr{op, singletonField, indir, 0} // offset is zero
 | 
			
		||||
	}
 | 
			
		||||
	engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0}
 | 
			
		||||
	return engine, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -772,14 +805,14 @@ func encode(b *bytes.Buffer, e interface{}) os.Error {
 | 
			
		|||
	for i := 0; i < indir; i++ {
 | 
			
		||||
		v = reflect.Indirect(v)
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := v.(*reflect.StructValue); !ok {
 | 
			
		||||
		return os.ErrorString("gob: encode can't handle " + v.Type().String())
 | 
			
		||||
	}
 | 
			
		||||
	typeLock.Lock()
 | 
			
		||||
	engine, err := getEncEngine(rt)
 | 
			
		||||
	typeLock.Unlock()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return encodeStruct(engine, b, v.Addr())
 | 
			
		||||
	if _, ok := v.(*reflect.StructValue); ok {
 | 
			
		||||
		return encodeStruct(engine, b, v.Addr())
 | 
			
		||||
	}
 | 
			
		||||
	return encodeSingle(engine, b, v.Addr())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue