blob: bc0101c4a1b6772f8c0b005cf8b18058bea50580 [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"
Rob Pikeaaa3a622010-03-20 22:32:34 -070042 "strconv"
43 "strings"
44 "sync"
45 "unsafe"
46)
47
48const debug bool = false
49
50// Constants that identify the encoding of a value on the wire.
51const (
52 WireVarint = 0
53 WireFixed64 = 1
54 WireBytes = 2
55 WireStartGroup = 3
56 WireEndGroup = 4
57 WireFixed32 = 5
58)
59
60const startSize = 10 // initial slice/string sizes
61
62// Encoders are defined in encoder.go
63// An encoder outputs the full representation of a field, including its
64// tag and encoder type.
65type encoder func(p *Buffer, prop *Properties, base uintptr) os.Error
66
67// A valueEncoder encodes a single integer in a particular encoding.
68type valueEncoder func(o *Buffer, x uint64) os.Error
69
70// Decoders are defined in decode.go
71// A decoder creates a value from its wire representation.
72// Unrecognized subelements are saved in unrec.
73type decoder func(p *Buffer, prop *Properties, base uintptr, sbase uintptr) os.Error
74
75// A valueDecoder decodes a single integer in a particular encoding.
76type valueDecoder func(o *Buffer) (x uint64, err os.Error)
77
78// StructProperties represents properties for all the fields of a struct.
79type StructProperties struct {
David Symonds79eae332010-10-16 11:33:20 +110080 Prop []*Properties // properties for each field
81 reqCount int // required count
82 tags map[int]int // map from proto tag to struct field number
83 origNames map[string]int // map from original name to struct field number
84 nscratch uintptr // size of scratch space
Rob Pikeaaa3a622010-03-20 22:32:34 -070085}
86
87// Properties represents the protocol-specific behavior of a single struct field.
88type Properties struct {
89 Name string // name of the field, for error messages
90 OrigName string // original name before protocol compiler (always set)
91 Wire string
92 WireType int
93 Tag int
94 Required bool
95 Optional bool
96 Repeated bool
David Symonds5b7775e2010-12-01 10:09:04 +110097 Packed bool // relevant for repeated primitives only
Rob Pikeaaa3a622010-03-20 22:32:34 -070098 Enum string // set for enum types only
99 Default string // default value
100 def_uint64 uint64
101
102 enc encoder
103 valEnc valueEncoder // set for bool and numeric types only
104 offset uintptr
105 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
106 tagbuf [8]byte
Rob Pike97e934d2011-04-11 12:52:49 -0700107 stype reflect.Type
Rob Pikeaaa3a622010-03-20 22:32:34 -0700108
109 dec decoder
110 valDec valueDecoder // set for bool and numeric types only
111 scratch uintptr
112 sizeof int // calculations of scratch space
113 alignof int
David Symonds5b7775e2010-12-01 10:09:04 +1100114
115 // If this is a packable field, this will be the decoder for the packed version of the field.
116 packedDec decoder
Rob Pikeaaa3a622010-03-20 22:32:34 -0700117}
118
119// String formats the properties in the "PB(...)" struct tag style.
120func (p *Properties) String() string {
121 s := p.Wire
122 s = ","
123 s += strconv.Itoa(p.Tag)
124 if p.Required {
125 s += ",req"
126 }
127 if p.Optional {
128 s += ",opt"
129 }
130 if p.Repeated {
131 s += ",rep"
132 }
David Symonds5b7775e2010-12-01 10:09:04 +1100133 if p.Packed {
134 s += ",packed"
135 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700136 if p.OrigName != p.Name {
137 s += ",name=" + p.OrigName
138 }
139 if len(p.Enum) > 0 {
140 s += ",enum=" + p.Enum
141 }
142 if len(p.Default) > 0 {
143 s += ",def=" + p.Default
144 }
145 return s
146}
147
148// Parse populates p by parsing a string in the "PB(...)" struct tag style.
149func (p *Properties) Parse(s string) {
150 // "bytes,49,opt,def=hello!,name=foo"
Rob Pike53385442010-06-30 22:22:43 -0700151 fields := strings.Split(s, ",", -1) // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700152 if len(fields) < 2 {
153 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
154 return
155 }
156
157 p.Wire = fields[0]
158 switch p.Wire {
159 case "varint":
160 p.WireType = WireVarint
161 p.valEnc = (*Buffer).EncodeVarint
162 p.valDec = (*Buffer).DecodeVarint
163 case "fixed32":
164 p.WireType = WireFixed32
165 p.valEnc = (*Buffer).EncodeFixed32
166 p.valDec = (*Buffer).DecodeFixed32
167 case "fixed64":
168 p.WireType = WireFixed64
169 p.valEnc = (*Buffer).EncodeFixed64
170 p.valDec = (*Buffer).DecodeFixed64
171 case "zigzag32":
172 p.WireType = WireVarint
173 p.valEnc = (*Buffer).EncodeZigzag32
174 p.valDec = (*Buffer).DecodeZigzag32
175 case "zigzag64":
176 p.WireType = WireVarint
177 p.valEnc = (*Buffer).EncodeZigzag64
178 p.valDec = (*Buffer).DecodeZigzag64
179 case "bytes", "group":
180 p.WireType = WireBytes
181 // no numeric converter for non-numeric types
182 default:
183 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
184 return
185 }
186
187 var err os.Error
188 p.Tag, err = strconv.Atoi(fields[1])
189 if err != nil {
190 return
191 }
192
193 for i := 2; i < len(fields); i++ {
194 f := fields[i]
195 switch {
196 case f == "req":
197 p.Required = true
198 case f == "opt":
199 p.Optional = true
200 case f == "rep":
201 p.Repeated = true
David Symonds5b7775e2010-12-01 10:09:04 +1100202 case f == "packed":
203 p.Packed = true
Rob Pikeaaa3a622010-03-20 22:32:34 -0700204 case len(f) >= 5 && f[0:5] == "name=":
205 p.OrigName = f[5:len(f)]
206 case len(f) >= 5 && f[0:5] == "enum=":
207 p.Enum = f[5:len(f)]
208 case len(f) >= 4 && f[0:4] == "def=":
209 p.Default = f[4:len(f)] // rest of string
210 if i+1 < len(fields) {
211 // Commas aren't escaped, and def is always last.
212 p.Default += "," + strings.Join(fields[i+1:len(fields)], ",")
213 break
214 }
215 }
216 }
217}
218
219// Initialize the fields for encoding and decoding.
220func (p *Properties) setEncAndDec(typ reflect.Type) {
221 var vbool bool
222 var vbyte byte
223 var vint32 int32
224 var vint64 int64
225 var vfloat32 float32
226 var vfloat64 float64
227 var vstring string
228 var vslice []byte
229
230 p.enc = nil
231 p.dec = nil
232
Rob Pike97e934d2011-04-11 12:52:49 -0700233 switch t1 := typ; t1.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700234 default:
235 fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
236 break
237
Rob Pike97e934d2011-04-11 12:52:49 -0700238 case reflect.Ptr:
239 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700240 default:
241 fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
242 break
Rob Pike97e934d2011-04-11 12:52:49 -0700243 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700244 p.enc = (*Buffer).enc_bool
245 p.dec = (*Buffer).dec_bool
246 p.alignof = unsafe.Alignof(vbool)
247 p.sizeof = unsafe.Sizeof(vbool)
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700248 case reflect.Int32, reflect.Uint32:
249 p.enc = (*Buffer).enc_int32
250 p.dec = (*Buffer).dec_int32
251 p.alignof = unsafe.Alignof(vint32)
252 p.sizeof = unsafe.Sizeof(vint32)
253 case reflect.Int64, reflect.Uint64:
254 p.enc = (*Buffer).enc_int64
255 p.dec = (*Buffer).dec_int64
256 p.alignof = unsafe.Alignof(vint64)
257 p.sizeof = unsafe.Sizeof(vint64)
258 case reflect.Float32:
259 p.enc = (*Buffer).enc_int32 // can just treat them as bits
260 p.dec = (*Buffer).dec_int32
261 p.alignof = unsafe.Alignof(vfloat32)
262 p.sizeof = unsafe.Sizeof(vfloat32)
263 case reflect.Float64:
264 p.enc = (*Buffer).enc_int64 // can just treat them as bits
265 p.dec = (*Buffer).dec_int64
266 p.alignof = unsafe.Alignof(vfloat64)
267 p.sizeof = unsafe.Sizeof(vfloat64)
Rob Pike97e934d2011-04-11 12:52:49 -0700268 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700269 p.enc = (*Buffer).enc_string
270 p.dec = (*Buffer).dec_string
271 p.alignof = unsafe.Alignof(vstring)
272 p.sizeof = unsafe.Sizeof(vstring) + startSize*unsafe.Sizeof(vbyte)
Rob Pike97e934d2011-04-11 12:52:49 -0700273 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700274 p.stype = t1
275 if p.Wire == "bytes" {
276 p.enc = (*Buffer).enc_struct_message
277 p.dec = (*Buffer).dec_struct_message
278 } else {
279 p.enc = (*Buffer).enc_struct_group
280 p.dec = (*Buffer).dec_struct_group
281 }
282 }
283
Rob Pike97e934d2011-04-11 12:52:49 -0700284 case reflect.Slice:
285 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700286 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700287 BadSliceType:
288 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700289 break
Rob Pike97e934d2011-04-11 12:52:49 -0700290 case reflect.Bool:
David Symonds5b7775e2010-12-01 10:09:04 +1100291 if p.Packed {
292 p.enc = (*Buffer).enc_slice_packed_bool
293 } else {
294 p.enc = (*Buffer).enc_slice_bool
295 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700296 p.dec = (*Buffer).dec_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100297 p.packedDec = (*Buffer).dec_slice_packed_bool
Rob Pikeaaa3a622010-03-20 22:32:34 -0700298 p.alignof = unsafe.Alignof(vbool)
299 p.sizeof = startSize * unsafe.Sizeof(vbool)
Rob Pike97e934d2011-04-11 12:52:49 -0700300 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 -0700301 switch t2.Bits() {
302 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100303 if p.Packed {
304 p.enc = (*Buffer).enc_slice_packed_int32
305 } else {
306 p.enc = (*Buffer).enc_slice_int32
307 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700308 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100309 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700310 p.alignof = unsafe.Alignof(vint32)
311 p.sizeof = startSize * unsafe.Sizeof(vint32)
312 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100313 if p.Packed {
314 p.enc = (*Buffer).enc_slice_packed_int64
315 } else {
316 p.enc = (*Buffer).enc_slice_int64
317 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700318 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100319 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700320 p.alignof = unsafe.Alignof(vint64)
321 p.sizeof = startSize * unsafe.Sizeof(vint64)
322 case 8:
323 if t2.Kind() == reflect.Uint8 {
324 p.enc = (*Buffer).enc_slice_byte
325 p.dec = (*Buffer).dec_slice_byte
326 p.alignof = unsafe.Alignof(vbyte)
327 p.sizeof = startSize * unsafe.Sizeof(vbyte)
328 }
329 default:
330 goto BadSliceType
331 }
Rob Pike97e934d2011-04-11 12:52:49 -0700332 case reflect.Float32, reflect.Float64:
Rob Pikeab5b8022010-06-21 17:47:58 -0700333 switch t2.Bits() {
334 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100335 // can just treat them as bits
336 if p.Packed {
337 p.enc = (*Buffer).enc_slice_packed_int32
338 } else {
339 p.enc = (*Buffer).enc_slice_int32
340 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700341 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100342 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700343 p.alignof = unsafe.Alignof(vfloat32)
344 p.sizeof = startSize * unsafe.Sizeof(vfloat32)
345 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100346 // can just treat them as bits
347 if p.Packed {
348 p.enc = (*Buffer).enc_slice_packed_int64
349 } else {
350 p.enc = (*Buffer).enc_slice_int64
351 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700352 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100353 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700354 p.alignof = unsafe.Alignof(vfloat64)
355 p.sizeof = startSize * unsafe.Sizeof(vfloat64)
356 default:
357 goto BadSliceType
358 }
Rob Pike97e934d2011-04-11 12:52:49 -0700359 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700360 p.enc = (*Buffer).enc_slice_string
361 p.dec = (*Buffer).dec_slice_string
362 p.alignof = unsafe.Alignof(vstring)
363 p.sizeof = startSize * unsafe.Sizeof(vstring)
Rob Pike97e934d2011-04-11 12:52:49 -0700364 case reflect.Ptr:
365 switch t3 := t2.Elem(); t3.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700366 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700367 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700368 break
Rob Pike97e934d2011-04-11 12:52:49 -0700369 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700370 p.stype = t2
371 p.enc = (*Buffer).enc_slice_struct_group
372 p.dec = (*Buffer).dec_slice_struct_group
373 if p.Wire == "bytes" {
374 p.enc = (*Buffer).enc_slice_struct_message
375 p.dec = (*Buffer).dec_slice_struct_message
376 }
377 p.alignof = unsafe.Alignof(vslice)
378 p.sizeof = startSize * unsafe.Sizeof(vslice)
379 }
Rob Pike97e934d2011-04-11 12:52:49 -0700380 case reflect.Slice:
Rob Pikeab5b8022010-06-21 17:47:58 -0700381 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700382 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700383 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 -0700384 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700385 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700386 p.enc = (*Buffer).enc_slice_slice_byte
387 p.dec = (*Buffer).dec_slice_slice_byte
388 p.alignof = unsafe.Alignof(vslice)
389 p.sizeof = startSize * unsafe.Sizeof(vslice)
390 }
391 }
392 }
393
394 // precalculate tag code
David Symonds5b7775e2010-12-01 10:09:04 +1100395 wire := p.WireType
396 if p.Packed {
397 wire = WireBytes
398 }
399 x := p.Tag<<3 | wire
Rob Pikeaaa3a622010-03-20 22:32:34 -0700400 i := 0
401 for i = 0; x > 127; i++ {
402 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
403 x >>= 7
404 }
405 p.tagbuf[i] = uint8(x)
406 p.tagcode = p.tagbuf[0 : i+1]
407}
408
409// Init populates the properties from a protocol buffer struct field.
410func (p *Properties) Init(typ reflect.Type, name, tag string, offset uintptr) {
411 // "PB(bytes,49,opt,def=hello!)"
412 // TODO: should not assume the only thing is PB(...)
413 p.Name = name
414 p.OrigName = name
415 p.offset = offset
416
417 if len(tag) < 4 || tag[0:3] != "PB(" || tag[len(tag)-1] != ')' {
418 return
419 }
420 p.Parse(tag[3 : len(tag)-1])
421 p.setEncAndDec(typ)
422}
423
424var (
425 mutex sync.Mutex
Rob Pike97e934d2011-04-11 12:52:49 -0700426 propertiesMap = make(map[reflect.Type]*StructProperties)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700427)
428
429// GetProperties returns the list of properties for the type represented by t.
Rob Pike97e934d2011-04-11 12:52:49 -0700430func GetProperties(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700431 mutex.Lock()
432 if prop, ok := propertiesMap[t]; ok {
433 mutex.Unlock()
434 stats.Chit++
435 return prop
436 }
437 stats.Cmiss++
438
439 prop := new(StructProperties)
440
441 // build properties
442 prop.Prop = make([]*Properties, t.NumField())
David Symonds79eae332010-10-16 11:33:20 +1100443 prop.origNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700444 for i := 0; i < t.NumField(); i++ {
445 f := t.Field(i)
446 p := new(Properties)
447 p.Init(f.Type, f.Name, f.Tag, f.Offset)
448 if f.Name == "XXX_extensions" { // special case
449 var vmap map[int32][]byte
450 p.enc = (*Buffer).enc_map
451 p.dec = nil // not needed
452 p.alignof = unsafe.Alignof(vmap)
453 p.sizeof = unsafe.Sizeof(vmap)
454 }
455 prop.Prop[i] = p
David Symonds79eae332010-10-16 11:33:20 +1100456 prop.origNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700457 if debug {
458 print(i, " ", f.Name, " ", t.String(), " ")
459 if p.Tag > 0 {
460 print(p.String())
461 }
462 print("\n")
463 }
464 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
465 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
466 }
467 }
468
469 // build required counts
470 // build scratch offsets
471 // build tags
472 reqCount := 0
473 scratch := uintptr(0)
474 prop.tags = make(map[int]int)
475 for i, p := range prop.Prop {
476 if p.Required {
477 reqCount++
478 }
479 scratch = align(scratch, p.alignof)
480 p.scratch = scratch
481 scratch += uintptr(p.sizeof)
482 prop.tags[p.Tag] = i
483 }
484 prop.reqCount = reqCount
485 prop.nscratch = scratch
486
487 propertiesMap[t] = prop
488 mutex.Unlock()
489 return prop
490}
491
492// Alignment of the data in the scratch area. It doesn't have to be
493// exact, just conservative. Returns the first number >= o that divides s.
494func align(o uintptr, s int) uintptr {
495 if s != 0 {
496 for o%uintptr(s) != 0 {
497 o++
498 }
499 }
500 return o
501}
502
503// Return the field index of the named field.
504// Returns nil if there is no such field.
Rob Pike97e934d2011-04-11 12:52:49 -0700505func fieldIndex(t reflect.Type, name string) []int {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700506 if field, ok := t.FieldByName(name); ok {
507 return field.Index
508 }
509 return nil
510}
511
512// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700513func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700514 if len(x) != 1 {
515 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
516 return nil
517 }
518 prop := GetProperties(t)
519 return prop.Prop[x[0]]
520}
521
522// Get the address and type of a pointer to the structure from an interface.
523// unsafe.Reflect can do this, but does multiple mallocs.
Rob Pike97e934d2011-04-11 12:52:49 -0700524func getbase(pb interface{}) (t reflect.Type, b uintptr, err os.Error) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700525 // get pointer
526 x := *(*[2]uintptr)(unsafe.Pointer(&pb))
527 b = x[1]
528 if b == 0 {
529 err = ErrNil
530 return
531 }
532
533 // get the reflect type of the struct.
Rob Pike97e934d2011-04-11 12:52:49 -0700534 t = reflect.Typeof(pb)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700535 return
536}
537
538// Allocate the aux space containing all the decoded data. The structure
539// handed into Unmarshal is filled with pointers to this newly allocated
540// data.
541func getsbase(prop *StructProperties) uintptr {
542 var vbyteptr *byte
543 if prop.nscratch == 0 {
544 return 0
545 }
546
547 // allocate the decode space as pointers
548 // so that the GC will scan it for pointers
549 n := uintptr(unsafe.Sizeof(vbyteptr))
550 b := make([]*byte, (prop.nscratch+n-1)/n)
551 sbase := uintptr(unsafe.Pointer(&b[0]))
552 return sbase
553}
554
555// A global registry of enum types.
556// The generated code will register the generated maps by calling RegisterEnum.
557
558var enumNameMaps = make(map[string]map[int32]string)
559var enumValueMaps = make(map[string]map[string]int32)
560
561// RegisterEnum is called from the generated code to install the enum descriptor
562// maps into the global table to aid parsing ASCII protocol buffers.
563func RegisterEnum(typeName string, nameMap map[int32]string, valueMap map[string]int32) {
564 if _, ok := enumNameMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700565 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700566 }
567 enumNameMaps[typeName] = nameMap
568 enumValueMaps[typeName] = valueMap
569}