blob: e74674da1868caeb7b4417c452c9afbf4198deba [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"
Rob Pikeaaa3a622010-03-20 22:32:34 -070046)
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.
Rob Pike76f6ee52011-10-20 12:58:28 -070073type decoder func(p *Buffer, prop *Properties, base uintptr) os.Error
Rob Pikeaaa3a622010-03-20 22:32:34 -070074
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
David Symondsd15e81b2011-10-03 14:31:12 -070084 order []int // list of struct field numbers in tag order
Rob Pikeaaa3a622010-03-20 22:32:34 -070085}
86
David Symondsd15e81b2011-10-03 14:31:12 -070087// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
88// See encoder.go, (*Buffer).enc_struct.
89
90func (sp *StructProperties) Len() int { return len(sp.order) }
91func (sp *StructProperties) Less(i, j int) bool {
92 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
93}
94func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
95
Rob Pikeaaa3a622010-03-20 22:32:34 -070096// Properties represents the protocol-specific behavior of a single struct field.
97type Properties struct {
98 Name string // name of the field, for error messages
99 OrigName string // original name before protocol compiler (always set)
100 Wire string
101 WireType int
102 Tag int
103 Required bool
104 Optional bool
105 Repeated bool
David Symonds5b7775e2010-12-01 10:09:04 +1100106 Packed bool // relevant for repeated primitives only
Rob Pikeaaa3a622010-03-20 22:32:34 -0700107 Enum string // set for enum types only
108 Default string // default value
109 def_uint64 uint64
110
111 enc encoder
112 valEnc valueEncoder // set for bool and numeric types only
113 offset uintptr
114 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
115 tagbuf [8]byte
Rob Pike97e934d2011-04-11 12:52:49 -0700116 stype reflect.Type
Rob Pikeaaa3a622010-03-20 22:32:34 -0700117
Rob Pikef1b341e2011-10-20 14:51:10 -0700118 dec decoder
119 valDec valueDecoder // set for bool and numeric types only
David Symonds5b7775e2010-12-01 10:09:04 +1100120
121 // If this is a packable field, this will be the decoder for the packed version of the field.
122 packedDec decoder
Rob Pikeaaa3a622010-03-20 22:32:34 -0700123}
124
David Symonds8935abf2011-07-04 15:53:16 +1000125// String formats the properties in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700126func (p *Properties) String() string {
127 s := p.Wire
128 s = ","
129 s += strconv.Itoa(p.Tag)
130 if p.Required {
131 s += ",req"
132 }
133 if p.Optional {
134 s += ",opt"
135 }
136 if p.Repeated {
137 s += ",rep"
138 }
David Symonds5b7775e2010-12-01 10:09:04 +1100139 if p.Packed {
140 s += ",packed"
141 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700142 if p.OrigName != p.Name {
143 s += ",name=" + p.OrigName
144 }
145 if len(p.Enum) > 0 {
146 s += ",enum=" + p.Enum
147 }
148 if len(p.Default) > 0 {
149 s += ",def=" + p.Default
150 }
151 return s
152}
153
David Symonds8935abf2011-07-04 15:53:16 +1000154// Parse populates p by parsing a string in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700155func (p *Properties) Parse(s string) {
156 // "bytes,49,opt,def=hello!,name=foo"
David Symonds8935abf2011-07-04 15:53:16 +1000157 fields := strings.Split(s, ",") // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700158 if len(fields) < 2 {
159 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
160 return
161 }
162
163 p.Wire = fields[0]
164 switch p.Wire {
165 case "varint":
166 p.WireType = WireVarint
167 p.valEnc = (*Buffer).EncodeVarint
168 p.valDec = (*Buffer).DecodeVarint
169 case "fixed32":
170 p.WireType = WireFixed32
171 p.valEnc = (*Buffer).EncodeFixed32
172 p.valDec = (*Buffer).DecodeFixed32
173 case "fixed64":
174 p.WireType = WireFixed64
175 p.valEnc = (*Buffer).EncodeFixed64
176 p.valDec = (*Buffer).DecodeFixed64
177 case "zigzag32":
178 p.WireType = WireVarint
179 p.valEnc = (*Buffer).EncodeZigzag32
180 p.valDec = (*Buffer).DecodeZigzag32
181 case "zigzag64":
182 p.WireType = WireVarint
183 p.valEnc = (*Buffer).EncodeZigzag64
184 p.valDec = (*Buffer).DecodeZigzag64
185 case "bytes", "group":
186 p.WireType = WireBytes
187 // no numeric converter for non-numeric types
188 default:
189 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
190 return
191 }
192
193 var err os.Error
194 p.Tag, err = strconv.Atoi(fields[1])
195 if err != nil {
196 return
197 }
198
199 for i := 2; i < len(fields); i++ {
200 f := fields[i]
201 switch {
202 case f == "req":
203 p.Required = true
204 case f == "opt":
205 p.Optional = true
206 case f == "rep":
207 p.Repeated = true
David Symonds5b7775e2010-12-01 10:09:04 +1100208 case f == "packed":
209 p.Packed = true
Rob Pikeaaa3a622010-03-20 22:32:34 -0700210 case len(f) >= 5 && f[0:5] == "name=":
211 p.OrigName = f[5:len(f)]
212 case len(f) >= 5 && f[0:5] == "enum=":
213 p.Enum = f[5:len(f)]
214 case len(f) >= 4 && f[0:4] == "def=":
215 p.Default = f[4:len(f)] // rest of string
216 if i+1 < len(fields) {
217 // Commas aren't escaped, and def is always last.
218 p.Default += "," + strings.Join(fields[i+1:len(fields)], ",")
219 break
220 }
221 }
222 }
223}
224
David Symonds5922d072011-06-22 15:48:09 +1000225func logNoSliceEnc(t1, t2 reflect.Type) {
226 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
227}
228
Rob Pikeaaa3a622010-03-20 22:32:34 -0700229// Initialize the fields for encoding and decoding.
230func (p *Properties) setEncAndDec(typ reflect.Type) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700231 p.enc = nil
232 p.dec = nil
233
Rob Pike97e934d2011-04-11 12:52:49 -0700234 switch t1 := typ; t1.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700235 default:
236 fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
237 break
238
Rob Pike97e934d2011-04-11 12:52:49 -0700239 case reflect.Ptr:
240 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700241 default:
242 fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
243 break
Rob Pike97e934d2011-04-11 12:52:49 -0700244 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700245 p.enc = (*Buffer).enc_bool
246 p.dec = (*Buffer).dec_bool
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700247 case reflect.Int32, reflect.Uint32:
248 p.enc = (*Buffer).enc_int32
249 p.dec = (*Buffer).dec_int32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700250 case reflect.Int64, reflect.Uint64:
251 p.enc = (*Buffer).enc_int64
252 p.dec = (*Buffer).dec_int64
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700253 case reflect.Float32:
254 p.enc = (*Buffer).enc_int32 // can just treat them as bits
255 p.dec = (*Buffer).dec_int32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700256 case reflect.Float64:
257 p.enc = (*Buffer).enc_int64 // can just treat them as bits
258 p.dec = (*Buffer).dec_int64
Rob Pike97e934d2011-04-11 12:52:49 -0700259 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700260 p.enc = (*Buffer).enc_string
261 p.dec = (*Buffer).dec_string
Rob Pike97e934d2011-04-11 12:52:49 -0700262 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700263 p.stype = t1
264 if p.Wire == "bytes" {
265 p.enc = (*Buffer).enc_struct_message
266 p.dec = (*Buffer).dec_struct_message
267 } else {
268 p.enc = (*Buffer).enc_struct_group
269 p.dec = (*Buffer).dec_struct_group
270 }
271 }
272
Rob Pike97e934d2011-04-11 12:52:49 -0700273 case reflect.Slice:
274 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700275 default:
David Symonds5922d072011-06-22 15:48:09 +1000276 logNoSliceEnc(t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700277 break
Rob Pike97e934d2011-04-11 12:52:49 -0700278 case reflect.Bool:
David Symonds5b7775e2010-12-01 10:09:04 +1100279 if p.Packed {
280 p.enc = (*Buffer).enc_slice_packed_bool
281 } else {
282 p.enc = (*Buffer).enc_slice_bool
283 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700284 p.dec = (*Buffer).dec_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100285 p.packedDec = (*Buffer).dec_slice_packed_bool
Rob Pike97e934d2011-04-11 12:52:49 -0700286 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 -0700287 switch t2.Bits() {
288 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100289 if p.Packed {
290 p.enc = (*Buffer).enc_slice_packed_int32
291 } else {
292 p.enc = (*Buffer).enc_slice_int32
293 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700294 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100295 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700296 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100297 if p.Packed {
298 p.enc = (*Buffer).enc_slice_packed_int64
299 } else {
300 p.enc = (*Buffer).enc_slice_int64
301 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700302 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100303 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700304 case 8:
305 if t2.Kind() == reflect.Uint8 {
306 p.enc = (*Buffer).enc_slice_byte
307 p.dec = (*Buffer).dec_slice_byte
Rob Pikeab5b8022010-06-21 17:47:58 -0700308 }
309 default:
David Symonds5922d072011-06-22 15:48:09 +1000310 logNoSliceEnc(t1, t2)
311 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700312 }
Rob Pike97e934d2011-04-11 12:52:49 -0700313 case reflect.Float32, reflect.Float64:
Rob Pikeab5b8022010-06-21 17:47:58 -0700314 switch t2.Bits() {
315 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100316 // can just treat them as bits
317 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 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100325 // can just treat them as bits
326 if p.Packed {
327 p.enc = (*Buffer).enc_slice_packed_int64
328 } else {
329 p.enc = (*Buffer).enc_slice_int64
330 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700331 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100332 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700333 default:
David Symonds5922d072011-06-22 15:48:09 +1000334 logNoSliceEnc(t1, t2)
335 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700336 }
Rob Pike97e934d2011-04-11 12:52:49 -0700337 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700338 p.enc = (*Buffer).enc_slice_string
339 p.dec = (*Buffer).dec_slice_string
Rob Pike97e934d2011-04-11 12:52:49 -0700340 case reflect.Ptr:
341 switch t3 := t2.Elem(); t3.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700342 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700343 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700344 break
Rob Pike97e934d2011-04-11 12:52:49 -0700345 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700346 p.stype = t2
347 p.enc = (*Buffer).enc_slice_struct_group
348 p.dec = (*Buffer).dec_slice_struct_group
349 if p.Wire == "bytes" {
350 p.enc = (*Buffer).enc_slice_struct_message
351 p.dec = (*Buffer).dec_slice_struct_message
352 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700353 }
Rob Pike97e934d2011-04-11 12:52:49 -0700354 case reflect.Slice:
Rob Pikeab5b8022010-06-21 17:47:58 -0700355 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700356 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700357 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 -0700358 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700359 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700360 p.enc = (*Buffer).enc_slice_slice_byte
361 p.dec = (*Buffer).dec_slice_slice_byte
Rob Pikeaaa3a622010-03-20 22:32:34 -0700362 }
363 }
364 }
365
366 // precalculate tag code
David Symonds5b7775e2010-12-01 10:09:04 +1100367 wire := p.WireType
368 if p.Packed {
369 wire = WireBytes
370 }
David Symondsd73d7b12011-09-28 10:56:43 -0700371 x := uint32(p.Tag)<<3 | uint32(wire)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700372 i := 0
373 for i = 0; x > 127; i++ {
374 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
375 x >>= 7
376 }
377 p.tagbuf[i] = uint8(x)
378 p.tagcode = p.tagbuf[0 : i+1]
379}
380
David Symonds8935abf2011-07-04 15:53:16 +1000381// Init populates the properties from a protocol buffer struct tag.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700382func (p *Properties) Init(typ reflect.Type, name, tag string, offset uintptr) {
David Symonds8935abf2011-07-04 15:53:16 +1000383 // "bytes,49,opt,def=hello!"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700384 p.Name = name
385 p.OrigName = name
386 p.offset = offset
387
David Symonds8935abf2011-07-04 15:53:16 +1000388 if tag == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700389 return
390 }
David Symonds8935abf2011-07-04 15:53:16 +1000391 p.Parse(tag)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700392 p.setEncAndDec(typ)
393}
394
395var (
396 mutex sync.Mutex
Rob Pike97e934d2011-04-11 12:52:49 -0700397 propertiesMap = make(map[reflect.Type]*StructProperties)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700398)
399
400// GetProperties returns the list of properties for the type represented by t.
Rob Pike97e934d2011-04-11 12:52:49 -0700401func GetProperties(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700402 mutex.Lock()
403 if prop, ok := propertiesMap[t]; ok {
404 mutex.Unlock()
405 stats.Chit++
406 return prop
407 }
408 stats.Cmiss++
409
410 prop := new(StructProperties)
411
412 // build properties
413 prop.Prop = make([]*Properties, t.NumField())
David Symondsd15e81b2011-10-03 14:31:12 -0700414 prop.order = make([]int, t.NumField())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700415 for i := 0; i < t.NumField(); i++ {
416 f := t.Field(i)
417 p := new(Properties)
David Symonds8935abf2011-07-04 15:53:16 +1000418 p.Init(f.Type, f.Name, f.Tag.Get("protobuf"), f.Offset)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700419 if f.Name == "XXX_extensions" { // special case
Rob Pikeaaa3a622010-03-20 22:32:34 -0700420 p.enc = (*Buffer).enc_map
421 p.dec = nil // not needed
Rob Pikeaaa3a622010-03-20 22:32:34 -0700422 }
423 prop.Prop[i] = p
David Symondsd15e81b2011-10-03 14:31:12 -0700424 prop.order[i] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700425 if debug {
426 print(i, " ", f.Name, " ", t.String(), " ")
427 if p.Tag > 0 {
428 print(p.String())
429 }
430 print("\n")
431 }
432 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
433 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
434 }
435 }
436
David Symondsd15e81b2011-10-03 14:31:12 -0700437 // Re-order prop.order.
438 sort.Sort(prop)
439
Rob Pikeaaa3a622010-03-20 22:32:34 -0700440 // build required counts
Rob Pikeaaa3a622010-03-20 22:32:34 -0700441 // build tags
442 reqCount := 0
Rob Pikeaaa3a622010-03-20 22:32:34 -0700443 prop.tags = make(map[int]int)
David Symondsd15e81b2011-10-03 14:31:12 -0700444 prop.origNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700445 for i, p := range prop.Prop {
446 if p.Required {
447 reqCount++
448 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700449 prop.tags[p.Tag] = i
David Symondsd15e81b2011-10-03 14:31:12 -0700450 prop.origNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700451 }
452 prop.reqCount = reqCount
Rob Pikeaaa3a622010-03-20 22:32:34 -0700453
454 propertiesMap[t] = prop
455 mutex.Unlock()
456 return prop
457}
458
Rob Pikeaaa3a622010-03-20 22:32:34 -0700459// Return the field index of the named field.
460// Returns nil if there is no such field.
Rob Pike97e934d2011-04-11 12:52:49 -0700461func fieldIndex(t reflect.Type, name string) []int {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700462 if field, ok := t.FieldByName(name); ok {
463 return field.Index
464 }
465 return nil
466}
467
468// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700469func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700470 if len(x) != 1 {
471 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
472 return nil
473 }
474 prop := GetProperties(t)
475 return prop.Prop[x[0]]
476}
477
David Symonds7656e742011-07-22 14:54:17 +1000478// Get the address and type of a pointer to a struct from an interface.
Rob Pike97e934d2011-04-11 12:52:49 -0700479func getbase(pb interface{}) (t reflect.Type, b uintptr, err os.Error) {
Rob Pikef1b341e2011-10-20 14:51:10 -0700480 if pb == nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700481 err = ErrNil
482 return
483 }
Rob Pikef1b341e2011-10-20 14:51:10 -0700484 // get the reflect type of the pointer to the struct.
Nigel Tao4ede8452011-04-28 11:27:25 +1000485 t = reflect.TypeOf(pb)
Rob Pikef1b341e2011-10-20 14:51:10 -0700486 if t.Kind() != reflect.Ptr {
487 err = ErrNotPtr
488 return
489 }
490 // get the address of the struct.
491 value := reflect.ValueOf(pb)
492 b = value.Pointer()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700493 return
494}
495
Rob Pikeaaa3a622010-03-20 22:32:34 -0700496// A global registry of enum types.
497// The generated code will register the generated maps by calling RegisterEnum.
498
499var enumNameMaps = make(map[string]map[int32]string)
500var enumValueMaps = make(map[string]map[string]int32)
501
502// RegisterEnum is called from the generated code to install the enum descriptor
503// maps into the global table to aid parsing ASCII protocol buffers.
504func RegisterEnum(typeName string, nameMap map[int32]string, valueMap map[string]int32) {
505 if _, ok := enumNameMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700506 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700507 }
508 enumNameMaps[typeName] = nameMap
509 enumValueMaps[typeName] = valueMap
510}