Rob Pike | b948c43 | 2009-06-29 15:15:07 -0700 | [diff] [blame] | 1 | // Copyright 2009 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package gob |
| 6 | |
| 7 | import ( |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 8 | "bytes" |
| 9 | "io" |
| 10 | "math" |
| 11 | "os" |
| 12 | "reflect" |
| 13 | "unsafe" |
Rob Pike | b948c43 | 2009-06-29 15:15:07 -0700 | [diff] [blame] | 14 | ) |
| 15 | |
Rob Pike | b85147c | 2009-07-28 17:20:19 -0700 | [diff] [blame] | 16 | const uint64Size = unsafe.Sizeof(uint64(0)) |
| 17 | |
Rob Pike | 79b2cf9 | 2009-06-30 16:20:31 -0700 | [diff] [blame] | 18 | // The global execution state of an instance of the encoder. |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 19 | // Field numbers are delta encoded and always increase. The field |
| 20 | // number is initialized to -1 so 0 comes out as delta(1). A delta of |
| 21 | // 0 terminates the structure. |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 22 | type encoderState struct { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 23 | b *bytes.Buffer |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 24 | sendZero bool // encoding an array element or map key/value pair; send zero values |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 25 | fieldnum int // the last field number written. |
| 26 | buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation. |
Rob Pike | 79b2cf9 | 2009-06-30 16:20:31 -0700 | [diff] [blame] | 27 | } |
| 28 | |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 29 | func newEncoderState(b *bytes.Buffer) *encoderState { |
| 30 | return &encoderState{b: b} |
| 31 | } |
| 32 | |
Rob Pike | b85147c | 2009-07-28 17:20:19 -0700 | [diff] [blame] | 33 | // Unsigned integers have a two-state encoding. If the number is less |
| 34 | // than 128 (0 through 0x7F), its value is written directly. |
| 35 | // Otherwise the value is written in big-endian byte order preceded |
| 36 | // by the byte length, negated. |
Rob Pike | b948c43 | 2009-06-29 15:15:07 -0700 | [diff] [blame] | 37 | |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 38 | // encodeUint writes an encoded unsigned integer to state.b. |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 39 | func encodeUint(state *encoderState, x uint64) { |
Rob Pike | b85147c | 2009-07-28 17:20:19 -0700 | [diff] [blame] | 40 | if x <= 0x7F { |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 41 | err := state.b.WriteByte(uint8(x)) |
| 42 | if err != nil { |
| 43 | error(err) |
| 44 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 45 | return |
Rob Pike | b948c43 | 2009-06-29 15:15:07 -0700 | [diff] [blame] | 46 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 47 | var n, m int |
| 48 | m = uint64Size |
Rob Pike | b85147c | 2009-07-28 17:20:19 -0700 | [diff] [blame] | 49 | for n = 1; x > 0; n++ { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 50 | state.buf[m] = uint8(x & 0xFF) |
| 51 | x >>= 8 |
| 52 | m-- |
Rob Pike | b85147c | 2009-07-28 17:20:19 -0700 | [diff] [blame] | 53 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 54 | state.buf[m] = uint8(-(n - 1)) |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 55 | n, err := state.b.Write(state.buf[m : uint64Size+1]) |
| 56 | if err != nil { |
| 57 | error(err) |
| 58 | } |
Rob Pike | b948c43 | 2009-06-29 15:15:07 -0700 | [diff] [blame] | 59 | } |
| 60 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 61 | // encodeInt writes an encoded signed integer to state.w. |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 62 | // The low bit of the encoding says whether to bit complement the (other bits of the) |
| 63 | // uint to recover the int. |
Russ Cox | c2ec958 | 2009-10-06 19:41:51 -0700 | [diff] [blame] | 64 | func encodeInt(state *encoderState, i int64) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 65 | var x uint64 |
Rob Pike | b948c43 | 2009-06-29 15:15:07 -0700 | [diff] [blame] | 66 | if i < 0 { |
Robert Griesemer | baba292 | 2009-11-09 21:13:17 -0800 | [diff] [blame] | 67 | x = uint64(^i<<1) | 1 |
Rob Pike | b948c43 | 2009-06-29 15:15:07 -0700 | [diff] [blame] | 68 | } else { |
Robert Griesemer | baba292 | 2009-11-09 21:13:17 -0800 | [diff] [blame] | 69 | x = uint64(i << 1) |
Rob Pike | b948c43 | 2009-06-29 15:15:07 -0700 | [diff] [blame] | 70 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 71 | encodeUint(state, uint64(x)) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 72 | } |
| 73 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 74 | type encOp func(i *encInstr, state *encoderState, p unsafe.Pointer) |
Rob Pike | b1e6458 | 2009-07-01 23:04:27 -0700 | [diff] [blame] | 75 | |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 76 | // The 'instructions' of the encoding machine |
| 77 | type encInstr struct { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 78 | op encOp |
| 79 | field int // field number |
| 80 | indir int // how many pointer indirections to reach the value in the struct |
| 81 | offset uintptr // offset in the structure of the field to encode |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 82 | } |
| 83 | |
Rob Pike | 0c33d43 | 2009-07-02 16:43:46 -0700 | [diff] [blame] | 84 | // Emit a field number and update the state to record its value for delta encoding. |
| 85 | // If the instruction pointer is nil, do nothing |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 86 | func (state *encoderState) update(instr *encInstr) { |
Rob Pike | 0c33d43 | 2009-07-02 16:43:46 -0700 | [diff] [blame] | 87 | if instr != nil { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 88 | encodeUint(state, uint64(instr.field-state.fieldnum)) |
| 89 | state.fieldnum = instr.field |
Rob Pike | 0c33d43 | 2009-07-02 16:43:46 -0700 | [diff] [blame] | 90 | } |
| 91 | } |
| 92 | |
Rob Pike | 79b2cf9 | 2009-06-30 16:20:31 -0700 | [diff] [blame] | 93 | // Each encoder is responsible for handling any indirections associated |
| 94 | // with the data structure. If any pointer so reached is nil, no bytes are written. |
| 95 | // If the data item is zero, no bytes are written. |
| 96 | // Otherwise, the output (for a scalar) is the field number, as an encoded integer, |
| 97 | // followed by the field data in its appropriate format. |
| 98 | |
Rob Pike | b9689433 | 2009-06-30 17:59:41 -0700 | [diff] [blame] | 99 | func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer { |
| 100 | for ; indir > 0; indir-- { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 101 | p = *(*unsafe.Pointer)(p) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 102 | if p == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 103 | return unsafe.Pointer(nil) |
Rob Pike | b9689433 | 2009-06-30 17:59:41 -0700 | [diff] [blame] | 104 | } |
| 105 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 106 | return p |
Rob Pike | b9689433 | 2009-06-30 17:59:41 -0700 | [diff] [blame] | 107 | } |
| 108 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 109 | func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 110 | b := *(*bool)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 111 | if b || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 112 | state.update(i) |
Rob Pike | 33311a7 | 2009-12-29 07:41:53 +1100 | [diff] [blame] | 113 | if b { |
| 114 | encodeUint(state, 1) |
| 115 | } else { |
| 116 | encodeUint(state, 0) |
| 117 | } |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 118 | } |
| 119 | } |
| 120 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 121 | func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 122 | v := int64(*(*int)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 123 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 124 | state.update(i) |
| 125 | encodeInt(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 126 | } |
| 127 | } |
| 128 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 129 | func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 130 | v := uint64(*(*uint)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 131 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 132 | state.update(i) |
| 133 | encodeUint(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 134 | } |
| 135 | } |
| 136 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 137 | func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 138 | v := int64(*(*int8)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 139 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 140 | state.update(i) |
| 141 | encodeInt(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 142 | } |
| 143 | } |
| 144 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 145 | func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 146 | v := uint64(*(*uint8)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 147 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 148 | state.update(i) |
| 149 | encodeUint(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 150 | } |
| 151 | } |
| 152 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 153 | func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 154 | v := int64(*(*int16)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 155 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 156 | state.update(i) |
| 157 | encodeInt(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 158 | } |
| 159 | } |
| 160 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 161 | func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 162 | v := uint64(*(*uint16)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 163 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 164 | state.update(i) |
| 165 | encodeUint(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 166 | } |
| 167 | } |
| 168 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 169 | func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 170 | v := int64(*(*int32)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 171 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 172 | state.update(i) |
| 173 | encodeInt(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 174 | } |
| 175 | } |
| 176 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 177 | func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 178 | v := uint64(*(*uint32)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 179 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 180 | state.update(i) |
| 181 | encodeUint(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 182 | } |
| 183 | } |
| 184 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 185 | func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 186 | v := *(*int64)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 187 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 188 | state.update(i) |
| 189 | encodeInt(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 190 | } |
| 191 | } |
| 192 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 193 | func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 194 | v := *(*uint64)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 195 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 196 | state.update(i) |
| 197 | encodeUint(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 198 | } |
| 199 | } |
| 200 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 201 | func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 202 | v := uint64(*(*uintptr)(p)) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 203 | if v != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 204 | state.update(i) |
| 205 | encodeUint(state, v) |
Rob Pike | ec23467e | 2009-07-09 14:33:43 -0700 | [diff] [blame] | 206 | } |
| 207 | } |
| 208 | |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 209 | // Floating-point numbers are transmitted as uint64s holding the bits |
| 210 | // of the underlying representation. They are sent byte-reversed, with |
| 211 | // the exponent end coming out first, so integer floating point numbers |
| 212 | // (for example) transmit more compactly. This routine does the |
| 213 | // swizzling. |
| 214 | func floatBits(f float64) uint64 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 215 | u := math.Float64bits(f) |
| 216 | var v uint64 |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 217 | for i := 0; i < 8; i++ { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 218 | v <<= 8 |
| 219 | v |= u & 0xFF |
| 220 | u >>= 8 |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 221 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 222 | return v |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 223 | } |
| 224 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 225 | func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Rob Pike | 37a6bc8 | 2010-06-24 15:07:28 -0700 | [diff] [blame] | 226 | f := *(*float)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 227 | if f != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 228 | v := floatBits(float64(f)) |
| 229 | state.update(i) |
| 230 | encodeUint(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 231 | } |
| 232 | } |
| 233 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 234 | func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Rob Pike | 37a6bc8 | 2010-06-24 15:07:28 -0700 | [diff] [blame] | 235 | f := *(*float32)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 236 | if f != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 237 | v := floatBits(float64(f)) |
| 238 | state.update(i) |
| 239 | encodeUint(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 240 | } |
| 241 | } |
| 242 | |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 243 | func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 244 | f := *(*float64)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 245 | if f != 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 246 | state.update(i) |
| 247 | v := floatBits(f) |
| 248 | encodeUint(state, v) |
Rob Pike | f6f8251 | 2009-06-30 15:37:46 -0700 | [diff] [blame] | 249 | } |
| 250 | } |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 251 | |
Rob Pike | 37a6bc8 | 2010-06-24 15:07:28 -0700 | [diff] [blame] | 252 | // Complex numbers are just a pair of floating-point numbers, real part first. |
| 253 | func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) { |
| 254 | c := *(*complex)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 255 | if c != 0+0i || state.sendZero { |
Rob Pike | 37a6bc8 | 2010-06-24 15:07:28 -0700 | [diff] [blame] | 256 | rpart := floatBits(float64(real(c))) |
| 257 | ipart := floatBits(float64(imag(c))) |
| 258 | state.update(i) |
| 259 | encodeUint(state, rpart) |
| 260 | encodeUint(state, ipart) |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) { |
| 265 | c := *(*complex64)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 266 | if c != 0+0i || state.sendZero { |
Rob Pike | 37a6bc8 | 2010-06-24 15:07:28 -0700 | [diff] [blame] | 267 | rpart := floatBits(float64(real(c))) |
| 268 | ipart := floatBits(float64(imag(c))) |
| 269 | state.update(i) |
| 270 | encodeUint(state, rpart) |
| 271 | encodeUint(state, ipart) |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) { |
| 276 | c := *(*complex128)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 277 | if c != 0+0i || state.sendZero { |
Rob Pike | 37a6bc8 | 2010-06-24 15:07:28 -0700 | [diff] [blame] | 278 | rpart := floatBits(real(c)) |
| 279 | ipart := floatBits(imag(c)) |
| 280 | state.update(i) |
| 281 | encodeUint(state, rpart) |
| 282 | encodeUint(state, ipart) |
| 283 | } |
| 284 | } |
| 285 | |
Rob Pike | 1ca1e1b | 2009-07-02 11:21:01 -0700 | [diff] [blame] | 286 | // Byte arrays are encoded as an unsigned count followed by the raw bytes. |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 287 | func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 288 | b := *(*[]byte)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 289 | if len(b) > 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 290 | state.update(i) |
| 291 | encodeUint(state, uint64(len(b))) |
| 292 | state.b.Write(b) |
Rob Pike | 1ca1e1b | 2009-07-02 11:21:01 -0700 | [diff] [blame] | 293 | } |
| 294 | } |
| 295 | |
| 296 | // Strings are encoded as an unsigned count followed by the raw bytes. |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 297 | func encString(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 298 | s := *(*string)(p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 299 | if len(s) > 0 || state.sendZero { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 300 | state.update(i) |
| 301 | encodeUint(state, uint64(len(s))) |
| 302 | io.WriteString(state.b, s) |
Rob Pike | 1ca1e1b | 2009-07-02 11:21:01 -0700 | [diff] [blame] | 303 | } |
| 304 | } |
| 305 | |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 306 | // The end of a struct is marked by a delta field number of 0. |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 307 | func encStructTerminator(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 308 | encodeUint(state, 0) |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 309 | } |
| 310 | |
| 311 | // Execution engine |
| 312 | |
| 313 | // The encoder engine is an array of instructions indexed by field number of the encoding |
| 314 | // data, typically a struct. It is executed top to bottom, walking the struct. |
| 315 | type encEngine struct { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 316 | instr []encInstr |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 317 | } |
| 318 | |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 319 | const singletonField = 0 |
| 320 | |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 321 | func encodeSingle(engine *encEngine, b *bytes.Buffer, basep uintptr) { |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 322 | state := newEncoderState(b) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 323 | state.fieldnum = singletonField |
| 324 | // There is no surrounding struct to frame the transmission, so we must |
| 325 | // generate data even if the item is zero. To do this, set sendZero. |
| 326 | state.sendZero = true |
| 327 | instr := &engine.instr[singletonField] |
| 328 | p := unsafe.Pointer(basep) // offset will be zero |
| 329 | if instr.indir > 0 { |
| 330 | if p = encIndirect(p, instr.indir); p == nil { |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 331 | return |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 332 | } |
| 333 | } |
| 334 | instr.op(instr, state, p) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 335 | } |
| 336 | |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 337 | func encodeStruct(engine *encEngine, b *bytes.Buffer, basep uintptr) { |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 338 | state := newEncoderState(b) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 339 | state.fieldnum = -1 |
Rob Pike | 77baac1 | 2009-07-02 13:43:47 -0700 | [diff] [blame] | 340 | for i := 0; i < len(engine.instr); i++ { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 341 | instr := &engine.instr[i] |
| 342 | p := unsafe.Pointer(basep + instr.offset) |
Rob Pike | 77baac1 | 2009-07-02 13:43:47 -0700 | [diff] [blame] | 343 | if instr.indir > 0 { |
| 344 | if p = encIndirect(p, instr.indir); p == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 345 | continue |
Rob Pike | 77baac1 | 2009-07-02 13:43:47 -0700 | [diff] [blame] | 346 | } |
| 347 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 348 | instr.op(instr, state, p) |
Rob Pike | 77baac1 | 2009-07-02 13:43:47 -0700 | [diff] [blame] | 349 | } |
Rob Pike | 77baac1 | 2009-07-02 13:43:47 -0700 | [diff] [blame] | 350 | } |
| 351 | |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 352 | func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) { |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 353 | state := newEncoderState(b) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 354 | state.fieldnum = -1 |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 355 | state.sendZero = true |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 356 | encodeUint(state, uint64(length)) |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 357 | for i := 0; i < length; i++ { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 358 | elemp := p |
| 359 | up := unsafe.Pointer(elemp) |
Rob Pike | c1fc4c8 | 2009-07-02 17:21:48 -0700 | [diff] [blame] | 360 | if elemIndir > 0 { |
| 361 | if up = encIndirect(up, elemIndir); up == nil { |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 362 | errorf("gob: encodeArray: nil element") |
Rob Pike | c1fc4c8 | 2009-07-02 17:21:48 -0700 | [diff] [blame] | 363 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 364 | elemp = uintptr(up) |
Rob Pike | c1fc4c8 | 2009-07-02 17:21:48 -0700 | [diff] [blame] | 365 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 366 | op(nil, state, unsafe.Pointer(elemp)) |
| 367 | p += uintptr(elemWid) |
Rob Pike | 0c33d43 | 2009-07-02 16:43:46 -0700 | [diff] [blame] | 368 | } |
Rob Pike | 0c33d43 | 2009-07-02 16:43:46 -0700 | [diff] [blame] | 369 | } |
| 370 | |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 371 | func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) { |
| 372 | for i := 0; i < indir && v != nil; i++ { |
| 373 | v = reflect.Indirect(v) |
| 374 | } |
| 375 | if v == nil { |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 376 | errorf("gob: encodeReflectValue: nil element") |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 377 | } |
| 378 | op(nil, state, unsafe.Pointer(v.Addr())) |
| 379 | } |
| 380 | |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 381 | func encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) { |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 382 | state := newEncoderState(b) |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 383 | state.fieldnum = -1 |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 384 | state.sendZero = true |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 385 | keys := mv.Keys() |
| 386 | encodeUint(state, uint64(len(keys))) |
| 387 | for _, key := range keys { |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 388 | encodeReflectValue(state, key, keyOp, keyIndir) |
| 389 | encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir) |
| 390 | } |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 391 | } |
| 392 | |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 393 | // To send an interface, we send a string identifying the concrete type, followed |
| 394 | // by the type identifier (which might require defining that type right now), followed |
| 395 | // by the concrete value. A nil value gets sent as the empty string for the name, |
| 396 | // followed by no value. |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 397 | func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) { |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 398 | state := newEncoderState(b) |
| 399 | state.fieldnum = -1 |
| 400 | state.sendZero = true |
| 401 | if iv.IsNil() { |
| 402 | encodeUint(state, 0) |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 403 | return |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 404 | } |
| 405 | |
| 406 | typ := iv.Elem().Type() |
| 407 | name, ok := concreteTypeToName[typ] |
| 408 | if !ok { |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 409 | errorf("gob: type not registered for interface: %s", typ) |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 410 | } |
| 411 | // Send the name. |
| 412 | encodeUint(state, uint64(len(name))) |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 413 | _, err := io.WriteString(state.b, name) |
| 414 | if err != nil { |
| 415 | error(err) |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 416 | } |
| 417 | // Send (and maybe first define) the type id. |
| 418 | enc.sendTypeDescriptor(typ) |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 419 | // Send the value. |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 420 | err = enc.encode(state.b, iv.Elem()) |
| 421 | if err != nil { |
| 422 | error(err) |
| 423 | } |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 424 | } |
| 425 | |
Russ Cox | fc090a3 | 2010-06-21 13:19:29 -0700 | [diff] [blame] | 426 | var encOpMap = []encOp{ |
Rob Pike | 37a6bc8 | 2010-06-24 15:07:28 -0700 | [diff] [blame] | 427 | reflect.Bool: encBool, |
| 428 | reflect.Int: encInt, |
| 429 | reflect.Int8: encInt8, |
| 430 | reflect.Int16: encInt16, |
| 431 | reflect.Int32: encInt32, |
| 432 | reflect.Int64: encInt64, |
| 433 | reflect.Uint: encUint, |
| 434 | reflect.Uint8: encUint8, |
| 435 | reflect.Uint16: encUint16, |
| 436 | reflect.Uint32: encUint32, |
| 437 | reflect.Uint64: encUint64, |
| 438 | reflect.Uintptr: encUintptr, |
| 439 | reflect.Float: encFloat, |
| 440 | reflect.Float32: encFloat32, |
| 441 | reflect.Float64: encFloat64, |
| 442 | reflect.Complex: encComplex, |
| 443 | reflect.Complex64: encComplex64, |
| 444 | reflect.Complex128: encComplex128, |
| 445 | reflect.String: encString, |
Rob Pike | 1ca1e1b | 2009-07-02 11:21:01 -0700 | [diff] [blame] | 446 | } |
| 447 | |
Rob Pike | 0ae7882 | 2009-07-07 21:05:24 -0700 | [diff] [blame] | 448 | // Return the encoding op for the base type under rt and |
| 449 | // the indirection count to reach it. |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 450 | func (enc *Encoder) encOpFor(rt reflect.Type) (encOp, int) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 451 | typ, indir := indirect(rt) |
Russ Cox | fc090a3 | 2010-06-21 13:19:29 -0700 | [diff] [blame] | 452 | var op encOp |
| 453 | k := typ.Kind() |
| 454 | if int(k) < len(encOpMap) { |
| 455 | op = encOpMap[k] |
| 456 | } |
| 457 | if op == nil { |
Rob Pike | 1ca1e1b | 2009-07-02 11:21:01 -0700 | [diff] [blame] | 458 | // Special cases |
Russ Cox | 8778393 | 2009-07-07 11:04:42 -0700 | [diff] [blame] | 459 | switch t := typ.(type) { |
| 460 | case *reflect.SliceType: |
Russ Cox | 45bdf03 | 2010-06-20 12:16:25 -0700 | [diff] [blame] | 461 | if t.Elem().Kind() == reflect.Uint8 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 462 | op = encUint8Array |
| 463 | break |
Rob Pike | 1ca1e1b | 2009-07-02 11:21:01 -0700 | [diff] [blame] | 464 | } |
Russ Cox | 8778393 | 2009-07-07 11:04:42 -0700 | [diff] [blame] | 465 | // Slices have a header; we decode it to find the underlying array. |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 466 | elemOp, indir := enc.encOpFor(t.Elem()) |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 467 | op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 468 | slice := (*reflect.SliceHeader)(p) |
Russ Cox | 8778393 | 2009-07-07 11:04:42 -0700 | [diff] [blame] | 469 | if slice.Len == 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 470 | return |
Russ Cox | 8778393 | 2009-07-07 11:04:42 -0700 | [diff] [blame] | 471 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 472 | state.update(i) |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 473 | encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), indir, int(slice.Len)) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 474 | } |
Russ Cox | 8778393 | 2009-07-07 11:04:42 -0700 | [diff] [blame] | 475 | case *reflect.ArrayType: |
| 476 | // True arrays have size in the type. |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 477 | elemOp, indir := enc.encOpFor(t.Elem()) |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 478 | op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 479 | state.update(i) |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 480 | encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len()) |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 481 | } |
| 482 | case *reflect.MapType: |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 483 | keyOp, keyIndir := enc.encOpFor(t.Key()) |
| 484 | elemOp, elemIndir := enc.encOpFor(t.Elem()) |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 485 | op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 486 | // Maps cannot be accessed by moving addresses around the way |
| 487 | // that slices etc. can. We must recover a full reflection value for |
| 488 | // the iteration. |
| 489 | v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p)))) |
| 490 | mv := reflect.Indirect(v).(*reflect.MapValue) |
| 491 | if mv.Len() == 0 { |
| 492 | return |
| 493 | } |
Rob Pike | 7861da7 | 2010-05-05 16:46:39 -0700 | [diff] [blame] | 494 | state.update(i) |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 495 | encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 496 | } |
Russ Cox | 8778393 | 2009-07-07 11:04:42 -0700 | [diff] [blame] | 497 | case *reflect.StructType: |
Rob Pike | 77baac1 | 2009-07-02 13:43:47 -0700 | [diff] [blame] | 498 | // Generate a closure that calls out to the engine for the nested type. |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 499 | enc.getEncEngine(typ) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 500 | info := mustGetTypeInfo(typ) |
Rob Pike | e76a335 | 2009-07-15 16:10:17 -0700 | [diff] [blame] | 501 | op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 502 | state.update(i) |
Rob Pike | ec23467e | 2009-07-09 14:33:43 -0700 | [diff] [blame] | 503 | // indirect through info to delay evaluation for recursive structs |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 504 | encodeStruct(info.encoder, state.b, uintptr(p)) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 505 | } |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 506 | case *reflect.InterfaceType: |
| 507 | op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { |
| 508 | // Interfaces transmit the name and contents of the concrete |
| 509 | // value they contain. |
| 510 | v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p)))) |
| 511 | iv := reflect.Indirect(v).(*reflect.InterfaceValue) |
| 512 | if !state.sendZero && (iv == nil || iv.IsNil()) { |
| 513 | return |
| 514 | } |
| 515 | state.update(i) |
Rob Pike | f593b37 | 2010-10-22 15:16:34 -0700 | [diff] [blame] | 516 | enc.encodeInterface(state.b, iv) |
Rob Pike | 5d90646 | 2010-10-22 11:17:40 -0700 | [diff] [blame] | 517 | } |
Rob Pike | 77baac1 | 2009-07-02 13:43:47 -0700 | [diff] [blame] | 518 | } |
Rob Pike | 1ca1e1b | 2009-07-02 11:21:01 -0700 | [diff] [blame] | 519 | } |
| 520 | if op == nil { |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 521 | errorf("gob enc: can't happen: encode type %s", rt.String()) |
Rob Pike | 1ca1e1b | 2009-07-02 11:21:01 -0700 | [diff] [blame] | 522 | } |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 523 | return op, indir |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 524 | } |
| 525 | |
Rob Pike | ec23467e | 2009-07-09 14:33:43 -0700 | [diff] [blame] | 526 | // The local Type was compiled from the actual value, so we know it's compatible. |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 527 | func (enc *Encoder) compileEnc(rt reflect.Type) *encEngine { |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 528 | srt, isStruct := rt.(*reflect.StructType) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 529 | engine := new(encEngine) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 530 | if isStruct { |
| 531 | engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator |
| 532 | for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ { |
| 533 | f := srt.Field(fieldnum) |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 534 | op, indir := enc.encOpFor(f.Type) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 535 | engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)} |
| 536 | } |
| 537 | engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0} |
| 538 | } else { |
| 539 | engine.instr = make([]encInstr, 1) |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 540 | op, indir := enc.encOpFor(rt) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 541 | engine.instr[0] = encInstr{op, singletonField, indir, 0} // offset is zero |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 542 | } |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 543 | return engine |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 544 | } |
| 545 | |
Rob Pike | ec23467e | 2009-07-09 14:33:43 -0700 | [diff] [blame] | 546 | // typeLock must be held (or we're in initialization and guaranteed single-threaded). |
| 547 | // The reflection type must have all its indirections processed out. |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 548 | func (enc *Encoder) getEncEngine(rt reflect.Type) *encEngine { |
| 549 | info, err1 := getTypeInfo(rt) |
| 550 | if err1 != nil { |
| 551 | error(err1) |
Rob Pike | 98607d0 | 2009-07-29 17:24:25 -0700 | [diff] [blame] | 552 | } |
Rob Pike | ec23467e | 2009-07-09 14:33:43 -0700 | [diff] [blame] | 553 | if info.encoder == nil { |
| 554 | // mark this engine as underway before compiling to handle recursive types. |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 555 | info.encoder = new(encEngine) |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 556 | info.encoder = enc.compileEnc(rt) |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 557 | } |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 558 | return info.encoder |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 559 | } |
| 560 | |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 561 | // Put this in a function so we can hold the lock only while compiling, not when encoding. |
| 562 | func (enc *Encoder) lockAndGetEncEngine(rt reflect.Type) *encEngine { |
| 563 | typeLock.Lock() |
| 564 | defer typeLock.Unlock() |
| 565 | return enc.getEncEngine(rt) |
| 566 | } |
| 567 | |
| 568 | func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value) (err os.Error) { |
| 569 | defer catchError(&err) |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 570 | // Dereference down to the underlying object. |
Rob Pike | 12a4d84 | 2010-06-28 17:11:54 -0700 | [diff] [blame] | 571 | rt, indir := indirect(value.Type()) |
Rob Pike | c1fc4c8 | 2009-07-02 17:21:48 -0700 | [diff] [blame] | 572 | for i := 0; i < indir; i++ { |
Rob Pike | 12a4d84 | 2010-06-28 17:11:54 -0700 | [diff] [blame] | 573 | value = reflect.Indirect(value) |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 574 | } |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 575 | engine := enc.lockAndGetEncEngine(rt) |
Rob Pike | da69685 | 2010-06-29 10:14:32 -0700 | [diff] [blame] | 576 | if value.Type().Kind() == reflect.Struct { |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 577 | encodeStruct(engine, b, value.Addr()) |
| 578 | } else { |
| 579 | encodeSingle(engine, b, value.Addr()) |
Rob Pike | a26ab29 | 2010-06-28 14:09:47 -0700 | [diff] [blame] | 580 | } |
Rob Pike | c28fa51 | 2010-10-22 16:07:26 -0700 | [diff] [blame^] | 581 | return nil |
Rob Pike | c701af8 | 2009-07-01 18:25:13 -0700 | [diff] [blame] | 582 | } |