blob: fa6fe22ea25e1c015abdb7b33f81e36649d62abf [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
32/*
David Symondsefeca9a2012-05-08 10:36:04 +100033 Package proto converts data structures to and from the wire format of
34 protocol buffers. It works in concert with the Go source code generated
35 for .proto files by the protocol compiler.
Rob Pikeaaa3a622010-03-20 22:32:34 -070036
37 A summary of the properties of the protocol buffer interface
38 for a protocol buffer variable v:
39
40 - Names are turned from camel_case to CamelCase for export.
David Symonds87c9bcc2012-06-28 10:42:01 -070041 - There are no methods on v to set fields; just treat
Rob Pikeaaa3a622010-03-20 22:32:34 -070042 them as structure fields.
David Symonds87c9bcc2012-06-28 10:42:01 -070043 - There are getters that return a field's value if set,
44 and return the field's default value if unset.
45 The getters work even if the receiver is a nil message.
Rob Pikeaaa3a622010-03-20 22:32:34 -070046 - The zero value for a struct is its correct initialization state.
47 All desired fields must be set before marshaling.
48 - A Reset() method will restore a protobuf struct to its zero state.
Rob Pikeaaa3a622010-03-20 22:32:34 -070049 - Non-repeated fields are pointers to the values; nil means unset.
50 That is, optional or required field int32 f becomes F *int32.
51 - Repeated fields are slices.
David Symonds87c9bcc2012-06-28 10:42:01 -070052 - Helper functions are available to aid the setting of fields.
53 Helpers for getting values are superseded by the
54 GetFoo methods and their use is deprecated.
55 msg.Foo = proto.String("hello") // set field
Rob Pikeaaa3a622010-03-20 22:32:34 -070056 - Constants are defined to hold the default values of all fields that
57 have them. They have the form Default_StructName_FieldName.
David Symonds87c9bcc2012-06-28 10:42:01 -070058 Because the getter methods handle defaulted values,
59 direct use of these constants should be rare.
David Symondsefeca9a2012-05-08 10:36:04 +100060 - Enums are given type names and maps from names to values.
61 Enum values are prefixed with the enum's type name. Enum types have
62 a String method, and a Enum method to assist in message construction.
Rob Pikeaaa3a622010-03-20 22:32:34 -070063 - Nested groups and enums have type names prefixed with the name of
64 the surrounding message type.
David Symonds9bd0a832010-04-11 10:02:32 +100065 - Extensions are given descriptor names that start with E_,
66 followed by an underscore-delimited list of the nested messages
67 that contain it (if any) followed by the CamelCased name of the
68 extension field itself. HasExtension, ClearExtension, GetExtension
69 and SetExtension are functions for manipulating extensions.
Rob Pikeaaa3a622010-03-20 22:32:34 -070070 - Marshal and Unmarshal are functions to encode and decode the wire format.
71
72 The simplest way to describe this is to see an example.
73 Given file test.proto, containing
74
75 package example;
76
77 enum FOO { X = 17; };
78
79 message Test {
80 required string label = 1;
81 optional int32 type = 2 [default=77];
82 repeated int64 reps = 3;
83 optional group OptionalGroup = 4 {
84 required string RequiredField = 5;
David Symondsefeca9a2012-05-08 10:36:04 +100085 }
Rob Pikeaaa3a622010-03-20 22:32:34 -070086 }
87
88 The resulting file, test.pb.go, is:
89
90 package example
91
Rob Pike3f6f2d82011-12-18 13:55:35 -080092 import "code.google.com/p/goprotobuf/proto"
Rob Pikeaaa3a622010-03-20 22:32:34 -070093
94 type FOO int32
95 const (
David Symondsefeca9a2012-05-08 10:36:04 +100096 FOO_X FOO = 17
Rob Pikeaaa3a622010-03-20 22:32:34 -070097 )
David Symondsefeca9a2012-05-08 10:36:04 +100098 var FOO_name = map[int32]string{
Rob Pikeaaa3a622010-03-20 22:32:34 -070099 17: "X",
100 }
David Symondsefeca9a2012-05-08 10:36:04 +1000101 var FOO_value = map[string]int32{
Rob Pikeaaa3a622010-03-20 22:32:34 -0700102 "X": 17,
103 }
David Symondsefeca9a2012-05-08 10:36:04 +1000104
105 func (x FOO) Enum() *FOO {
106 p := new(FOO)
107 *p = x
108 return p
Rob Pikeaaa3a622010-03-20 22:32:34 -0700109 }
David Symonds350c58f2011-08-03 12:09:32 +1000110 func (x FOO) String() string {
111 return proto.EnumName(FOO_name, int32(x))
112 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700113
114 type Test struct {
David Symondsefeca9a2012-05-08 10:36:04 +1000115 Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
116 Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
117 Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
118 Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
119 XXX_unrecognized []byte `json:"-"`
Rob Pikeaaa3a622010-03-20 22:32:34 -0700120 }
David Symondsefeca9a2012-05-08 10:36:04 +1000121 func (this *Test) Reset() { *this = Test{} }
122 func (this *Test) String() string { return proto.CompactTextString(this) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700123 const Default_Test_Type int32 = 77
124
David Symonds87c9bcc2012-06-28 10:42:01 -0700125 func (this *Test) GetLabel() string {
126 if this != nil && this.Label != nil {
127 return *this.Label
128 }
129 return ""
130 }
131
132 func (this *Test) GetType() int32 {
133 if this != nil && this.Type != nil {
134 return *this.Type
135 }
136 return Default_Test_Type
137 }
138
139 func (this *Test) GetOptionalgroup() *Test_OptionalGroup {
140 if this != nil {
141 return this.Optionalgroup
142 }
143 return nil
144 }
145
Rob Pikeaaa3a622010-03-20 22:32:34 -0700146 type Test_OptionalGroup struct {
David Symondsefeca9a2012-05-08 10:36:04 +1000147 RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
148 XXX_unrecognized []byte `json:"-"`
Rob Pikeaaa3a622010-03-20 22:32:34 -0700149 }
David Symondsefeca9a2012-05-08 10:36:04 +1000150 func (this *Test_OptionalGroup) Reset() { *this = Test_OptionalGroup{} }
151 func (this *Test_OptionalGroup) String() string { return proto.CompactTextString(this) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700152
David Symonds87c9bcc2012-06-28 10:42:01 -0700153 func (this *Test_OptionalGroup) GetRequiredField() string {
154 if this != nil && this.RequiredField != nil {
155 return *this.RequiredField
156 }
157 return ""
158 }
159
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160 func init() {
161 proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
162 }
163
164 To create and play with a Test object:
165
166 package main
167
168 import (
169 "log"
170
Rob Pike3f6f2d82011-12-18 13:55:35 -0800171 "code.google.com/p/goprotobuf/proto"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700172 "./example.pb"
173 )
174
175 func main() {
David Symondscc7142e2010-11-06 14:37:15 +1100176 test := &example.Test{
Rob Pikeaaa3a622010-03-20 22:32:34 -0700177 Label: proto.String("hello"),
David Symondsefeca9a2012-05-08 10:36:04 +1000178 Type: proto.Int32(17),
David Symondscc7142e2010-11-06 14:37:15 +1100179 Optionalgroup: &example.Test_OptionalGroup{
Rob Pikeaaa3a622010-03-20 22:32:34 -0700180 RequiredField: proto.String("good bye"),
181 },
182 }
183 data, err := proto.Marshal(test)
184 if err != nil {
Rob Pike4202e4d2011-02-11 16:06:41 -0800185 log.Fatal("marshaling error: ", err)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700186 }
David Symondscc7142e2010-11-06 14:37:15 +1100187 newTest := new(example.Test)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700188 err = proto.Unmarshal(data, newTest)
189 if err != nil {
Rob Pike4202e4d2011-02-11 16:06:41 -0800190 log.Fatal("unmarshaling error: ", err)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700191 }
192 // Now test and newTest contain the same data.
David Symonds87c9bcc2012-06-28 10:42:01 -0700193 if test.GetLabel() != newTest.GetLabel() {
194 log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700195 }
196 // etc.
197 }
198*/
199package proto
200
201import (
David Symonds62539862012-08-04 10:06:55 +1000202 "encoding/json"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700203 "fmt"
David Symondsb79d99b2011-08-29 16:38:49 +1000204 "log"
205 "reflect"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700206 "strconv"
David Symondsb79d99b2011-08-29 16:38:49 +1000207 "sync"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700208)
209
David Symonds9f60f432012-06-14 09:45:25 +1000210// Message is implemented by generated protocol buffer messages.
211type Message interface {
212 Reset()
213 String() string
214 ProtoMessage()
215}
216
Rob Pikeaaa3a622010-03-20 22:32:34 -0700217// Stats records allocation details about the protocol buffer encoders
218// and decoders. Useful for tuning the library itself.
219type Stats struct {
220 Emalloc uint64 // mallocs in encode
221 Dmalloc uint64 // mallocs in decode
222 Encode uint64 // number of encodes
223 Decode uint64 // number of decodes
224 Chit uint64 // number of cache hits
225 Cmiss uint64 // number of cache misses
226}
227
David Symonds9f60f432012-06-14 09:45:25 +1000228// Set to true to enable stats collection.
229const collectStats = false
230
Rob Pikeaaa3a622010-03-20 22:32:34 -0700231var stats Stats
232
233// GetStats returns a copy of the global Stats structure.
234func GetStats() Stats { return stats }
235
236// A Buffer is a buffer manager for marshaling and unmarshaling
237// protocol buffers. It may be reused between invocations to
238// reduce memory usage. It is not necessary to use a Buffer;
239// the global functions Marshal and Unmarshal create a
240// temporary Buffer and are fine for most applications.
241type Buffer struct {
242 buf []byte // encode/decode byte stream
243 index int // write point
244 freelist [10][]byte // list of available buffers
245 nfreelist int // number of free buffers
Russ Coxd4ce3f12012-09-12 10:36:26 +1000246
Rob Pike76f6ee52011-10-20 12:58:28 -0700247 // pools of basic types to amortize allocation.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000248 bools []bool
249 uint32s []uint32
250 uint64s []uint64
251
252 // extra pools, only used with pointer_reflect.go
253 int32s []int32
254 int64s []int64
255 float32s []float32
256 float64s []float64
Rob Pikeaaa3a622010-03-20 22:32:34 -0700257}
258
259// NewBuffer allocates a new Buffer and initializes its internal data to
260// the contents of the argument slice.
261func NewBuffer(e []byte) *Buffer {
262 p := new(Buffer)
263 if e == nil {
264 e = p.bufalloc()
265 }
266 p.buf = e
267 p.index = 0
268 return p
269}
270
271// Reset resets the Buffer, ready for marshaling a new protocol buffer.
272func (p *Buffer) Reset() {
273 if p.buf == nil {
274 p.buf = p.bufalloc()
275 }
276 p.buf = p.buf[0:0] // for reading/writing
277 p.index = 0 // for reading
278}
279
280// SetBuf replaces the internal buffer with the slice,
281// ready for unmarshaling the contents of the slice.
282func (p *Buffer) SetBuf(s []byte) {
283 p.buf = s
284 p.index = 0
285}
286
287// Bytes returns the contents of the Buffer.
288func (p *Buffer) Bytes() []byte { return p.buf }
289
290// Allocate a buffer for the Buffer.
291func (p *Buffer) bufalloc() []byte {
292 if p.nfreelist > 0 {
293 // reuse an old one
294 p.nfreelist--
295 s := p.freelist[p.nfreelist]
296 return s[0:0]
297 }
298 // make a new one
299 s := make([]byte, 0, 16)
300 return s
301}
302
303// Free (and remember in freelist) a byte buffer for the Buffer.
304func (p *Buffer) buffree(s []byte) {
305 if p.nfreelist < len(p.freelist) {
306 // Take next slot.
307 p.freelist[p.nfreelist] = s
308 p.nfreelist++
309 return
310 }
311
312 // Find the smallest.
313 besti := -1
314 bestl := len(s)
315 for i, b := range p.freelist {
316 if len(b) < bestl {
317 besti = i
318 bestl = len(b)
319 }
320 }
321
322 // Overwrite the smallest.
323 if besti >= 0 {
324 p.freelist[besti] = s
325 }
326}
327
328/*
329 * Helper routines for simplifying the creation of optional fields of basic type.
330 */
331
332// Bool is a helper routine that allocates a new bool value
333// to store v and returns a pointer to it.
334func Bool(v bool) *bool {
David Symondsfff2ec62013-08-08 13:37:09 +1000335 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700336}
337
338// Int32 is a helper routine that allocates a new int32 value
339// to store v and returns a pointer to it.
340func Int32(v int32) *int32 {
David Symondsfff2ec62013-08-08 13:37:09 +1000341 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700342}
343
344// Int is a helper routine that allocates a new int32 value
345// to store v and returns a pointer to it, but unlike Int32
346// its argument value is an int.
347func Int(v int) *int32 {
348 p := new(int32)
349 *p = int32(v)
350 return p
351}
352
353// Int64 is a helper routine that allocates a new int64 value
354// to store v and returns a pointer to it.
355func Int64(v int64) *int64 {
David Symondsfff2ec62013-08-08 13:37:09 +1000356 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700357}
358
359// Float32 is a helper routine that allocates a new float32 value
360// to store v and returns a pointer to it.
361func Float32(v float32) *float32 {
David Symondsfff2ec62013-08-08 13:37:09 +1000362 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700363}
364
365// Float64 is a helper routine that allocates a new float64 value
366// to store v and returns a pointer to it.
367func Float64(v float64) *float64 {
David Symondsfff2ec62013-08-08 13:37:09 +1000368 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700369}
370
371// Uint32 is a helper routine that allocates a new uint32 value
372// to store v and returns a pointer to it.
373func Uint32(v uint32) *uint32 {
374 p := new(uint32)
375 *p = v
376 return p
377}
378
379// Uint64 is a helper routine that allocates a new uint64 value
380// to store v and returns a pointer to it.
381func Uint64(v uint64) *uint64 {
David Symondsfff2ec62013-08-08 13:37:09 +1000382 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700383}
384
385// String is a helper routine that allocates a new string value
386// to store v and returns a pointer to it.
387func String(v string) *string {
David Symondsfff2ec62013-08-08 13:37:09 +1000388 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700389}
390
Rob Pikeaaa3a622010-03-20 22:32:34 -0700391// EnumName is a helper function to simplify printing protocol buffer enums
392// by name. Given an enum map and a value, it returns a useful string.
393func EnumName(m map[int32]string, v int32) string {
394 s, ok := m[v]
395 if ok {
396 return s
397 }
David Symondsf8a1fcc2013-05-03 08:51:23 +1000398 return strconv.Itoa(int(v))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700399}
400
David Symonds62539862012-08-04 10:06:55 +1000401// UnmarshalJSONEnum is a helper function to simplify recovering enum int values
402// from their JSON-encoded representation. Given a map from the enum's symbolic
403// names to its int values, and a byte buffer containing the JSON-encoded
404// value, it returns an int32 that can be cast to the enum type by the caller.
405//
406// The function can deal with older JSON representations, which represented
407// enums directly by their int32 values, or with newer representations, which
408// use the symbolic name as a string.
409func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
410 if data[0] == '"' {
411 // New style: enums are strings.
412 var repr string
413 if err := json.Unmarshal(data, &repr); err != nil {
414 return -1, err
415 }
416 val, ok := m[repr]
417 if !ok {
418 return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
419 }
420 return val, nil
421 }
422 // Old style: enums are ints.
423 var val int32
424 if err := json.Unmarshal(data, &val); err != nil {
425 return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
426 }
427 return val, nil
428}
429
Rob Pikeaaa3a622010-03-20 22:32:34 -0700430// DebugPrint dumps the encoded data in b in a debugging format with a header
431// including the string s. Used in testing but made available for general debugging.
432func (o *Buffer) DebugPrint(s string, b []byte) {
433 var u uint64
434
435 obuf := o.buf
436 index := o.index
437 o.buf = b
438 o.index = 0
439 depth := 0
440
441 fmt.Printf("\n--- %s ---\n", s)
442
443out:
444 for {
445 for i := 0; i < depth; i++ {
446 fmt.Print(" ")
447 }
448
449 index := o.index
450 if index == len(o.buf) {
451 break
452 }
453
454 op, err := o.DecodeVarint()
455 if err != nil {
456 fmt.Printf("%3d: fetching op err %v\n", index, err)
457 break out
458 }
459 tag := op >> 3
460 wire := op & 7
461
462 switch wire {
463 default:
464 fmt.Printf("%3d: t=%3d unknown wire=%d\n",
465 index, tag, wire)
466 break out
467
468 case WireBytes:
469 var r []byte
470
471 r, err = o.DecodeRawBytes(false)
472 if err != nil {
473 break out
474 }
475 fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r))
476 if len(r) <= 6 {
477 for i := 0; i < len(r); i++ {
478 fmt.Printf(" %.2x", r[i])
479 }
480 } else {
481 for i := 0; i < 3; i++ {
482 fmt.Printf(" %.2x", r[i])
483 }
484 fmt.Printf(" ..")
485 for i := len(r) - 3; i < len(r); i++ {
486 fmt.Printf(" %.2x", r[i])
487 }
488 }
489 fmt.Printf("\n")
490
491 case WireFixed32:
492 u, err = o.DecodeFixed32()
493 if err != nil {
494 fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err)
495 break out
496 }
497 fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u)
498
499 case WireFixed64:
500 u, err = o.DecodeFixed64()
501 if err != nil {
502 fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err)
503 break out
504 }
505 fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
506 break
507
508 case WireVarint:
509 u, err = o.DecodeVarint()
510 if err != nil {
511 fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err)
512 break out
513 }
514 fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
515
516 case WireStartGroup:
517 if err != nil {
518 fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err)
519 break out
520 }
521 fmt.Printf("%3d: t=%3d start\n", index, tag)
522 depth++
523
524 case WireEndGroup:
525 depth--
526 if err != nil {
527 fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err)
528 break out
529 }
530 fmt.Printf("%3d: t=%3d end\n", index, tag)
531 }
532 }
533
534 if depth != 0 {
535 fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth)
536 }
537 fmt.Printf("\n")
538
539 o.buf = obuf
540 o.index = index
541}
David Symondsb79d99b2011-08-29 16:38:49 +1000542
543// SetDefaults sets unset protocol buffer fields to their default values.
544// It only modifies fields that are both unset and have defined defaults.
545// It recursively sets default values in any non-nil sub-messages.
David Symonds9f60f432012-06-14 09:45:25 +1000546func SetDefaults(pb Message) {
547 setDefaults(reflect.ValueOf(pb), true, false)
David Symondsb79d99b2011-08-29 16:38:49 +1000548}
549
550// v is a pointer to a struct.
551func setDefaults(v reflect.Value, recur, zeros bool) {
552 v = v.Elem()
553
David Symonds72607582011-11-01 12:52:01 +1100554 defaultMu.RLock()
David Symondsb79d99b2011-08-29 16:38:49 +1000555 dm, ok := defaults[v.Type()]
David Symonds72607582011-11-01 12:52:01 +1100556 defaultMu.RUnlock()
David Symondsb79d99b2011-08-29 16:38:49 +1000557 if !ok {
558 dm = buildDefaultMessage(v.Type())
559 defaultMu.Lock()
560 defaults[v.Type()] = dm
561 defaultMu.Unlock()
562 }
563
564 for _, sf := range dm.scalars {
565 f := v.Field(sf.index)
566 if !f.IsNil() {
567 // field already set
568 continue
569 }
570 dv := sf.value
571 if dv == nil && !zeros {
572 // no explicit default, and don't want to set zeros
573 continue
574 }
575 fptr := f.Addr().Interface() // **T
576 // TODO: Consider batching the allocations we do here.
577 switch sf.kind {
578 case reflect.Bool:
579 b := new(bool)
580 if dv != nil {
581 *b = dv.(bool)
582 }
583 *(fptr.(**bool)) = b
584 case reflect.Float32:
585 f := new(float32)
586 if dv != nil {
587 *f = dv.(float32)
588 }
589 *(fptr.(**float32)) = f
590 case reflect.Float64:
591 f := new(float64)
592 if dv != nil {
593 *f = dv.(float64)
594 }
595 *(fptr.(**float64)) = f
596 case reflect.Int32:
597 // might be an enum
598 if ft := f.Type(); ft != int32PtrType {
599 // enum
600 f.Set(reflect.New(ft.Elem()))
601 if dv != nil {
602 f.Elem().SetInt(int64(dv.(int32)))
603 }
604 } else {
605 // int32 field
606 i := new(int32)
607 if dv != nil {
608 *i = dv.(int32)
609 }
610 *(fptr.(**int32)) = i
611 }
612 case reflect.Int64:
613 i := new(int64)
614 if dv != nil {
615 *i = dv.(int64)
616 }
617 *(fptr.(**int64)) = i
618 case reflect.String:
619 s := new(string)
620 if dv != nil {
621 *s = dv.(string)
622 }
623 *(fptr.(**string)) = s
624 case reflect.Uint8:
625 // exceptional case: []byte
626 var b []byte
627 if dv != nil {
628 db := dv.([]byte)
629 b = make([]byte, len(db))
630 copy(b, db)
631 } else {
632 b = []byte{}
633 }
634 *(fptr.(*[]byte)) = b
635 case reflect.Uint32:
636 u := new(uint32)
637 if dv != nil {
638 *u = dv.(uint32)
639 }
640 *(fptr.(**uint32)) = u
641 case reflect.Uint64:
642 u := new(uint64)
643 if dv != nil {
644 *u = dv.(uint64)
645 }
646 *(fptr.(**uint64)) = u
647 default:
648 log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind)
649 }
650 }
651
652 for _, ni := range dm.nested {
David Symonds814b9362011-12-13 09:10:47 +1100653 f := v.Field(ni)
654 if f.IsNil() {
655 continue
656 }
David Symonds472e2592013-07-15 11:10:07 +1000657 // f is *T or []*T
658 if f.Kind() == reflect.Ptr {
659 setDefaults(f, recur, zeros)
660 } else {
661 for i := 0; i < f.Len(); i++ {
662 e := f.Index(i)
663 if e.IsNil() {
664 continue
665 }
666 setDefaults(e, recur, zeros)
667 }
668 }
David Symondsb79d99b2011-08-29 16:38:49 +1000669 }
670}
671
672var (
673 // defaults maps a protocol buffer struct type to a slice of the fields,
674 // with its scalar fields set to their proto-declared non-zero default values.
David Symonds72607582011-11-01 12:52:01 +1100675 defaultMu sync.RWMutex
David Symondsb79d99b2011-08-29 16:38:49 +1000676 defaults = make(map[reflect.Type]defaultMessage)
677
678 int32PtrType = reflect.TypeOf((*int32)(nil))
679)
680
681// defaultMessage represents information about the default values of a message.
682type defaultMessage struct {
683 scalars []scalarField
684 nested []int // struct field index of nested messages
685}
686
687type scalarField struct {
688 index int // struct field index
689 kind reflect.Kind // element type (the T in *T or []T)
690 value interface{} // the proto-declared default value, or nil
691}
692
David Symonds472e2592013-07-15 11:10:07 +1000693func ptrToStruct(t reflect.Type) bool {
694 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
695}
696
David Symondsb79d99b2011-08-29 16:38:49 +1000697// t is a struct type.
698func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
699 sprop := GetProperties(t)
700 for _, prop := range sprop.Prop {
David Symonds2bba1b22012-09-26 14:53:08 +1000701 fi, ok := sprop.decoderTags.get(prop.Tag)
David Symonds6a6f82c2012-08-22 09:18:54 +1000702 if !ok {
703 // XXX_unrecognized
704 continue
705 }
David Symondsb79d99b2011-08-29 16:38:49 +1000706 ft := t.Field(fi).Type
707
708 // nested messages
David Symonds472e2592013-07-15 11:10:07 +1000709 if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) {
David Symondsb79d99b2011-08-29 16:38:49 +1000710 dm.nested = append(dm.nested, fi)
711 continue
712 }
713
714 sf := scalarField{
715 index: fi,
716 kind: ft.Elem().Kind(),
717 }
718
719 // scalar fields without defaults
720 if prop.Default == "" {
721 dm.scalars = append(dm.scalars, sf)
722 continue
723 }
724
725 // a scalar field: either *T or []byte
726 switch ft.Elem().Kind() {
727 case reflect.Bool:
David Symonds93be46f2011-12-08 12:58:23 +1100728 x, err := strconv.ParseBool(prop.Default)
David Symondsb79d99b2011-08-29 16:38:49 +1000729 if err != nil {
730 log.Printf("proto: bad default bool %q: %v", prop.Default, err)
731 continue
732 }
733 sf.value = x
734 case reflect.Float32:
David Symonds93be46f2011-12-08 12:58:23 +1100735 x, err := strconv.ParseFloat(prop.Default, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000736 if err != nil {
737 log.Printf("proto: bad default float32 %q: %v", prop.Default, err)
738 continue
739 }
David Symonds93be46f2011-12-08 12:58:23 +1100740 sf.value = float32(x)
David Symondsb79d99b2011-08-29 16:38:49 +1000741 case reflect.Float64:
David Symonds93be46f2011-12-08 12:58:23 +1100742 x, err := strconv.ParseFloat(prop.Default, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000743 if err != nil {
744 log.Printf("proto: bad default float64 %q: %v", prop.Default, err)
745 continue
746 }
747 sf.value = x
748 case reflect.Int32:
David Symonds93be46f2011-12-08 12:58:23 +1100749 x, err := strconv.ParseInt(prop.Default, 10, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000750 if err != nil {
751 log.Printf("proto: bad default int32 %q: %v", prop.Default, err)
752 continue
753 }
754 sf.value = int32(x)
755 case reflect.Int64:
David Symonds93be46f2011-12-08 12:58:23 +1100756 x, err := strconv.ParseInt(prop.Default, 10, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000757 if err != nil {
758 log.Printf("proto: bad default int64 %q: %v", prop.Default, err)
759 continue
760 }
761 sf.value = x
762 case reflect.String:
763 sf.value = prop.Default
764 case reflect.Uint8:
765 // []byte (not *uint8)
766 sf.value = []byte(prop.Default)
767 case reflect.Uint32:
David Symonds93be46f2011-12-08 12:58:23 +1100768 x, err := strconv.ParseUint(prop.Default, 10, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000769 if err != nil {
770 log.Printf("proto: bad default uint32 %q: %v", prop.Default, err)
771 continue
772 }
773 sf.value = uint32(x)
774 case reflect.Uint64:
David Symonds93be46f2011-12-08 12:58:23 +1100775 x, err := strconv.ParseUint(prop.Default, 10, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000776 if err != nil {
777 log.Printf("proto: bad default uint64 %q: %v", prop.Default, err)
778 continue
779 }
780 sf.value = x
781 default:
782 log.Printf("proto: unhandled def kind %v", ft.Elem().Kind())
783 continue
784 }
785
786 dm.scalars = append(dm.scalars, sf)
787 }
788
789 return dm
790}