blob: 7177cfc9650cb9c68d7ea66ed220f45cfb0b23bf [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
David Symonds0bf1ad52013-10-11 09:07:50 +110062// Encoders are defined in encode.go
Rob Pikeaaa3a622010-03-20 22:32:34 -070063// 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
David Symonds0bf1ad52013-10-11 09:07:50 +110070// Sizers are defined in encode.go
71// A sizer returns the encoded size of a field, including its tag and encoder
72// type.
73type sizer func(prop *Properties, base structPointer) int
74
75// A valueSizer returns the encoded size of a single integer in a particular
76// encoding.
77type valueSizer func(x uint64) int
78
Rob Pikeaaa3a622010-03-20 22:32:34 -070079// Decoders are defined in decode.go
80// A decoder creates a value from its wire representation.
81// Unrecognized subelements are saved in unrec.
Russ Coxd4ce3f12012-09-12 10:36:26 +100082type decoder func(p *Buffer, prop *Properties, base structPointer) error
Rob Pikeaaa3a622010-03-20 22:32:34 -070083
84// A valueDecoder decodes a single integer in a particular encoding.
Rob Pikea17fdd92011-11-02 12:43:05 -070085type valueDecoder func(o *Buffer) (x uint64, err error)
Rob Pikeaaa3a622010-03-20 22:32:34 -070086
David Symonds6a6f82c2012-08-22 09:18:54 +100087// tagMap is an optimization over map[int]int for typical protocol buffer
88// use-cases. Encoded protocol buffers are often in tag order with small tag
89// numbers.
90type tagMap struct {
91 fastTags []int
92 slowTags map[int]int
93}
94
95// tagMapFastLimit is the upper bound on the tag number that will be stored in
96// the tagMap slice rather than its map.
97const tagMapFastLimit = 1024
98
99func (p *tagMap) get(t int) (int, bool) {
100 if t > 0 && t < tagMapFastLimit {
101 if t >= len(p.fastTags) {
102 return 0, false
103 }
104 fi := p.fastTags[t]
105 return fi, fi >= 0
106 }
107 fi, ok := p.slowTags[t]
108 return fi, ok
109}
110
111func (p *tagMap) put(t int, fi int) {
112 if t > 0 && t < tagMapFastLimit {
113 for len(p.fastTags) < t+1 {
114 p.fastTags = append(p.fastTags, -1)
115 }
116 p.fastTags[t] = fi
117 return
118 }
119 if p.slowTags == nil {
120 p.slowTags = make(map[int]int)
121 }
122 p.slowTags[t] = fi
123}
124
Rob Pikeaaa3a622010-03-20 22:32:34 -0700125// StructProperties represents properties for all the fields of a struct.
David Symonds2bba1b22012-09-26 14:53:08 +1000126// decoderTags and decoderOrigNames should only be used by the decoder.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700127type StructProperties struct {
David Symonds2bba1b22012-09-26 14:53:08 +1000128 Prop []*Properties // properties for each field
129 reqCount int // required count
130 decoderTags tagMap // map from proto tag to struct field number
131 decoderOrigNames map[string]int // map from original name to struct field number
132 order []int // list of struct field numbers in tag order
133 unrecField field // field id of the XXX_unrecognized []byte field
134 extendable bool // is this an extendable proto
Rob Pikeaaa3a622010-03-20 22:32:34 -0700135}
136
David Symondsd15e81b2011-10-03 14:31:12 -0700137// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
David Symonds0bf1ad52013-10-11 09:07:50 +1100138// See encode.go, (*Buffer).enc_struct.
David Symondsd15e81b2011-10-03 14:31:12 -0700139
140func (sp *StructProperties) Len() int { return len(sp.order) }
141func (sp *StructProperties) Less(i, j int) bool {
142 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
143}
144func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
145
Rob Pikeaaa3a622010-03-20 22:32:34 -0700146// Properties represents the protocol-specific behavior of a single struct field.
147type Properties struct {
148 Name string // name of the field, for error messages
149 OrigName string // original name before protocol compiler (always set)
150 Wire string
151 WireType int
152 Tag int
153 Required bool
154 Optional bool
155 Repeated bool
David Symonds5b7775e2010-12-01 10:09:04 +1100156 Packed bool // relevant for repeated primitives only
Rob Pikeaaa3a622010-03-20 22:32:34 -0700157 Enum string // set for enum types only
158 Default string // default value
159 def_uint64 uint64
160
David Symondsa80b2822012-03-14 14:31:25 +1100161 enc encoder
162 valEnc valueEncoder // set for bool and numeric types only
Russ Coxd4ce3f12012-09-12 10:36:26 +1000163 field field
David Symondsa80b2822012-03-14 14:31:25 +1100164 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
165 tagbuf [8]byte
David Symondsc0287172012-08-15 11:10:30 +1000166 stype reflect.Type // set for struct types only
167 sprop *StructProperties // set for struct types only
David Symondsa80b2822012-03-14 14:31:25 +1100168 isMarshaler bool
169 isUnmarshaler bool
Rob Pikeaaa3a622010-03-20 22:32:34 -0700170
David Symonds0bf1ad52013-10-11 09:07:50 +1100171 size sizer
172 valSize valueSizer // set for bool and numeric types only
173
David Symonds049646b2011-10-21 11:13:45 +1100174 dec decoder
175 valDec valueDecoder // set for bool and numeric types only
David Symonds5b7775e2010-12-01 10:09:04 +1100176
177 // If this is a packable field, this will be the decoder for the packed version of the field.
178 packedDec decoder
Rob Pikeaaa3a622010-03-20 22:32:34 -0700179}
180
David Symonds8935abf2011-07-04 15:53:16 +1000181// String formats the properties in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700182func (p *Properties) String() string {
183 s := p.Wire
184 s = ","
185 s += strconv.Itoa(p.Tag)
186 if p.Required {
187 s += ",req"
188 }
189 if p.Optional {
190 s += ",opt"
191 }
192 if p.Repeated {
193 s += ",rep"
194 }
David Symonds5b7775e2010-12-01 10:09:04 +1100195 if p.Packed {
196 s += ",packed"
197 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700198 if p.OrigName != p.Name {
199 s += ",name=" + p.OrigName
200 }
201 if len(p.Enum) > 0 {
202 s += ",enum=" + p.Enum
203 }
204 if len(p.Default) > 0 {
205 s += ",def=" + p.Default
206 }
207 return s
208}
209
David Symonds8935abf2011-07-04 15:53:16 +1000210// Parse populates p by parsing a string in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700211func (p *Properties) Parse(s string) {
David Symondsa7e9ef92012-01-18 18:27:58 +1100212 // "bytes,49,opt,name=foo,def=hello!"
David Symonds8935abf2011-07-04 15:53:16 +1000213 fields := strings.Split(s, ",") // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700214 if len(fields) < 2 {
215 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
216 return
217 }
218
219 p.Wire = fields[0]
220 switch p.Wire {
221 case "varint":
222 p.WireType = WireVarint
223 p.valEnc = (*Buffer).EncodeVarint
224 p.valDec = (*Buffer).DecodeVarint
David Symonds0bf1ad52013-10-11 09:07:50 +1100225 p.valSize = sizeVarint
Rob Pikeaaa3a622010-03-20 22:32:34 -0700226 case "fixed32":
227 p.WireType = WireFixed32
228 p.valEnc = (*Buffer).EncodeFixed32
229 p.valDec = (*Buffer).DecodeFixed32
David Symonds0bf1ad52013-10-11 09:07:50 +1100230 p.valSize = sizeFixed32
Rob Pikeaaa3a622010-03-20 22:32:34 -0700231 case "fixed64":
232 p.WireType = WireFixed64
233 p.valEnc = (*Buffer).EncodeFixed64
234 p.valDec = (*Buffer).DecodeFixed64
David Symonds0bf1ad52013-10-11 09:07:50 +1100235 p.valSize = sizeFixed64
Rob Pikeaaa3a622010-03-20 22:32:34 -0700236 case "zigzag32":
237 p.WireType = WireVarint
238 p.valEnc = (*Buffer).EncodeZigzag32
239 p.valDec = (*Buffer).DecodeZigzag32
David Symonds0bf1ad52013-10-11 09:07:50 +1100240 p.valSize = sizeZigzag32
Rob Pikeaaa3a622010-03-20 22:32:34 -0700241 case "zigzag64":
242 p.WireType = WireVarint
243 p.valEnc = (*Buffer).EncodeZigzag64
244 p.valDec = (*Buffer).DecodeZigzag64
David Symonds0bf1ad52013-10-11 09:07:50 +1100245 p.valSize = sizeZigzag64
Rob Pikeaaa3a622010-03-20 22:32:34 -0700246 case "bytes", "group":
247 p.WireType = WireBytes
248 // no numeric converter for non-numeric types
249 default:
250 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
251 return
252 }
253
Rob Pikea17fdd92011-11-02 12:43:05 -0700254 var err error
Rob Pikeaaa3a622010-03-20 22:32:34 -0700255 p.Tag, err = strconv.Atoi(fields[1])
256 if err != nil {
257 return
258 }
259
260 for i := 2; i < len(fields); i++ {
261 f := fields[i]
262 switch {
263 case f == "req":
264 p.Required = true
265 case f == "opt":
266 p.Optional = true
267 case f == "rep":
268 p.Repeated = true
David Symonds5b7775e2010-12-01 10:09:04 +1100269 case f == "packed":
270 p.Packed = true
David Symondsa7e9ef92012-01-18 18:27:58 +1100271 case strings.HasPrefix(f, "name="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000272 p.OrigName = f[5:]
David Symondsa7e9ef92012-01-18 18:27:58 +1100273 case strings.HasPrefix(f, "enum="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000274 p.Enum = f[5:]
David Symondsa7e9ef92012-01-18 18:27:58 +1100275 case strings.HasPrefix(f, "def="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000276 p.Default = f[4:] // rest of string
Rob Pikeaaa3a622010-03-20 22:32:34 -0700277 if i+1 < len(fields) {
278 // Commas aren't escaped, and def is always last.
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000279 p.Default += "," + strings.Join(fields[i+1:], ",")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700280 break
281 }
282 }
283 }
284}
285
David Symonds5922d072011-06-22 15:48:09 +1000286func logNoSliceEnc(t1, t2 reflect.Type) {
287 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
288}
289
David Symonds525838c2012-07-20 15:42:49 +1000290var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
291
Rob Pikeaaa3a622010-03-20 22:32:34 -0700292// Initialize the fields for encoding and decoding.
David Symondsc0287172012-08-15 11:10:30 +1000293func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700294 p.enc = nil
295 p.dec = nil
David Symonds0bf1ad52013-10-11 09:07:50 +1100296 p.size = nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700297
Rob Pike97e934d2011-04-11 12:52:49 -0700298 switch t1 := typ; t1.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700299 default:
300 fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700301
Rob Pike97e934d2011-04-11 12:52:49 -0700302 case reflect.Ptr:
303 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700304 default:
305 fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
306 break
Rob Pike97e934d2011-04-11 12:52:49 -0700307 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700308 p.enc = (*Buffer).enc_bool
309 p.dec = (*Buffer).dec_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100310 p.size = size_bool
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700311 case reflect.Int32, reflect.Uint32:
312 p.enc = (*Buffer).enc_int32
313 p.dec = (*Buffer).dec_int32
David Symonds0bf1ad52013-10-11 09:07:50 +1100314 p.size = size_int32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700315 case reflect.Int64, reflect.Uint64:
316 p.enc = (*Buffer).enc_int64
317 p.dec = (*Buffer).dec_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100318 p.size = size_int64
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700319 case reflect.Float32:
320 p.enc = (*Buffer).enc_int32 // can just treat them as bits
321 p.dec = (*Buffer).dec_int32
David Symonds0bf1ad52013-10-11 09:07:50 +1100322 p.size = size_int32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700323 case reflect.Float64:
324 p.enc = (*Buffer).enc_int64 // can just treat them as bits
325 p.dec = (*Buffer).dec_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100326 p.size = size_int64
Rob Pike97e934d2011-04-11 12:52:49 -0700327 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700328 p.enc = (*Buffer).enc_string
329 p.dec = (*Buffer).dec_string
David Symonds0bf1ad52013-10-11 09:07:50 +1100330 p.size = size_string
Rob Pike97e934d2011-04-11 12:52:49 -0700331 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000332 p.stype = t1.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100333 p.isMarshaler = isMarshaler(t1)
334 p.isUnmarshaler = isUnmarshaler(t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700335 if p.Wire == "bytes" {
336 p.enc = (*Buffer).enc_struct_message
337 p.dec = (*Buffer).dec_struct_message
David Symonds0bf1ad52013-10-11 09:07:50 +1100338 p.size = size_struct_message
Rob Pikeaaa3a622010-03-20 22:32:34 -0700339 } else {
340 p.enc = (*Buffer).enc_struct_group
341 p.dec = (*Buffer).dec_struct_group
David Symonds0bf1ad52013-10-11 09:07:50 +1100342 p.size = size_struct_group
Rob Pikeaaa3a622010-03-20 22:32:34 -0700343 }
344 }
345
Rob Pike97e934d2011-04-11 12:52:49 -0700346 case reflect.Slice:
347 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700348 default:
David Symonds5922d072011-06-22 15:48:09 +1000349 logNoSliceEnc(t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700350 break
Rob Pike97e934d2011-04-11 12:52:49 -0700351 case reflect.Bool:
David Symonds5b7775e2010-12-01 10:09:04 +1100352 if p.Packed {
353 p.enc = (*Buffer).enc_slice_packed_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100354 p.size = size_slice_packed_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100355 } else {
356 p.enc = (*Buffer).enc_slice_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100357 p.size = size_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100358 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700359 p.dec = (*Buffer).dec_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100360 p.packedDec = (*Buffer).dec_slice_packed_bool
Rob Pike97e934d2011-04-11 12:52:49 -0700361 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 -0700362 switch t2.Bits() {
363 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100364 if p.Packed {
365 p.enc = (*Buffer).enc_slice_packed_int32
David Symonds0bf1ad52013-10-11 09:07:50 +1100366 p.size = size_slice_packed_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100367 } else {
368 p.enc = (*Buffer).enc_slice_int32
David Symonds0bf1ad52013-10-11 09:07:50 +1100369 p.size = size_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100370 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700371 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100372 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700373 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100374 if p.Packed {
375 p.enc = (*Buffer).enc_slice_packed_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100376 p.size = size_slice_packed_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100377 } else {
378 p.enc = (*Buffer).enc_slice_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100379 p.size = size_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100380 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700381 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100382 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700383 case 8:
384 if t2.Kind() == reflect.Uint8 {
385 p.enc = (*Buffer).enc_slice_byte
386 p.dec = (*Buffer).dec_slice_byte
David Symonds0bf1ad52013-10-11 09:07:50 +1100387 p.size = size_slice_byte
Rob Pikeab5b8022010-06-21 17:47:58 -0700388 }
389 default:
David Symonds5922d072011-06-22 15:48:09 +1000390 logNoSliceEnc(t1, t2)
391 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700392 }
Rob Pike97e934d2011-04-11 12:52:49 -0700393 case reflect.Float32, reflect.Float64:
Rob Pikeab5b8022010-06-21 17:47:58 -0700394 switch t2.Bits() {
395 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100396 // can just treat them as bits
397 if p.Packed {
398 p.enc = (*Buffer).enc_slice_packed_int32
David Symonds0bf1ad52013-10-11 09:07:50 +1100399 p.size = size_slice_packed_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100400 } else {
401 p.enc = (*Buffer).enc_slice_int32
David Symonds0bf1ad52013-10-11 09:07:50 +1100402 p.size = size_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100403 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700404 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100405 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700406 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100407 // can just treat them as bits
408 if p.Packed {
409 p.enc = (*Buffer).enc_slice_packed_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100410 p.size = size_slice_packed_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100411 } else {
412 p.enc = (*Buffer).enc_slice_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100413 p.size = size_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100414 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700415 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100416 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700417 default:
David Symonds5922d072011-06-22 15:48:09 +1000418 logNoSliceEnc(t1, t2)
419 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700420 }
Rob Pike97e934d2011-04-11 12:52:49 -0700421 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700422 p.enc = (*Buffer).enc_slice_string
423 p.dec = (*Buffer).dec_slice_string
David Symonds0bf1ad52013-10-11 09:07:50 +1100424 p.size = size_slice_string
Rob Pike97e934d2011-04-11 12:52:49 -0700425 case reflect.Ptr:
426 switch t3 := t2.Elem(); t3.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700427 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700428 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700429 break
Rob Pike97e934d2011-04-11 12:52:49 -0700430 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000431 p.stype = t2.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100432 p.isMarshaler = isMarshaler(t2)
433 p.isUnmarshaler = isUnmarshaler(t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700434 if p.Wire == "bytes" {
435 p.enc = (*Buffer).enc_slice_struct_message
436 p.dec = (*Buffer).dec_slice_struct_message
David Symonds0bf1ad52013-10-11 09:07:50 +1100437 p.size = size_slice_struct_message
438 } else {
439 p.enc = (*Buffer).enc_slice_struct_group
440 p.dec = (*Buffer).dec_slice_struct_group
441 p.size = size_slice_struct_group
Rob Pikeaaa3a622010-03-20 22:32:34 -0700442 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700443 }
Rob Pike97e934d2011-04-11 12:52:49 -0700444 case reflect.Slice:
Rob Pikeab5b8022010-06-21 17:47:58 -0700445 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700446 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700447 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 -0700448 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700449 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700450 p.enc = (*Buffer).enc_slice_slice_byte
451 p.dec = (*Buffer).dec_slice_slice_byte
David Symonds0bf1ad52013-10-11 09:07:50 +1100452 p.size = size_slice_slice_byte
Rob Pikeaaa3a622010-03-20 22:32:34 -0700453 }
454 }
455 }
456
457 // precalculate tag code
David Symonds5b7775e2010-12-01 10:09:04 +1100458 wire := p.WireType
459 if p.Packed {
460 wire = WireBytes
461 }
David Symondsd73d7b12011-09-28 10:56:43 -0700462 x := uint32(p.Tag)<<3 | uint32(wire)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700463 i := 0
464 for i = 0; x > 127; i++ {
465 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
466 x >>= 7
467 }
468 p.tagbuf[i] = uint8(x)
469 p.tagcode = p.tagbuf[0 : i+1]
David Symondsc0287172012-08-15 11:10:30 +1000470
471 if p.stype != nil {
472 if lockGetProp {
David Symonds6a6f82c2012-08-22 09:18:54 +1000473 p.sprop = GetProperties(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000474 } else {
David Symonds6a6f82c2012-08-22 09:18:54 +1000475 p.sprop = getPropertiesLocked(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000476 }
477 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700478}
479
David Symondsa80b2822012-03-14 14:31:25 +1100480var (
481 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
482 unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
483)
484
485// isMarshaler reports whether type t implements Marshaler.
486func isMarshaler(t reflect.Type) bool {
487 // We're checking for (likely) pointer-receiver methods
488 // so if t is not a pointer, something is very wrong.
489 // The calls above only invoke isMarshaler on pointer types.
490 if t.Kind() != reflect.Ptr {
491 panic("proto: misuse of isMarshaler")
492 }
493 return t.Implements(marshalerType)
494}
495
496// isUnmarshaler reports whether type t implements Unmarshaler.
497func isUnmarshaler(t reflect.Type) bool {
498 // We're checking for (likely) pointer-receiver methods
499 // so if t is not a pointer, something is very wrong.
500 // The calls above only invoke isUnmarshaler on pointer types.
501 if t.Kind() != reflect.Ptr {
502 panic("proto: misuse of isUnmarshaler")
503 }
504 return t.Implements(unmarshalerType)
505}
506
David Symonds8935abf2011-07-04 15:53:16 +1000507// Init populates the properties from a protocol buffer struct tag.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000508func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
509 p.init(typ, name, tag, f, true)
David Symondsc0287172012-08-15 11:10:30 +1000510}
511
Russ Coxd4ce3f12012-09-12 10:36:26 +1000512func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
David Symonds8935abf2011-07-04 15:53:16 +1000513 // "bytes,49,opt,def=hello!"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700514 p.Name = name
515 p.OrigName = name
Russ Coxd4ce3f12012-09-12 10:36:26 +1000516 if f != nil {
517 p.field = toField(f)
518 }
David Symonds8935abf2011-07-04 15:53:16 +1000519 if tag == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700520 return
521 }
David Symonds8935abf2011-07-04 15:53:16 +1000522 p.Parse(tag)
David Symondsc0287172012-08-15 11:10:30 +1000523 p.setEncAndDec(typ, lockGetProp)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700524}
525
526var (
527 mutex sync.Mutex
Rob Pike97e934d2011-04-11 12:52:49 -0700528 propertiesMap = make(map[reflect.Type]*StructProperties)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700529)
530
531// GetProperties returns the list of properties for the type represented by t.
Rob Pike97e934d2011-04-11 12:52:49 -0700532func GetProperties(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700533 mutex.Lock()
David Symondsc0287172012-08-15 11:10:30 +1000534 sprop := getPropertiesLocked(t)
535 mutex.Unlock()
536 return sprop
537}
538
539// getPropertiesLocked requires that mutex is held.
540func getPropertiesLocked(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700541 if prop, ok := propertiesMap[t]; ok {
David Symonds9f60f432012-06-14 09:45:25 +1000542 if collectStats {
543 stats.Chit++
544 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700545 return prop
546 }
David Symonds9f60f432012-06-14 09:45:25 +1000547 if collectStats {
548 stats.Cmiss++
549 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700550
551 prop := new(StructProperties)
David Symondsc0287172012-08-15 11:10:30 +1000552 // in case of recursive protos, fill this in now.
553 propertiesMap[t] = prop
Rob Pikeaaa3a622010-03-20 22:32:34 -0700554
555 // build properties
Russ Coxd4ce3f12012-09-12 10:36:26 +1000556 prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
557 prop.unrecField = invalidField
Rob Pikeaaa3a622010-03-20 22:32:34 -0700558 prop.Prop = make([]*Properties, t.NumField())
David Symondsd15e81b2011-10-03 14:31:12 -0700559 prop.order = make([]int, t.NumField())
David Symonds20370902013-03-23 17:20:01 +1100560
Rob Pikeaaa3a622010-03-20 22:32:34 -0700561 for i := 0; i < t.NumField(); i++ {
562 f := t.Field(i)
563 p := new(Properties)
David Symonds20370902013-03-23 17:20:01 +1100564 name := f.Name
565 p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
566
Rob Pikeaaa3a622010-03-20 22:32:34 -0700567 if f.Name == "XXX_extensions" { // special case
Rob Pikeaaa3a622010-03-20 22:32:34 -0700568 p.enc = (*Buffer).enc_map
569 p.dec = nil // not needed
David Symonds0bf1ad52013-10-11 09:07:50 +1100570 p.size = size_map
Rob Pikeaaa3a622010-03-20 22:32:34 -0700571 }
David Symonds10c93ba2012-08-04 16:38:08 +1000572 if f.Name == "XXX_unrecognized" { // special case
Russ Coxd4ce3f12012-09-12 10:36:26 +1000573 prop.unrecField = toField(&f)
David Symonds10c93ba2012-08-04 16:38:08 +1000574 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700575 prop.Prop[i] = p
David Symondsd15e81b2011-10-03 14:31:12 -0700576 prop.order[i] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700577 if debug {
578 print(i, " ", f.Name, " ", t.String(), " ")
579 if p.Tag > 0 {
580 print(p.String())
581 }
582 print("\n")
583 }
584 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
585 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
586 }
587 }
588
David Symondsd15e81b2011-10-03 14:31:12 -0700589 // Re-order prop.order.
590 sort.Sort(prop)
591
Rob Pikeaaa3a622010-03-20 22:32:34 -0700592 // build required counts
Rob Pikeaaa3a622010-03-20 22:32:34 -0700593 // build tags
594 reqCount := 0
David Symonds2bba1b22012-09-26 14:53:08 +1000595 prop.decoderOrigNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700596 for i, p := range prop.Prop {
David Symonds6e50db52012-02-11 15:56:22 +1100597 if strings.HasPrefix(p.Name, "XXX_") {
598 // Internal fields should not appear in tags/origNames maps.
599 // They are handled specially when encoding and decoding.
600 continue
601 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700602 if p.Required {
603 reqCount++
604 }
David Symonds2bba1b22012-09-26 14:53:08 +1000605 prop.decoderTags.put(p.Tag, i)
606 prop.decoderOrigNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700607 }
608 prop.reqCount = reqCount
Rob Pikeaaa3a622010-03-20 22:32:34 -0700609
Rob Pikeaaa3a622010-03-20 22:32:34 -0700610 return prop
611}
612
Rob Pikeaaa3a622010-03-20 22:32:34 -0700613// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700614func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700615 if len(x) != 1 {
616 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
617 return nil
618 }
619 prop := GetProperties(t)
620 return prop.Prop[x[0]]
621}
622
David Symonds7656e742011-07-22 14:54:17 +1000623// Get the address and type of a pointer to a struct from an interface.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000624func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
Rob Pikef1b341e2011-10-20 14:51:10 -0700625 if pb == nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700626 err = ErrNil
627 return
628 }
Rob Pikef1b341e2011-10-20 14:51:10 -0700629 // get the reflect type of the pointer to the struct.
Nigel Tao4ede8452011-04-28 11:27:25 +1000630 t = reflect.TypeOf(pb)
Rob Pikef1b341e2011-10-20 14:51:10 -0700631 // get the address of the struct.
632 value := reflect.ValueOf(pb)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000633 b = toStructPointer(value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700634 return
635}
636
Rob Pikeaaa3a622010-03-20 22:32:34 -0700637// A global registry of enum types.
638// The generated code will register the generated maps by calling RegisterEnum.
639
Rob Pikeaaa3a622010-03-20 22:32:34 -0700640var enumValueMaps = make(map[string]map[string]int32)
641
642// RegisterEnum is called from the generated code to install the enum descriptor
David Symondsf8a1fcc2013-05-03 08:51:23 +1000643// maps into the global table to aid parsing text format protocol buffers.
644func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
645 if _, ok := enumValueMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700646 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700647 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700648 enumValueMaps[typeName] = valueMap
649}