blob: b64481decdb65b6838c568d2b26b01e1f58dbeb9 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2010 Google Inc. All rights reserved.
4// http://code.google.com/p/goprotobuf/
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32package proto
33
34/*
35 * Routines for encoding data into the wire format for protocol buffers.
36 */
37
38import (
39 "fmt"
40 "os"
41 "reflect"
David Symondsd15e81b2011-10-03 14:31:12 -070042 "sort"
Rob Pikeaaa3a622010-03-20 22:32:34 -070043 "strconv"
44 "strings"
45 "sync"
46 "unsafe"
47)
48
49const debug bool = false
50
51// Constants that identify the encoding of a value on the wire.
52const (
53 WireVarint = 0
54 WireFixed64 = 1
55 WireBytes = 2
56 WireStartGroup = 3
57 WireEndGroup = 4
58 WireFixed32 = 5
59)
60
61const startSize = 10 // initial slice/string sizes
62
63// Encoders are defined in encoder.go
64// An encoder outputs the full representation of a field, including its
65// tag and encoder type.
66type encoder func(p *Buffer, prop *Properties, base uintptr) os.Error
67
68// A valueEncoder encodes a single integer in a particular encoding.
69type valueEncoder func(o *Buffer, x uint64) os.Error
70
71// Decoders are defined in decode.go
72// A decoder creates a value from its wire representation.
73// Unrecognized subelements are saved in unrec.
74type decoder func(p *Buffer, prop *Properties, base uintptr, sbase uintptr) os.Error
75
76// A valueDecoder decodes a single integer in a particular encoding.
77type valueDecoder func(o *Buffer) (x uint64, err os.Error)
78
79// StructProperties represents properties for all the fields of a struct.
80type StructProperties struct {
David Symonds79eae332010-10-16 11:33:20 +110081 Prop []*Properties // properties for each field
82 reqCount int // required count
83 tags map[int]int // map from proto tag to struct field number
84 origNames map[string]int // map from original name to struct field number
David Symondsd15e81b2011-10-03 14:31:12 -070085 order []int // list of struct field numbers in tag order
David Symonds79eae332010-10-16 11:33:20 +110086 nscratch uintptr // size of scratch space
Rob Pikeaaa3a622010-03-20 22:32:34 -070087}
88
David Symondsd15e81b2011-10-03 14:31:12 -070089// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
90// See encoder.go, (*Buffer).enc_struct.
91
92func (sp *StructProperties) Len() int { return len(sp.order) }
93func (sp *StructProperties) Less(i, j int) bool {
94 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
95}
96func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
97
Rob Pikeaaa3a622010-03-20 22:32:34 -070098// Properties represents the protocol-specific behavior of a single struct field.
99type Properties struct {
100 Name string // name of the field, for error messages
101 OrigName string // original name before protocol compiler (always set)
102 Wire string
103 WireType int
104 Tag int
105 Required bool
106 Optional bool
107 Repeated bool
David Symonds5b7775e2010-12-01 10:09:04 +1100108 Packed bool // relevant for repeated primitives only
Rob Pikeaaa3a622010-03-20 22:32:34 -0700109 Enum string // set for enum types only
110 Default string // default value
111 def_uint64 uint64
112
113 enc encoder
114 valEnc valueEncoder // set for bool and numeric types only
115 offset uintptr
116 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
117 tagbuf [8]byte
Rob Pike97e934d2011-04-11 12:52:49 -0700118 stype reflect.Type
Rob Pikeaaa3a622010-03-20 22:32:34 -0700119
120 dec decoder
121 valDec valueDecoder // set for bool and numeric types only
122 scratch uintptr
David Symonds39f27f42011-07-01 11:30:07 +1000123 sizeof uintptr // calculations of scratch space
124 alignof uintptr
David Symonds5b7775e2010-12-01 10:09:04 +1100125
126 // If this is a packable field, this will be the decoder for the packed version of the field.
127 packedDec decoder
Rob Pikeaaa3a622010-03-20 22:32:34 -0700128}
129
David Symonds8935abf2011-07-04 15:53:16 +1000130// String formats the properties in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700131func (p *Properties) String() string {
132 s := p.Wire
133 s = ","
134 s += strconv.Itoa(p.Tag)
135 if p.Required {
136 s += ",req"
137 }
138 if p.Optional {
139 s += ",opt"
140 }
141 if p.Repeated {
142 s += ",rep"
143 }
David Symonds5b7775e2010-12-01 10:09:04 +1100144 if p.Packed {
145 s += ",packed"
146 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700147 if p.OrigName != p.Name {
148 s += ",name=" + p.OrigName
149 }
150 if len(p.Enum) > 0 {
151 s += ",enum=" + p.Enum
152 }
153 if len(p.Default) > 0 {
154 s += ",def=" + p.Default
155 }
156 return s
157}
158
David Symonds8935abf2011-07-04 15:53:16 +1000159// Parse populates p by parsing a string in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160func (p *Properties) Parse(s string) {
161 // "bytes,49,opt,def=hello!,name=foo"
David Symonds8935abf2011-07-04 15:53:16 +1000162 fields := strings.Split(s, ",") // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700163 if len(fields) < 2 {
164 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
165 return
166 }
167
168 p.Wire = fields[0]
169 switch p.Wire {
170 case "varint":
171 p.WireType = WireVarint
172 p.valEnc = (*Buffer).EncodeVarint
173 p.valDec = (*Buffer).DecodeVarint
174 case "fixed32":
175 p.WireType = WireFixed32
176 p.valEnc = (*Buffer).EncodeFixed32
177 p.valDec = (*Buffer).DecodeFixed32
178 case "fixed64":
179 p.WireType = WireFixed64
180 p.valEnc = (*Buffer).EncodeFixed64
181 p.valDec = (*Buffer).DecodeFixed64
182 case "zigzag32":
183 p.WireType = WireVarint
184 p.valEnc = (*Buffer).EncodeZigzag32
185 p.valDec = (*Buffer).DecodeZigzag32
186 case "zigzag64":
187 p.WireType = WireVarint
188 p.valEnc = (*Buffer).EncodeZigzag64
189 p.valDec = (*Buffer).DecodeZigzag64
190 case "bytes", "group":
191 p.WireType = WireBytes
192 // no numeric converter for non-numeric types
193 default:
194 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
195 return
196 }
197
198 var err os.Error
199 p.Tag, err = strconv.Atoi(fields[1])
200 if err != nil {
201 return
202 }
203
204 for i := 2; i < len(fields); i++ {
205 f := fields[i]
206 switch {
207 case f == "req":
208 p.Required = true
209 case f == "opt":
210 p.Optional = true
211 case f == "rep":
212 p.Repeated = true
David Symonds5b7775e2010-12-01 10:09:04 +1100213 case f == "packed":
214 p.Packed = true
Rob Pikeaaa3a622010-03-20 22:32:34 -0700215 case len(f) >= 5 && f[0:5] == "name=":
216 p.OrigName = f[5:len(f)]
217 case len(f) >= 5 && f[0:5] == "enum=":
218 p.Enum = f[5:len(f)]
219 case len(f) >= 4 && f[0:4] == "def=":
220 p.Default = f[4:len(f)] // rest of string
221 if i+1 < len(fields) {
222 // Commas aren't escaped, and def is always last.
223 p.Default += "," + strings.Join(fields[i+1:len(fields)], ",")
224 break
225 }
226 }
227 }
228}
229
David Symonds5922d072011-06-22 15:48:09 +1000230func logNoSliceEnc(t1, t2 reflect.Type) {
231 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
232}
233
Rob Pikeaaa3a622010-03-20 22:32:34 -0700234// Initialize the fields for encoding and decoding.
235func (p *Properties) setEncAndDec(typ reflect.Type) {
236 var vbool bool
237 var vbyte byte
238 var vint32 int32
239 var vint64 int64
240 var vfloat32 float32
241 var vfloat64 float64
242 var vstring string
243 var vslice []byte
244
245 p.enc = nil
246 p.dec = nil
247
Rob Pike97e934d2011-04-11 12:52:49 -0700248 switch t1 := typ; t1.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700249 default:
250 fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
251 break
252
Rob Pike97e934d2011-04-11 12:52:49 -0700253 case reflect.Ptr:
254 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700255 default:
256 fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
257 break
Rob Pike97e934d2011-04-11 12:52:49 -0700258 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700259 p.enc = (*Buffer).enc_bool
260 p.dec = (*Buffer).dec_bool
261 p.alignof = unsafe.Alignof(vbool)
262 p.sizeof = unsafe.Sizeof(vbool)
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700263 case reflect.Int32, reflect.Uint32:
264 p.enc = (*Buffer).enc_int32
265 p.dec = (*Buffer).dec_int32
266 p.alignof = unsafe.Alignof(vint32)
267 p.sizeof = unsafe.Sizeof(vint32)
268 case reflect.Int64, reflect.Uint64:
269 p.enc = (*Buffer).enc_int64
270 p.dec = (*Buffer).dec_int64
271 p.alignof = unsafe.Alignof(vint64)
272 p.sizeof = unsafe.Sizeof(vint64)
273 case reflect.Float32:
274 p.enc = (*Buffer).enc_int32 // can just treat them as bits
275 p.dec = (*Buffer).dec_int32
276 p.alignof = unsafe.Alignof(vfloat32)
277 p.sizeof = unsafe.Sizeof(vfloat32)
278 case reflect.Float64:
279 p.enc = (*Buffer).enc_int64 // can just treat them as bits
280 p.dec = (*Buffer).dec_int64
281 p.alignof = unsafe.Alignof(vfloat64)
282 p.sizeof = unsafe.Sizeof(vfloat64)
Rob Pike97e934d2011-04-11 12:52:49 -0700283 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700284 p.enc = (*Buffer).enc_string
285 p.dec = (*Buffer).dec_string
286 p.alignof = unsafe.Alignof(vstring)
287 p.sizeof = unsafe.Sizeof(vstring) + startSize*unsafe.Sizeof(vbyte)
Rob Pike97e934d2011-04-11 12:52:49 -0700288 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700289 p.stype = t1
290 if p.Wire == "bytes" {
291 p.enc = (*Buffer).enc_struct_message
292 p.dec = (*Buffer).dec_struct_message
293 } else {
294 p.enc = (*Buffer).enc_struct_group
295 p.dec = (*Buffer).dec_struct_group
296 }
297 }
298
Rob Pike97e934d2011-04-11 12:52:49 -0700299 case reflect.Slice:
300 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700301 default:
David Symonds5922d072011-06-22 15:48:09 +1000302 logNoSliceEnc(t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700303 break
Rob Pike97e934d2011-04-11 12:52:49 -0700304 case reflect.Bool:
David Symonds5b7775e2010-12-01 10:09:04 +1100305 if p.Packed {
306 p.enc = (*Buffer).enc_slice_packed_bool
307 } else {
308 p.enc = (*Buffer).enc_slice_bool
309 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700310 p.dec = (*Buffer).dec_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100311 p.packedDec = (*Buffer).dec_slice_packed_bool
Rob Pikeaaa3a622010-03-20 22:32:34 -0700312 p.alignof = unsafe.Alignof(vbool)
313 p.sizeof = startSize * unsafe.Sizeof(vbool)
Rob Pike97e934d2011-04-11 12:52:49 -0700314 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
Rob Pikeab5b8022010-06-21 17:47:58 -0700315 switch t2.Bits() {
316 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100317 if p.Packed {
318 p.enc = (*Buffer).enc_slice_packed_int32
319 } else {
320 p.enc = (*Buffer).enc_slice_int32
321 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700322 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100323 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700324 p.alignof = unsafe.Alignof(vint32)
325 p.sizeof = startSize * unsafe.Sizeof(vint32)
326 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100327 if p.Packed {
328 p.enc = (*Buffer).enc_slice_packed_int64
329 } else {
330 p.enc = (*Buffer).enc_slice_int64
331 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700332 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100333 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700334 p.alignof = unsafe.Alignof(vint64)
335 p.sizeof = startSize * unsafe.Sizeof(vint64)
336 case 8:
337 if t2.Kind() == reflect.Uint8 {
338 p.enc = (*Buffer).enc_slice_byte
339 p.dec = (*Buffer).dec_slice_byte
340 p.alignof = unsafe.Alignof(vbyte)
341 p.sizeof = startSize * unsafe.Sizeof(vbyte)
342 }
343 default:
David Symonds5922d072011-06-22 15:48:09 +1000344 logNoSliceEnc(t1, t2)
345 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700346 }
Rob Pike97e934d2011-04-11 12:52:49 -0700347 case reflect.Float32, reflect.Float64:
Rob Pikeab5b8022010-06-21 17:47:58 -0700348 switch t2.Bits() {
349 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100350 // can just treat them as bits
351 if p.Packed {
352 p.enc = (*Buffer).enc_slice_packed_int32
353 } else {
354 p.enc = (*Buffer).enc_slice_int32
355 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700356 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100357 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700358 p.alignof = unsafe.Alignof(vfloat32)
359 p.sizeof = startSize * unsafe.Sizeof(vfloat32)
360 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100361 // can just treat them as bits
362 if p.Packed {
363 p.enc = (*Buffer).enc_slice_packed_int64
364 } else {
365 p.enc = (*Buffer).enc_slice_int64
366 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700367 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100368 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700369 p.alignof = unsafe.Alignof(vfloat64)
370 p.sizeof = startSize * unsafe.Sizeof(vfloat64)
371 default:
David Symonds5922d072011-06-22 15:48:09 +1000372 logNoSliceEnc(t1, t2)
373 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700374 }
Rob Pike97e934d2011-04-11 12:52:49 -0700375 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700376 p.enc = (*Buffer).enc_slice_string
377 p.dec = (*Buffer).dec_slice_string
378 p.alignof = unsafe.Alignof(vstring)
379 p.sizeof = startSize * unsafe.Sizeof(vstring)
Rob Pike97e934d2011-04-11 12:52:49 -0700380 case reflect.Ptr:
381 switch t3 := t2.Elem(); t3.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700382 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700383 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700384 break
Rob Pike97e934d2011-04-11 12:52:49 -0700385 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700386 p.stype = t2
387 p.enc = (*Buffer).enc_slice_struct_group
388 p.dec = (*Buffer).dec_slice_struct_group
389 if p.Wire == "bytes" {
390 p.enc = (*Buffer).enc_slice_struct_message
391 p.dec = (*Buffer).dec_slice_struct_message
392 }
393 p.alignof = unsafe.Alignof(vslice)
394 p.sizeof = startSize * unsafe.Sizeof(vslice)
395 }
Rob Pike97e934d2011-04-11 12:52:49 -0700396 case reflect.Slice:
Rob Pikeab5b8022010-06-21 17:47:58 -0700397 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700398 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700399 fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700400 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700401 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700402 p.enc = (*Buffer).enc_slice_slice_byte
403 p.dec = (*Buffer).dec_slice_slice_byte
404 p.alignof = unsafe.Alignof(vslice)
405 p.sizeof = startSize * unsafe.Sizeof(vslice)
406 }
407 }
408 }
409
410 // precalculate tag code
David Symonds5b7775e2010-12-01 10:09:04 +1100411 wire := p.WireType
412 if p.Packed {
413 wire = WireBytes
414 }
David Symondsd73d7b12011-09-28 10:56:43 -0700415 x := uint32(p.Tag)<<3 | uint32(wire)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700416 i := 0
417 for i = 0; x > 127; i++ {
418 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
419 x >>= 7
420 }
421 p.tagbuf[i] = uint8(x)
422 p.tagcode = p.tagbuf[0 : i+1]
423}
424
David Symonds8935abf2011-07-04 15:53:16 +1000425// Init populates the properties from a protocol buffer struct tag.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700426func (p *Properties) Init(typ reflect.Type, name, tag string, offset uintptr) {
David Symonds8935abf2011-07-04 15:53:16 +1000427 // "bytes,49,opt,def=hello!"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700428 p.Name = name
429 p.OrigName = name
430 p.offset = offset
431
David Symonds8935abf2011-07-04 15:53:16 +1000432 if tag == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700433 return
434 }
David Symonds8935abf2011-07-04 15:53:16 +1000435 p.Parse(tag)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700436 p.setEncAndDec(typ)
437}
438
439var (
440 mutex sync.Mutex
Rob Pike97e934d2011-04-11 12:52:49 -0700441 propertiesMap = make(map[reflect.Type]*StructProperties)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700442)
443
444// GetProperties returns the list of properties for the type represented by t.
Rob Pike97e934d2011-04-11 12:52:49 -0700445func GetProperties(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700446 mutex.Lock()
447 if prop, ok := propertiesMap[t]; ok {
448 mutex.Unlock()
449 stats.Chit++
450 return prop
451 }
452 stats.Cmiss++
453
454 prop := new(StructProperties)
455
456 // build properties
457 prop.Prop = make([]*Properties, t.NumField())
David Symondsd15e81b2011-10-03 14:31:12 -0700458 prop.order = make([]int, t.NumField())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700459 for i := 0; i < t.NumField(); i++ {
460 f := t.Field(i)
461 p := new(Properties)
David Symonds8935abf2011-07-04 15:53:16 +1000462 p.Init(f.Type, f.Name, f.Tag.Get("protobuf"), f.Offset)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700463 if f.Name == "XXX_extensions" { // special case
464 var vmap map[int32][]byte
465 p.enc = (*Buffer).enc_map
466 p.dec = nil // not needed
467 p.alignof = unsafe.Alignof(vmap)
468 p.sizeof = unsafe.Sizeof(vmap)
469 }
470 prop.Prop[i] = p
David Symondsd15e81b2011-10-03 14:31:12 -0700471 prop.order[i] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700472 if debug {
473 print(i, " ", f.Name, " ", t.String(), " ")
474 if p.Tag > 0 {
475 print(p.String())
476 }
477 print("\n")
478 }
479 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
480 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
481 }
482 }
483
David Symondsd15e81b2011-10-03 14:31:12 -0700484 // Re-order prop.order.
485 sort.Sort(prop)
486
Rob Pikeaaa3a622010-03-20 22:32:34 -0700487 // build required counts
488 // build scratch offsets
489 // build tags
490 reqCount := 0
491 scratch := uintptr(0)
492 prop.tags = make(map[int]int)
David Symondsd15e81b2011-10-03 14:31:12 -0700493 prop.origNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700494 for i, p := range prop.Prop {
495 if p.Required {
496 reqCount++
497 }
498 scratch = align(scratch, p.alignof)
499 p.scratch = scratch
David Symonds39f27f42011-07-01 11:30:07 +1000500 scratch += p.sizeof
Rob Pikeaaa3a622010-03-20 22:32:34 -0700501 prop.tags[p.Tag] = i
David Symondsd15e81b2011-10-03 14:31:12 -0700502 prop.origNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700503 }
504 prop.reqCount = reqCount
505 prop.nscratch = scratch
506
507 propertiesMap[t] = prop
508 mutex.Unlock()
509 return prop
510}
511
512// Alignment of the data in the scratch area. It doesn't have to be
513// exact, just conservative. Returns the first number >= o that divides s.
David Symonds39f27f42011-07-01 11:30:07 +1000514func align(o uintptr, s uintptr) uintptr {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700515 if s != 0 {
516 for o%uintptr(s) != 0 {
517 o++
518 }
519 }
520 return o
521}
522
523// Return the field index of the named field.
524// Returns nil if there is no such field.
Rob Pike97e934d2011-04-11 12:52:49 -0700525func fieldIndex(t reflect.Type, name string) []int {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700526 if field, ok := t.FieldByName(name); ok {
527 return field.Index
528 }
529 return nil
530}
531
532// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700533func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700534 if len(x) != 1 {
535 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
536 return nil
537 }
538 prop := GetProperties(t)
539 return prop.Prop[x[0]]
540}
541
David Symonds7656e742011-07-22 14:54:17 +1000542// Get the address and type of a pointer to a struct from an interface.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700543// unsafe.Reflect can do this, but does multiple mallocs.
Rob Pike97e934d2011-04-11 12:52:49 -0700544func getbase(pb interface{}) (t reflect.Type, b uintptr, err os.Error) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700545 // get pointer
546 x := *(*[2]uintptr)(unsafe.Pointer(&pb))
547 b = x[1]
548 if b == 0 {
549 err = ErrNil
550 return
551 }
552
553 // get the reflect type of the struct.
Nigel Tao4ede8452011-04-28 11:27:25 +1000554 t = reflect.TypeOf(pb)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700555 return
556}
557
558// Allocate the aux space containing all the decoded data. The structure
559// handed into Unmarshal is filled with pointers to this newly allocated
560// data.
561func getsbase(prop *StructProperties) uintptr {
562 var vbyteptr *byte
563 if prop.nscratch == 0 {
564 return 0
565 }
566
567 // allocate the decode space as pointers
568 // so that the GC will scan it for pointers
569 n := uintptr(unsafe.Sizeof(vbyteptr))
570 b := make([]*byte, (prop.nscratch+n-1)/n)
571 sbase := uintptr(unsafe.Pointer(&b[0]))
572 return sbase
573}
574
575// A global registry of enum types.
576// The generated code will register the generated maps by calling RegisterEnum.
577
578var enumNameMaps = make(map[string]map[int32]string)
579var enumValueMaps = make(map[string]map[string]int32)
580
581// RegisterEnum is called from the generated code to install the enum descriptor
582// maps into the global table to aid parsing ASCII protocol buffers.
583func RegisterEnum(typeName string, nameMap map[int32]string, valueMap map[string]int32) {
584 if _, ok := enumNameMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700585 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700586 }
587 enumNameMaps[typeName] = nameMap
588 enumValueMaps[typeName] = valueMap
589}