blob: 9bad3815aeb1dd36e4758bf5b0f3a8f5ae00dc2b [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.
Russ Coxd4ce3f12012-09-12 10:36:26 +100065type encoder func(p *Buffer, prop *Properties, base structPointer) error
Rob Pikeaaa3a622010-03-20 22:32:34 -070066
67// A valueEncoder encodes a single integer in a particular encoding.
Rob Pikea17fdd92011-11-02 12:43:05 -070068type valueEncoder func(o *Buffer, x uint64) error
Rob Pikeaaa3a622010-03-20 22:32:34 -070069
70// Decoders are defined in decode.go
71// A decoder creates a value from its wire representation.
72// Unrecognized subelements are saved in unrec.
Russ Coxd4ce3f12012-09-12 10:36:26 +100073type decoder func(p *Buffer, prop *Properties, base structPointer) error
Rob Pikeaaa3a622010-03-20 22:32:34 -070074
75// A valueDecoder decodes a single integer in a particular encoding.
Rob Pikea17fdd92011-11-02 12:43:05 -070076type valueDecoder func(o *Buffer) (x uint64, err error)
Rob Pikeaaa3a622010-03-20 22:32:34 -070077
David Symonds6a6f82c2012-08-22 09:18:54 +100078// tagMap is an optimization over map[int]int for typical protocol buffer
79// use-cases. Encoded protocol buffers are often in tag order with small tag
80// numbers.
81type tagMap struct {
82 fastTags []int
83 slowTags map[int]int
84}
85
86// tagMapFastLimit is the upper bound on the tag number that will be stored in
87// the tagMap slice rather than its map.
88const tagMapFastLimit = 1024
89
90func (p *tagMap) get(t int) (int, bool) {
91 if t > 0 && t < tagMapFastLimit {
92 if t >= len(p.fastTags) {
93 return 0, false
94 }
95 fi := p.fastTags[t]
96 return fi, fi >= 0
97 }
98 fi, ok := p.slowTags[t]
99 return fi, ok
100}
101
102func (p *tagMap) put(t int, fi int) {
103 if t > 0 && t < tagMapFastLimit {
104 for len(p.fastTags) < t+1 {
105 p.fastTags = append(p.fastTags, -1)
106 }
107 p.fastTags[t] = fi
108 return
109 }
110 if p.slowTags == nil {
111 p.slowTags = make(map[int]int)
112 }
113 p.slowTags[t] = fi
114}
115
Rob Pikeaaa3a622010-03-20 22:32:34 -0700116// StructProperties represents properties for all the fields of a struct.
117type StructProperties struct {
Russ Coxd4ce3f12012-09-12 10:36:26 +1000118 Prop []*Properties // properties for each field
119 reqCount int // required count
120 tags tagMap // map from proto tag to struct field number
121 origNames map[string]int // map from original name to struct field number
122 order []int // list of struct field numbers in tag order
123 unrecField field // field id of the XXX_unrecognized []byte field
124 extendable bool // is this an extendable proto
Rob Pikeaaa3a622010-03-20 22:32:34 -0700125}
126
David Symondsd15e81b2011-10-03 14:31:12 -0700127// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
128// See encoder.go, (*Buffer).enc_struct.
129
130func (sp *StructProperties) Len() int { return len(sp.order) }
131func (sp *StructProperties) Less(i, j int) bool {
132 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
133}
134func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
135
Rob Pikeaaa3a622010-03-20 22:32:34 -0700136// Properties represents the protocol-specific behavior of a single struct field.
137type Properties struct {
138 Name string // name of the field, for error messages
139 OrigName string // original name before protocol compiler (always set)
140 Wire string
141 WireType int
142 Tag int
143 Required bool
144 Optional bool
145 Repeated bool
David Symonds5b7775e2010-12-01 10:09:04 +1100146 Packed bool // relevant for repeated primitives only
Rob Pikeaaa3a622010-03-20 22:32:34 -0700147 Enum string // set for enum types only
148 Default string // default value
149 def_uint64 uint64
150
David Symondsa80b2822012-03-14 14:31:25 +1100151 enc encoder
152 valEnc valueEncoder // set for bool and numeric types only
Russ Coxd4ce3f12012-09-12 10:36:26 +1000153 field field
David Symondsa80b2822012-03-14 14:31:25 +1100154 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
155 tagbuf [8]byte
David Symondsc0287172012-08-15 11:10:30 +1000156 stype reflect.Type // set for struct types only
157 sprop *StructProperties // set for struct types only
David Symondsa80b2822012-03-14 14:31:25 +1100158 isMarshaler bool
159 isUnmarshaler bool
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160
David Symonds049646b2011-10-21 11:13:45 +1100161 dec decoder
162 valDec valueDecoder // set for bool and numeric types only
David Symonds5b7775e2010-12-01 10:09:04 +1100163
164 // If this is a packable field, this will be the decoder for the packed version of the field.
165 packedDec decoder
Rob Pikeaaa3a622010-03-20 22:32:34 -0700166}
167
David Symonds8935abf2011-07-04 15:53:16 +1000168// String formats the properties in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700169func (p *Properties) String() string {
170 s := p.Wire
171 s = ","
172 s += strconv.Itoa(p.Tag)
173 if p.Required {
174 s += ",req"
175 }
176 if p.Optional {
177 s += ",opt"
178 }
179 if p.Repeated {
180 s += ",rep"
181 }
David Symonds5b7775e2010-12-01 10:09:04 +1100182 if p.Packed {
183 s += ",packed"
184 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700185 if p.OrigName != p.Name {
186 s += ",name=" + p.OrigName
187 }
188 if len(p.Enum) > 0 {
189 s += ",enum=" + p.Enum
190 }
191 if len(p.Default) > 0 {
192 s += ",def=" + p.Default
193 }
194 return s
195}
196
David Symonds8935abf2011-07-04 15:53:16 +1000197// Parse populates p by parsing a string in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700198func (p *Properties) Parse(s string) {
David Symondsa7e9ef92012-01-18 18:27:58 +1100199 // "bytes,49,opt,name=foo,def=hello!"
David Symonds8935abf2011-07-04 15:53:16 +1000200 fields := strings.Split(s, ",") // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700201 if len(fields) < 2 {
202 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
203 return
204 }
205
206 p.Wire = fields[0]
207 switch p.Wire {
208 case "varint":
209 p.WireType = WireVarint
210 p.valEnc = (*Buffer).EncodeVarint
211 p.valDec = (*Buffer).DecodeVarint
212 case "fixed32":
213 p.WireType = WireFixed32
214 p.valEnc = (*Buffer).EncodeFixed32
215 p.valDec = (*Buffer).DecodeFixed32
216 case "fixed64":
217 p.WireType = WireFixed64
218 p.valEnc = (*Buffer).EncodeFixed64
219 p.valDec = (*Buffer).DecodeFixed64
220 case "zigzag32":
221 p.WireType = WireVarint
222 p.valEnc = (*Buffer).EncodeZigzag32
223 p.valDec = (*Buffer).DecodeZigzag32
224 case "zigzag64":
225 p.WireType = WireVarint
226 p.valEnc = (*Buffer).EncodeZigzag64
227 p.valDec = (*Buffer).DecodeZigzag64
228 case "bytes", "group":
229 p.WireType = WireBytes
230 // no numeric converter for non-numeric types
231 default:
232 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
233 return
234 }
235
Rob Pikea17fdd92011-11-02 12:43:05 -0700236 var err error
Rob Pikeaaa3a622010-03-20 22:32:34 -0700237 p.Tag, err = strconv.Atoi(fields[1])
238 if err != nil {
239 return
240 }
241
242 for i := 2; i < len(fields); i++ {
243 f := fields[i]
244 switch {
245 case f == "req":
246 p.Required = true
247 case f == "opt":
248 p.Optional = true
249 case f == "rep":
250 p.Repeated = true
David Symonds5b7775e2010-12-01 10:09:04 +1100251 case f == "packed":
252 p.Packed = true
David Symondsa7e9ef92012-01-18 18:27:58 +1100253 case strings.HasPrefix(f, "name="):
Rob Pikeaaa3a622010-03-20 22:32:34 -0700254 p.OrigName = f[5:len(f)]
David Symondsa7e9ef92012-01-18 18:27:58 +1100255 case strings.HasPrefix(f, "enum="):
Rob Pikeaaa3a622010-03-20 22:32:34 -0700256 p.Enum = f[5:len(f)]
David Symondsa7e9ef92012-01-18 18:27:58 +1100257 case strings.HasPrefix(f, "def="):
Rob Pikeaaa3a622010-03-20 22:32:34 -0700258 p.Default = f[4:len(f)] // rest of string
259 if i+1 < len(fields) {
260 // Commas aren't escaped, and def is always last.
261 p.Default += "," + strings.Join(fields[i+1:len(fields)], ",")
262 break
263 }
264 }
265 }
266}
267
David Symonds5922d072011-06-22 15:48:09 +1000268func logNoSliceEnc(t1, t2 reflect.Type) {
269 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
270}
271
David Symonds525838c2012-07-20 15:42:49 +1000272var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
273
Rob Pikeaaa3a622010-03-20 22:32:34 -0700274// Initialize the fields for encoding and decoding.
David Symondsc0287172012-08-15 11:10:30 +1000275func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700276 p.enc = nil
277 p.dec = nil
278
Rob Pike97e934d2011-04-11 12:52:49 -0700279 switch t1 := typ; t1.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700280 default:
281 fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700282
Rob Pike97e934d2011-04-11 12:52:49 -0700283 case reflect.Ptr:
284 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700285 default:
286 fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
287 break
Rob Pike97e934d2011-04-11 12:52:49 -0700288 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700289 p.enc = (*Buffer).enc_bool
290 p.dec = (*Buffer).dec_bool
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700291 case reflect.Int32, reflect.Uint32:
292 p.enc = (*Buffer).enc_int32
293 p.dec = (*Buffer).dec_int32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700294 case reflect.Int64, reflect.Uint64:
295 p.enc = (*Buffer).enc_int64
296 p.dec = (*Buffer).dec_int64
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700297 case reflect.Float32:
298 p.enc = (*Buffer).enc_int32 // can just treat them as bits
299 p.dec = (*Buffer).dec_int32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700300 case reflect.Float64:
301 p.enc = (*Buffer).enc_int64 // can just treat them as bits
302 p.dec = (*Buffer).dec_int64
Rob Pike97e934d2011-04-11 12:52:49 -0700303 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700304 p.enc = (*Buffer).enc_string
305 p.dec = (*Buffer).dec_string
Rob Pike97e934d2011-04-11 12:52:49 -0700306 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000307 p.stype = t1.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100308 p.isMarshaler = isMarshaler(t1)
309 p.isUnmarshaler = isUnmarshaler(t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700310 if p.Wire == "bytes" {
311 p.enc = (*Buffer).enc_struct_message
312 p.dec = (*Buffer).dec_struct_message
313 } else {
314 p.enc = (*Buffer).enc_struct_group
315 p.dec = (*Buffer).dec_struct_group
316 }
317 }
318
Rob Pike97e934d2011-04-11 12:52:49 -0700319 case reflect.Slice:
320 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700321 default:
David Symonds5922d072011-06-22 15:48:09 +1000322 logNoSliceEnc(t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700323 break
Rob Pike97e934d2011-04-11 12:52:49 -0700324 case reflect.Bool:
David Symonds5b7775e2010-12-01 10:09:04 +1100325 if p.Packed {
326 p.enc = (*Buffer).enc_slice_packed_bool
327 } else {
328 p.enc = (*Buffer).enc_slice_bool
329 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700330 p.dec = (*Buffer).dec_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100331 p.packedDec = (*Buffer).dec_slice_packed_bool
Rob Pike97e934d2011-04-11 12:52:49 -0700332 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 -0700333 switch t2.Bits() {
334 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100335 if p.Packed {
336 p.enc = (*Buffer).enc_slice_packed_int32
337 } else {
338 p.enc = (*Buffer).enc_slice_int32
339 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700340 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100341 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700342 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100343 if p.Packed {
344 p.enc = (*Buffer).enc_slice_packed_int64
345 } else {
346 p.enc = (*Buffer).enc_slice_int64
347 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700348 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100349 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700350 case 8:
351 if t2.Kind() == reflect.Uint8 {
352 p.enc = (*Buffer).enc_slice_byte
353 p.dec = (*Buffer).dec_slice_byte
Rob Pikeab5b8022010-06-21 17:47:58 -0700354 }
355 default:
David Symonds5922d072011-06-22 15:48:09 +1000356 logNoSliceEnc(t1, t2)
357 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700358 }
Rob Pike97e934d2011-04-11 12:52:49 -0700359 case reflect.Float32, reflect.Float64:
Rob Pikeab5b8022010-06-21 17:47:58 -0700360 switch t2.Bits() {
361 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100362 // can just treat them as bits
363 if p.Packed {
364 p.enc = (*Buffer).enc_slice_packed_int32
365 } else {
366 p.enc = (*Buffer).enc_slice_int32
367 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700368 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100369 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700370 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100371 // can just treat them as bits
372 if p.Packed {
373 p.enc = (*Buffer).enc_slice_packed_int64
374 } else {
375 p.enc = (*Buffer).enc_slice_int64
376 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700377 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100378 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700379 default:
David Symonds5922d072011-06-22 15:48:09 +1000380 logNoSliceEnc(t1, t2)
381 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700382 }
Rob Pike97e934d2011-04-11 12:52:49 -0700383 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700384 p.enc = (*Buffer).enc_slice_string
385 p.dec = (*Buffer).dec_slice_string
Rob Pike97e934d2011-04-11 12:52:49 -0700386 case reflect.Ptr:
387 switch t3 := t2.Elem(); t3.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700388 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700389 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700390 break
Rob Pike97e934d2011-04-11 12:52:49 -0700391 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000392 p.stype = t2.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100393 p.isMarshaler = isMarshaler(t2)
394 p.isUnmarshaler = isUnmarshaler(t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700395 p.enc = (*Buffer).enc_slice_struct_group
396 p.dec = (*Buffer).dec_slice_struct_group
397 if p.Wire == "bytes" {
398 p.enc = (*Buffer).enc_slice_struct_message
399 p.dec = (*Buffer).dec_slice_struct_message
400 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700401 }
Rob Pike97e934d2011-04-11 12:52:49 -0700402 case reflect.Slice:
Rob Pikeab5b8022010-06-21 17:47:58 -0700403 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700404 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700405 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 -0700406 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700407 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700408 p.enc = (*Buffer).enc_slice_slice_byte
409 p.dec = (*Buffer).dec_slice_slice_byte
Rob Pikeaaa3a622010-03-20 22:32:34 -0700410 }
411 }
412 }
413
414 // precalculate tag code
David Symonds5b7775e2010-12-01 10:09:04 +1100415 wire := p.WireType
416 if p.Packed {
417 wire = WireBytes
418 }
David Symondsd73d7b12011-09-28 10:56:43 -0700419 x := uint32(p.Tag)<<3 | uint32(wire)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700420 i := 0
421 for i = 0; x > 127; i++ {
422 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
423 x >>= 7
424 }
425 p.tagbuf[i] = uint8(x)
426 p.tagcode = p.tagbuf[0 : i+1]
David Symondsc0287172012-08-15 11:10:30 +1000427
428 if p.stype != nil {
429 if lockGetProp {
David Symonds6a6f82c2012-08-22 09:18:54 +1000430 p.sprop = GetProperties(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000431 } else {
David Symonds6a6f82c2012-08-22 09:18:54 +1000432 p.sprop = getPropertiesLocked(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000433 }
434 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700435}
436
David Symondsa80b2822012-03-14 14:31:25 +1100437var (
438 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
439 unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
440)
441
442// isMarshaler reports whether type t implements Marshaler.
443func isMarshaler(t reflect.Type) bool {
444 // We're checking for (likely) pointer-receiver methods
445 // so if t is not a pointer, something is very wrong.
446 // The calls above only invoke isMarshaler on pointer types.
447 if t.Kind() != reflect.Ptr {
448 panic("proto: misuse of isMarshaler")
449 }
450 return t.Implements(marshalerType)
451}
452
453// isUnmarshaler reports whether type t implements Unmarshaler.
454func isUnmarshaler(t reflect.Type) bool {
455 // We're checking for (likely) pointer-receiver methods
456 // so if t is not a pointer, something is very wrong.
457 // The calls above only invoke isUnmarshaler on pointer types.
458 if t.Kind() != reflect.Ptr {
459 panic("proto: misuse of isUnmarshaler")
460 }
461 return t.Implements(unmarshalerType)
462}
463
David Symonds8935abf2011-07-04 15:53:16 +1000464// Init populates the properties from a protocol buffer struct tag.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000465func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
466 p.init(typ, name, tag, f, true)
David Symondsc0287172012-08-15 11:10:30 +1000467}
468
Russ Coxd4ce3f12012-09-12 10:36:26 +1000469func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
David Symonds8935abf2011-07-04 15:53:16 +1000470 // "bytes,49,opt,def=hello!"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700471 p.Name = name
472 p.OrigName = name
Russ Coxd4ce3f12012-09-12 10:36:26 +1000473 if f != nil {
474 p.field = toField(f)
475 }
David Symonds8935abf2011-07-04 15:53:16 +1000476 if tag == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700477 return
478 }
David Symonds8935abf2011-07-04 15:53:16 +1000479 p.Parse(tag)
David Symondsc0287172012-08-15 11:10:30 +1000480 p.setEncAndDec(typ, lockGetProp)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700481}
482
483var (
484 mutex sync.Mutex
Rob Pike97e934d2011-04-11 12:52:49 -0700485 propertiesMap = make(map[reflect.Type]*StructProperties)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700486)
487
488// GetProperties returns the list of properties for the type represented by t.
Rob Pike97e934d2011-04-11 12:52:49 -0700489func GetProperties(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700490 mutex.Lock()
David Symondsc0287172012-08-15 11:10:30 +1000491 sprop := getPropertiesLocked(t)
492 mutex.Unlock()
493 return sprop
494}
495
496// getPropertiesLocked requires that mutex is held.
497func getPropertiesLocked(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700498 if prop, ok := propertiesMap[t]; ok {
David Symonds9f60f432012-06-14 09:45:25 +1000499 if collectStats {
500 stats.Chit++
501 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700502 return prop
503 }
David Symonds9f60f432012-06-14 09:45:25 +1000504 if collectStats {
505 stats.Cmiss++
506 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700507
508 prop := new(StructProperties)
David Symondsc0287172012-08-15 11:10:30 +1000509 // in case of recursive protos, fill this in now.
510 propertiesMap[t] = prop
Rob Pikeaaa3a622010-03-20 22:32:34 -0700511
512 // build properties
Russ Coxd4ce3f12012-09-12 10:36:26 +1000513 prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
514 prop.unrecField = invalidField
Rob Pikeaaa3a622010-03-20 22:32:34 -0700515 prop.Prop = make([]*Properties, t.NumField())
David Symondsd15e81b2011-10-03 14:31:12 -0700516 prop.order = make([]int, t.NumField())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700517 for i := 0; i < t.NumField(); i++ {
518 f := t.Field(i)
519 p := new(Properties)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000520 p.init(f.Type, f.Name, f.Tag.Get("protobuf"), &f, false)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700521 if f.Name == "XXX_extensions" { // special case
Rob Pikeaaa3a622010-03-20 22:32:34 -0700522 p.enc = (*Buffer).enc_map
523 p.dec = nil // not needed
Rob Pikeaaa3a622010-03-20 22:32:34 -0700524 }
David Symonds10c93ba2012-08-04 16:38:08 +1000525 if f.Name == "XXX_unrecognized" { // special case
Russ Coxd4ce3f12012-09-12 10:36:26 +1000526 prop.unrecField = toField(&f)
David Symonds10c93ba2012-08-04 16:38:08 +1000527 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700528 prop.Prop[i] = p
David Symondsd15e81b2011-10-03 14:31:12 -0700529 prop.order[i] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700530 if debug {
531 print(i, " ", f.Name, " ", t.String(), " ")
532 if p.Tag > 0 {
533 print(p.String())
534 }
535 print("\n")
536 }
537 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
538 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
539 }
540 }
541
David Symondsd15e81b2011-10-03 14:31:12 -0700542 // Re-order prop.order.
543 sort.Sort(prop)
544
Rob Pikeaaa3a622010-03-20 22:32:34 -0700545 // build required counts
Rob Pikeaaa3a622010-03-20 22:32:34 -0700546 // build tags
547 reqCount := 0
David Symondsd15e81b2011-10-03 14:31:12 -0700548 prop.origNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700549 for i, p := range prop.Prop {
David Symonds6e50db52012-02-11 15:56:22 +1100550 if strings.HasPrefix(p.Name, "XXX_") {
551 // Internal fields should not appear in tags/origNames maps.
552 // They are handled specially when encoding and decoding.
553 continue
554 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700555 if p.Required {
556 reqCount++
557 }
David Symonds6a6f82c2012-08-22 09:18:54 +1000558 prop.tags.put(p.Tag, i)
David Symondsd15e81b2011-10-03 14:31:12 -0700559 prop.origNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700560 }
561 prop.reqCount = reqCount
Rob Pikeaaa3a622010-03-20 22:32:34 -0700562
Rob Pikeaaa3a622010-03-20 22:32:34 -0700563 return prop
564}
565
Rob Pikeaaa3a622010-03-20 22:32:34 -0700566// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700567func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700568 if len(x) != 1 {
569 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
570 return nil
571 }
572 prop := GetProperties(t)
573 return prop.Prop[x[0]]
574}
575
David Symonds7656e742011-07-22 14:54:17 +1000576// Get the address and type of a pointer to a struct from an interface.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000577func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
Rob Pikef1b341e2011-10-20 14:51:10 -0700578 if pb == nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700579 err = ErrNil
580 return
581 }
Rob Pikef1b341e2011-10-20 14:51:10 -0700582 // get the reflect type of the pointer to the struct.
Nigel Tao4ede8452011-04-28 11:27:25 +1000583 t = reflect.TypeOf(pb)
Rob Pikef1b341e2011-10-20 14:51:10 -0700584 // get the address of the struct.
585 value := reflect.ValueOf(pb)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000586 b = toStructPointer(value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700587 return
588}
589
Rob Pikeaaa3a622010-03-20 22:32:34 -0700590// A global registry of enum types.
591// The generated code will register the generated maps by calling RegisterEnum.
592
593var enumNameMaps = make(map[string]map[int32]string)
594var enumValueMaps = make(map[string]map[string]int32)
595
596// RegisterEnum is called from the generated code to install the enum descriptor
597// maps into the global table to aid parsing ASCII protocol buffers.
598func RegisterEnum(typeName string, nameMap map[int32]string, valueMap map[string]int32) {
599 if _, ok := enumNameMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700600 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700601 }
602 enumNameMaps[typeName] = nameMap
603 enumValueMaps[typeName] = valueMap
604}