blob: 0127f72a540491e60f9a18c3aae00b42efe34106 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
David Symondsee6e9c52012-11-29 08:51:07 +11003// Copyright 2010 The Go Authors. All rights reserved.
Rob Pikeaaa3a622010-03-20 22:32:34 -07004// 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.
David Symonds2bba1b22012-09-26 14:53:08 +1000117// decoderTags and decoderOrigNames should only be used by the decoder.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700118type StructProperties struct {
David Symonds2bba1b22012-09-26 14:53:08 +1000119 Prop []*Properties // properties for each field
120 reqCount int // required count
121 decoderTags tagMap // map from proto tag to struct field number
122 decoderOrigNames map[string]int // map from original name to struct field number
123 order []int // list of struct field numbers in tag order
124 unrecField field // field id of the XXX_unrecognized []byte field
125 extendable bool // is this an extendable proto
Rob Pikeaaa3a622010-03-20 22:32:34 -0700126}
127
David Symondsd15e81b2011-10-03 14:31:12 -0700128// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
129// See encoder.go, (*Buffer).enc_struct.
130
131func (sp *StructProperties) Len() int { return len(sp.order) }
132func (sp *StructProperties) Less(i, j int) bool {
133 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
134}
135func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
136
Rob Pikeaaa3a622010-03-20 22:32:34 -0700137// Properties represents the protocol-specific behavior of a single struct field.
138type Properties struct {
139 Name string // name of the field, for error messages
140 OrigName string // original name before protocol compiler (always set)
141 Wire string
142 WireType int
143 Tag int
144 Required bool
145 Optional bool
146 Repeated bool
David Symonds5b7775e2010-12-01 10:09:04 +1100147 Packed bool // relevant for repeated primitives only
Rob Pikeaaa3a622010-03-20 22:32:34 -0700148 Enum string // set for enum types only
149 Default string // default value
150 def_uint64 uint64
151
David Symondsa80b2822012-03-14 14:31:25 +1100152 enc encoder
153 valEnc valueEncoder // set for bool and numeric types only
Russ Coxd4ce3f12012-09-12 10:36:26 +1000154 field field
David Symondsa80b2822012-03-14 14:31:25 +1100155 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
156 tagbuf [8]byte
David Symondsc0287172012-08-15 11:10:30 +1000157 stype reflect.Type // set for struct types only
158 sprop *StructProperties // set for struct types only
David Symondsa80b2822012-03-14 14:31:25 +1100159 isMarshaler bool
160 isUnmarshaler bool
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161
David Symonds049646b2011-10-21 11:13:45 +1100162 dec decoder
163 valDec valueDecoder // set for bool and numeric types only
David Symonds5b7775e2010-12-01 10:09:04 +1100164
165 // If this is a packable field, this will be the decoder for the packed version of the field.
166 packedDec decoder
Rob Pikeaaa3a622010-03-20 22:32:34 -0700167}
168
David Symonds8935abf2011-07-04 15:53:16 +1000169// String formats the properties in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700170func (p *Properties) String() string {
171 s := p.Wire
172 s = ","
173 s += strconv.Itoa(p.Tag)
174 if p.Required {
175 s += ",req"
176 }
177 if p.Optional {
178 s += ",opt"
179 }
180 if p.Repeated {
181 s += ",rep"
182 }
David Symonds5b7775e2010-12-01 10:09:04 +1100183 if p.Packed {
184 s += ",packed"
185 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700186 if p.OrigName != p.Name {
187 s += ",name=" + p.OrigName
188 }
189 if len(p.Enum) > 0 {
190 s += ",enum=" + p.Enum
191 }
192 if len(p.Default) > 0 {
193 s += ",def=" + p.Default
194 }
195 return s
196}
197
David Symonds8935abf2011-07-04 15:53:16 +1000198// Parse populates p by parsing a string in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700199func (p *Properties) Parse(s string) {
David Symondsa7e9ef92012-01-18 18:27:58 +1100200 // "bytes,49,opt,name=foo,def=hello!"
David Symonds8935abf2011-07-04 15:53:16 +1000201 fields := strings.Split(s, ",") // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700202 if len(fields) < 2 {
203 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
204 return
205 }
206
207 p.Wire = fields[0]
208 switch p.Wire {
209 case "varint":
210 p.WireType = WireVarint
211 p.valEnc = (*Buffer).EncodeVarint
212 p.valDec = (*Buffer).DecodeVarint
213 case "fixed32":
214 p.WireType = WireFixed32
215 p.valEnc = (*Buffer).EncodeFixed32
216 p.valDec = (*Buffer).DecodeFixed32
217 case "fixed64":
218 p.WireType = WireFixed64
219 p.valEnc = (*Buffer).EncodeFixed64
220 p.valDec = (*Buffer).DecodeFixed64
221 case "zigzag32":
222 p.WireType = WireVarint
223 p.valEnc = (*Buffer).EncodeZigzag32
224 p.valDec = (*Buffer).DecodeZigzag32
225 case "zigzag64":
226 p.WireType = WireVarint
227 p.valEnc = (*Buffer).EncodeZigzag64
228 p.valDec = (*Buffer).DecodeZigzag64
229 case "bytes", "group":
230 p.WireType = WireBytes
231 // no numeric converter for non-numeric types
232 default:
233 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
234 return
235 }
236
Rob Pikea17fdd92011-11-02 12:43:05 -0700237 var err error
Rob Pikeaaa3a622010-03-20 22:32:34 -0700238 p.Tag, err = strconv.Atoi(fields[1])
239 if err != nil {
240 return
241 }
242
243 for i := 2; i < len(fields); i++ {
244 f := fields[i]
245 switch {
246 case f == "req":
247 p.Required = true
248 case f == "opt":
249 p.Optional = true
250 case f == "rep":
251 p.Repeated = true
David Symonds5b7775e2010-12-01 10:09:04 +1100252 case f == "packed":
253 p.Packed = true
David Symondsa7e9ef92012-01-18 18:27:58 +1100254 case strings.HasPrefix(f, "name="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000255 p.OrigName = f[5:]
David Symondsa7e9ef92012-01-18 18:27:58 +1100256 case strings.HasPrefix(f, "enum="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000257 p.Enum = f[5:]
David Symondsa7e9ef92012-01-18 18:27:58 +1100258 case strings.HasPrefix(f, "def="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000259 p.Default = f[4:] // rest of string
Rob Pikeaaa3a622010-03-20 22:32:34 -0700260 if i+1 < len(fields) {
261 // Commas aren't escaped, and def is always last.
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000262 p.Default += "," + strings.Join(fields[i+1:], ",")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700263 break
264 }
265 }
266 }
267}
268
David Symonds5922d072011-06-22 15:48:09 +1000269func logNoSliceEnc(t1, t2 reflect.Type) {
270 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
271}
272
David Symonds525838c2012-07-20 15:42:49 +1000273var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
274
Rob Pikeaaa3a622010-03-20 22:32:34 -0700275// Initialize the fields for encoding and decoding.
David Symondsc0287172012-08-15 11:10:30 +1000276func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700277 p.enc = nil
278 p.dec = nil
279
Rob Pike97e934d2011-04-11 12:52:49 -0700280 switch t1 := typ; t1.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700281 default:
282 fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700283
Rob Pike97e934d2011-04-11 12:52:49 -0700284 case reflect.Ptr:
285 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700286 default:
287 fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
288 break
Rob Pike97e934d2011-04-11 12:52:49 -0700289 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700290 p.enc = (*Buffer).enc_bool
291 p.dec = (*Buffer).dec_bool
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700292 case reflect.Int32, reflect.Uint32:
293 p.enc = (*Buffer).enc_int32
294 p.dec = (*Buffer).dec_int32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700295 case reflect.Int64, reflect.Uint64:
296 p.enc = (*Buffer).enc_int64
297 p.dec = (*Buffer).dec_int64
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700298 case reflect.Float32:
299 p.enc = (*Buffer).enc_int32 // can just treat them as bits
300 p.dec = (*Buffer).dec_int32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700301 case reflect.Float64:
302 p.enc = (*Buffer).enc_int64 // can just treat them as bits
303 p.dec = (*Buffer).dec_int64
Rob Pike97e934d2011-04-11 12:52:49 -0700304 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700305 p.enc = (*Buffer).enc_string
306 p.dec = (*Buffer).dec_string
Rob Pike97e934d2011-04-11 12:52:49 -0700307 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000308 p.stype = t1.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100309 p.isMarshaler = isMarshaler(t1)
310 p.isUnmarshaler = isUnmarshaler(t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700311 if p.Wire == "bytes" {
312 p.enc = (*Buffer).enc_struct_message
313 p.dec = (*Buffer).dec_struct_message
314 } else {
315 p.enc = (*Buffer).enc_struct_group
316 p.dec = (*Buffer).dec_struct_group
317 }
318 }
319
Rob Pike97e934d2011-04-11 12:52:49 -0700320 case reflect.Slice:
321 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700322 default:
David Symonds5922d072011-06-22 15:48:09 +1000323 logNoSliceEnc(t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700324 break
Rob Pike97e934d2011-04-11 12:52:49 -0700325 case reflect.Bool:
David Symonds5b7775e2010-12-01 10:09:04 +1100326 if p.Packed {
327 p.enc = (*Buffer).enc_slice_packed_bool
328 } else {
329 p.enc = (*Buffer).enc_slice_bool
330 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700331 p.dec = (*Buffer).dec_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100332 p.packedDec = (*Buffer).dec_slice_packed_bool
Rob Pike97e934d2011-04-11 12:52:49 -0700333 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 -0700334 switch t2.Bits() {
335 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100336 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 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100344 if p.Packed {
345 p.enc = (*Buffer).enc_slice_packed_int64
346 } else {
347 p.enc = (*Buffer).enc_slice_int64
348 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700349 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100350 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700351 case 8:
352 if t2.Kind() == reflect.Uint8 {
353 p.enc = (*Buffer).enc_slice_byte
354 p.dec = (*Buffer).dec_slice_byte
Rob Pikeab5b8022010-06-21 17:47:58 -0700355 }
356 default:
David Symonds5922d072011-06-22 15:48:09 +1000357 logNoSliceEnc(t1, t2)
358 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700359 }
Rob Pike97e934d2011-04-11 12:52:49 -0700360 case reflect.Float32, reflect.Float64:
Rob Pikeab5b8022010-06-21 17:47:58 -0700361 switch t2.Bits() {
362 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100363 // can just treat them as bits
364 if p.Packed {
365 p.enc = (*Buffer).enc_slice_packed_int32
366 } else {
367 p.enc = (*Buffer).enc_slice_int32
368 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700369 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100370 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700371 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100372 // can just treat them as bits
373 if p.Packed {
374 p.enc = (*Buffer).enc_slice_packed_int64
375 } else {
376 p.enc = (*Buffer).enc_slice_int64
377 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700378 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100379 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700380 default:
David Symonds5922d072011-06-22 15:48:09 +1000381 logNoSliceEnc(t1, t2)
382 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700383 }
Rob Pike97e934d2011-04-11 12:52:49 -0700384 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700385 p.enc = (*Buffer).enc_slice_string
386 p.dec = (*Buffer).dec_slice_string
Rob Pike97e934d2011-04-11 12:52:49 -0700387 case reflect.Ptr:
388 switch t3 := t2.Elem(); t3.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700389 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700390 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700391 break
Rob Pike97e934d2011-04-11 12:52:49 -0700392 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000393 p.stype = t2.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100394 p.isMarshaler = isMarshaler(t2)
395 p.isUnmarshaler = isUnmarshaler(t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700396 p.enc = (*Buffer).enc_slice_struct_group
397 p.dec = (*Buffer).dec_slice_struct_group
398 if p.Wire == "bytes" {
399 p.enc = (*Buffer).enc_slice_struct_message
400 p.dec = (*Buffer).dec_slice_struct_message
401 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700402 }
Rob Pike97e934d2011-04-11 12:52:49 -0700403 case reflect.Slice:
Rob Pikeab5b8022010-06-21 17:47:58 -0700404 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700405 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700406 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 -0700407 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700408 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700409 p.enc = (*Buffer).enc_slice_slice_byte
410 p.dec = (*Buffer).dec_slice_slice_byte
Rob Pikeaaa3a622010-03-20 22:32:34 -0700411 }
412 }
413 }
414
415 // precalculate tag code
David Symonds5b7775e2010-12-01 10:09:04 +1100416 wire := p.WireType
417 if p.Packed {
418 wire = WireBytes
419 }
David Symondsd73d7b12011-09-28 10:56:43 -0700420 x := uint32(p.Tag)<<3 | uint32(wire)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700421 i := 0
422 for i = 0; x > 127; i++ {
423 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
424 x >>= 7
425 }
426 p.tagbuf[i] = uint8(x)
427 p.tagcode = p.tagbuf[0 : i+1]
David Symondsc0287172012-08-15 11:10:30 +1000428
429 if p.stype != nil {
430 if lockGetProp {
David Symonds6a6f82c2012-08-22 09:18:54 +1000431 p.sprop = GetProperties(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000432 } else {
David Symonds6a6f82c2012-08-22 09:18:54 +1000433 p.sprop = getPropertiesLocked(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000434 }
435 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700436}
437
David Symondsa80b2822012-03-14 14:31:25 +1100438var (
439 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
440 unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
441)
442
443// isMarshaler reports whether type t implements Marshaler.
444func isMarshaler(t reflect.Type) bool {
445 // We're checking for (likely) pointer-receiver methods
446 // so if t is not a pointer, something is very wrong.
447 // The calls above only invoke isMarshaler on pointer types.
448 if t.Kind() != reflect.Ptr {
449 panic("proto: misuse of isMarshaler")
450 }
451 return t.Implements(marshalerType)
452}
453
454// isUnmarshaler reports whether type t implements Unmarshaler.
455func isUnmarshaler(t reflect.Type) bool {
456 // We're checking for (likely) pointer-receiver methods
457 // so if t is not a pointer, something is very wrong.
458 // The calls above only invoke isUnmarshaler on pointer types.
459 if t.Kind() != reflect.Ptr {
460 panic("proto: misuse of isUnmarshaler")
461 }
462 return t.Implements(unmarshalerType)
463}
464
David Symonds8935abf2011-07-04 15:53:16 +1000465// Init populates the properties from a protocol buffer struct tag.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000466func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
467 p.init(typ, name, tag, f, true)
David Symondsc0287172012-08-15 11:10:30 +1000468}
469
Russ Coxd4ce3f12012-09-12 10:36:26 +1000470func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
David Symonds8935abf2011-07-04 15:53:16 +1000471 // "bytes,49,opt,def=hello!"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700472 p.Name = name
473 p.OrigName = name
Russ Coxd4ce3f12012-09-12 10:36:26 +1000474 if f != nil {
475 p.field = toField(f)
476 }
David Symonds8935abf2011-07-04 15:53:16 +1000477 if tag == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700478 return
479 }
David Symonds8935abf2011-07-04 15:53:16 +1000480 p.Parse(tag)
David Symondsc0287172012-08-15 11:10:30 +1000481 p.setEncAndDec(typ, lockGetProp)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700482}
483
484var (
485 mutex sync.Mutex
Rob Pike97e934d2011-04-11 12:52:49 -0700486 propertiesMap = make(map[reflect.Type]*StructProperties)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700487)
488
489// GetProperties returns the list of properties for the type represented by t.
Rob Pike97e934d2011-04-11 12:52:49 -0700490func GetProperties(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700491 mutex.Lock()
David Symondsc0287172012-08-15 11:10:30 +1000492 sprop := getPropertiesLocked(t)
493 mutex.Unlock()
494 return sprop
495}
496
497// getPropertiesLocked requires that mutex is held.
498func getPropertiesLocked(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700499 if prop, ok := propertiesMap[t]; ok {
David Symonds9f60f432012-06-14 09:45:25 +1000500 if collectStats {
501 stats.Chit++
502 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700503 return prop
504 }
David Symonds9f60f432012-06-14 09:45:25 +1000505 if collectStats {
506 stats.Cmiss++
507 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700508
509 prop := new(StructProperties)
David Symondsc0287172012-08-15 11:10:30 +1000510 // in case of recursive protos, fill this in now.
511 propertiesMap[t] = prop
Rob Pikeaaa3a622010-03-20 22:32:34 -0700512
513 // build properties
Russ Coxd4ce3f12012-09-12 10:36:26 +1000514 prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
515 prop.unrecField = invalidField
Rob Pikeaaa3a622010-03-20 22:32:34 -0700516 prop.Prop = make([]*Properties, t.NumField())
David Symondsd15e81b2011-10-03 14:31:12 -0700517 prop.order = make([]int, t.NumField())
David Symonds20370902013-03-23 17:20:01 +1100518
Rob Pikeaaa3a622010-03-20 22:32:34 -0700519 for i := 0; i < t.NumField(); i++ {
520 f := t.Field(i)
521 p := new(Properties)
David Symonds20370902013-03-23 17:20:01 +1100522 name := f.Name
523 p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
524
Rob Pikeaaa3a622010-03-20 22:32:34 -0700525 if f.Name == "XXX_extensions" { // special case
Rob Pikeaaa3a622010-03-20 22:32:34 -0700526 p.enc = (*Buffer).enc_map
527 p.dec = nil // not needed
Rob Pikeaaa3a622010-03-20 22:32:34 -0700528 }
David Symonds10c93ba2012-08-04 16:38:08 +1000529 if f.Name == "XXX_unrecognized" { // special case
Russ Coxd4ce3f12012-09-12 10:36:26 +1000530 prop.unrecField = toField(&f)
David Symonds10c93ba2012-08-04 16:38:08 +1000531 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700532 prop.Prop[i] = p
David Symondsd15e81b2011-10-03 14:31:12 -0700533 prop.order[i] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700534 if debug {
535 print(i, " ", f.Name, " ", t.String(), " ")
536 if p.Tag > 0 {
537 print(p.String())
538 }
539 print("\n")
540 }
541 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
542 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
543 }
544 }
545
David Symondsd15e81b2011-10-03 14:31:12 -0700546 // Re-order prop.order.
547 sort.Sort(prop)
548
Rob Pikeaaa3a622010-03-20 22:32:34 -0700549 // build required counts
Rob Pikeaaa3a622010-03-20 22:32:34 -0700550 // build tags
551 reqCount := 0
David Symonds2bba1b22012-09-26 14:53:08 +1000552 prop.decoderOrigNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700553 for i, p := range prop.Prop {
David Symonds6e50db52012-02-11 15:56:22 +1100554 if strings.HasPrefix(p.Name, "XXX_") {
555 // Internal fields should not appear in tags/origNames maps.
556 // They are handled specially when encoding and decoding.
557 continue
558 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700559 if p.Required {
560 reqCount++
561 }
David Symonds2bba1b22012-09-26 14:53:08 +1000562 prop.decoderTags.put(p.Tag, i)
563 prop.decoderOrigNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700564 }
565 prop.reqCount = reqCount
Rob Pikeaaa3a622010-03-20 22:32:34 -0700566
Rob Pikeaaa3a622010-03-20 22:32:34 -0700567 return prop
568}
569
Rob Pikeaaa3a622010-03-20 22:32:34 -0700570// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700571func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700572 if len(x) != 1 {
573 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
574 return nil
575 }
576 prop := GetProperties(t)
577 return prop.Prop[x[0]]
578}
579
David Symonds7656e742011-07-22 14:54:17 +1000580// Get the address and type of a pointer to a struct from an interface.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000581func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
Rob Pikef1b341e2011-10-20 14:51:10 -0700582 if pb == nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700583 err = ErrNil
584 return
585 }
Rob Pikef1b341e2011-10-20 14:51:10 -0700586 // get the reflect type of the pointer to the struct.
Nigel Tao4ede8452011-04-28 11:27:25 +1000587 t = reflect.TypeOf(pb)
Rob Pikef1b341e2011-10-20 14:51:10 -0700588 // get the address of the struct.
589 value := reflect.ValueOf(pb)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000590 b = toStructPointer(value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700591 return
592}
593
Rob Pikeaaa3a622010-03-20 22:32:34 -0700594// A global registry of enum types.
595// The generated code will register the generated maps by calling RegisterEnum.
596
597var enumNameMaps = make(map[string]map[int32]string)
598var enumValueMaps = make(map[string]map[string]int32)
599
600// RegisterEnum is called from the generated code to install the enum descriptor
601// maps into the global table to aid parsing ASCII protocol buffers.
602func RegisterEnum(typeName string, nameMap map[int32]string, valueMap map[string]int32) {
603 if _, ok := enumNameMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700604 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700605 }
606 enumNameMaps[typeName] = nameMap
607 enumValueMaps[typeName] = valueMap
608}