blob: e22084ef15811d5134cc31884dbc0e8f483e4d19 [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
David Symonds0bf1ad52013-10-11 09:07:50 +1100226 Size uint64 // number of sizes
Rob Pikeaaa3a622010-03-20 22:32:34 -0700227}
228
David Symonds9f60f432012-06-14 09:45:25 +1000229// Set to true to enable stats collection.
230const collectStats = false
231
Rob Pikeaaa3a622010-03-20 22:32:34 -0700232var stats Stats
233
234// GetStats returns a copy of the global Stats structure.
235func GetStats() Stats { return stats }
236
237// A Buffer is a buffer manager for marshaling and unmarshaling
238// protocol buffers. It may be reused between invocations to
239// reduce memory usage. It is not necessary to use a Buffer;
240// the global functions Marshal and Unmarshal create a
241// temporary Buffer and are fine for most applications.
242type Buffer struct {
David Symonds8b253302014-01-14 16:24:19 +1100243 buf []byte // encode/decode byte stream
244 index int // write point
Russ Coxd4ce3f12012-09-12 10:36:26 +1000245
Rob Pike76f6ee52011-10-20 12:58:28 -0700246 // pools of basic types to amortize allocation.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000247 bools []bool
248 uint32s []uint32
249 uint64s []uint64
250
251 // extra pools, only used with pointer_reflect.go
252 int32s []int32
253 int64s []int64
254 float32s []float32
255 float64s []float64
Rob Pikeaaa3a622010-03-20 22:32:34 -0700256}
257
258// NewBuffer allocates a new Buffer and initializes its internal data to
259// the contents of the argument slice.
260func NewBuffer(e []byte) *Buffer {
David Symonds8b253302014-01-14 16:24:19 +1100261 return &Buffer{buf: e}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700262}
263
264// Reset resets the Buffer, ready for marshaling a new protocol buffer.
265func (p *Buffer) Reset() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700266 p.buf = p.buf[0:0] // for reading/writing
267 p.index = 0 // for reading
268}
269
270// SetBuf replaces the internal buffer with the slice,
271// ready for unmarshaling the contents of the slice.
272func (p *Buffer) SetBuf(s []byte) {
273 p.buf = s
274 p.index = 0
275}
276
277// Bytes returns the contents of the Buffer.
278func (p *Buffer) Bytes() []byte { return p.buf }
279
Rob Pikeaaa3a622010-03-20 22:32:34 -0700280/*
281 * Helper routines for simplifying the creation of optional fields of basic type.
282 */
283
284// Bool is a helper routine that allocates a new bool value
285// to store v and returns a pointer to it.
286func Bool(v bool) *bool {
David Symondsfff2ec62013-08-08 13:37:09 +1000287 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700288}
289
290// Int32 is a helper routine that allocates a new int32 value
291// to store v and returns a pointer to it.
292func Int32(v int32) *int32 {
David Symondsfff2ec62013-08-08 13:37:09 +1000293 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700294}
295
296// Int is a helper routine that allocates a new int32 value
297// to store v and returns a pointer to it, but unlike Int32
298// its argument value is an int.
299func Int(v int) *int32 {
300 p := new(int32)
301 *p = int32(v)
302 return p
303}
304
305// Int64 is a helper routine that allocates a new int64 value
306// to store v and returns a pointer to it.
307func Int64(v int64) *int64 {
David Symondsfff2ec62013-08-08 13:37:09 +1000308 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700309}
310
311// Float32 is a helper routine that allocates a new float32 value
312// to store v and returns a pointer to it.
313func Float32(v float32) *float32 {
David Symondsfff2ec62013-08-08 13:37:09 +1000314 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700315}
316
317// Float64 is a helper routine that allocates a new float64 value
318// to store v and returns a pointer to it.
319func Float64(v float64) *float64 {
David Symondsfff2ec62013-08-08 13:37:09 +1000320 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700321}
322
323// Uint32 is a helper routine that allocates a new uint32 value
324// to store v and returns a pointer to it.
325func Uint32(v uint32) *uint32 {
326 p := new(uint32)
327 *p = v
328 return p
329}
330
331// Uint64 is a helper routine that allocates a new uint64 value
332// to store v and returns a pointer to it.
333func Uint64(v uint64) *uint64 {
David Symondsfff2ec62013-08-08 13:37:09 +1000334 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700335}
336
337// String is a helper routine that allocates a new string value
338// to store v and returns a pointer to it.
339func String(v string) *string {
David Symondsfff2ec62013-08-08 13:37:09 +1000340 return &v
Rob Pikeaaa3a622010-03-20 22:32:34 -0700341}
342
Rob Pikeaaa3a622010-03-20 22:32:34 -0700343// EnumName is a helper function to simplify printing protocol buffer enums
344// by name. Given an enum map and a value, it returns a useful string.
345func EnumName(m map[int32]string, v int32) string {
346 s, ok := m[v]
347 if ok {
348 return s
349 }
David Symondsf8a1fcc2013-05-03 08:51:23 +1000350 return strconv.Itoa(int(v))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700351}
352
David Symonds62539862012-08-04 10:06:55 +1000353// UnmarshalJSONEnum is a helper function to simplify recovering enum int values
354// from their JSON-encoded representation. Given a map from the enum's symbolic
355// names to its int values, and a byte buffer containing the JSON-encoded
356// value, it returns an int32 that can be cast to the enum type by the caller.
357//
David Symonds4af5f1f2013-10-11 10:08:35 +1100358// The function can deal with both JSON representations, numeric and symbolic.
David Symonds62539862012-08-04 10:06:55 +1000359func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
360 if data[0] == '"' {
361 // New style: enums are strings.
362 var repr string
363 if err := json.Unmarshal(data, &repr); err != nil {
364 return -1, err
365 }
366 val, ok := m[repr]
367 if !ok {
368 return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
369 }
370 return val, nil
371 }
372 // Old style: enums are ints.
373 var val int32
374 if err := json.Unmarshal(data, &val); err != nil {
375 return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
376 }
377 return val, nil
378}
379
Rob Pikeaaa3a622010-03-20 22:32:34 -0700380// DebugPrint dumps the encoded data in b in a debugging format with a header
381// including the string s. Used in testing but made available for general debugging.
382func (o *Buffer) DebugPrint(s string, b []byte) {
383 var u uint64
384
385 obuf := o.buf
386 index := o.index
387 o.buf = b
388 o.index = 0
389 depth := 0
390
391 fmt.Printf("\n--- %s ---\n", s)
392
393out:
394 for {
395 for i := 0; i < depth; i++ {
396 fmt.Print(" ")
397 }
398
399 index := o.index
400 if index == len(o.buf) {
401 break
402 }
403
404 op, err := o.DecodeVarint()
405 if err != nil {
406 fmt.Printf("%3d: fetching op err %v\n", index, err)
407 break out
408 }
409 tag := op >> 3
410 wire := op & 7
411
412 switch wire {
413 default:
414 fmt.Printf("%3d: t=%3d unknown wire=%d\n",
415 index, tag, wire)
416 break out
417
418 case WireBytes:
419 var r []byte
420
421 r, err = o.DecodeRawBytes(false)
422 if err != nil {
423 break out
424 }
425 fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r))
426 if len(r) <= 6 {
427 for i := 0; i < len(r); i++ {
428 fmt.Printf(" %.2x", r[i])
429 }
430 } else {
431 for i := 0; i < 3; i++ {
432 fmt.Printf(" %.2x", r[i])
433 }
434 fmt.Printf(" ..")
435 for i := len(r) - 3; i < len(r); i++ {
436 fmt.Printf(" %.2x", r[i])
437 }
438 }
439 fmt.Printf("\n")
440
441 case WireFixed32:
442 u, err = o.DecodeFixed32()
443 if err != nil {
444 fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err)
445 break out
446 }
447 fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u)
448
449 case WireFixed64:
450 u, err = o.DecodeFixed64()
451 if err != nil {
452 fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err)
453 break out
454 }
455 fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
456 break
457
458 case WireVarint:
459 u, err = o.DecodeVarint()
460 if err != nil {
461 fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err)
462 break out
463 }
464 fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
465
466 case WireStartGroup:
467 if err != nil {
468 fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err)
469 break out
470 }
471 fmt.Printf("%3d: t=%3d start\n", index, tag)
472 depth++
473
474 case WireEndGroup:
475 depth--
476 if err != nil {
477 fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err)
478 break out
479 }
480 fmt.Printf("%3d: t=%3d end\n", index, tag)
481 }
482 }
483
484 if depth != 0 {
485 fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth)
486 }
487 fmt.Printf("\n")
488
489 o.buf = obuf
490 o.index = index
491}
David Symondsb79d99b2011-08-29 16:38:49 +1000492
493// SetDefaults sets unset protocol buffer fields to their default values.
494// It only modifies fields that are both unset and have defined defaults.
495// It recursively sets default values in any non-nil sub-messages.
David Symonds9f60f432012-06-14 09:45:25 +1000496func SetDefaults(pb Message) {
497 setDefaults(reflect.ValueOf(pb), true, false)
David Symondsb79d99b2011-08-29 16:38:49 +1000498}
499
500// v is a pointer to a struct.
501func setDefaults(v reflect.Value, recur, zeros bool) {
502 v = v.Elem()
503
David Symonds72607582011-11-01 12:52:01 +1100504 defaultMu.RLock()
David Symondsb79d99b2011-08-29 16:38:49 +1000505 dm, ok := defaults[v.Type()]
David Symonds72607582011-11-01 12:52:01 +1100506 defaultMu.RUnlock()
David Symondsb79d99b2011-08-29 16:38:49 +1000507 if !ok {
508 dm = buildDefaultMessage(v.Type())
509 defaultMu.Lock()
510 defaults[v.Type()] = dm
511 defaultMu.Unlock()
512 }
513
514 for _, sf := range dm.scalars {
515 f := v.Field(sf.index)
516 if !f.IsNil() {
517 // field already set
518 continue
519 }
520 dv := sf.value
521 if dv == nil && !zeros {
522 // no explicit default, and don't want to set zeros
523 continue
524 }
525 fptr := f.Addr().Interface() // **T
526 // TODO: Consider batching the allocations we do here.
527 switch sf.kind {
528 case reflect.Bool:
529 b := new(bool)
530 if dv != nil {
531 *b = dv.(bool)
532 }
533 *(fptr.(**bool)) = b
534 case reflect.Float32:
535 f := new(float32)
536 if dv != nil {
537 *f = dv.(float32)
538 }
539 *(fptr.(**float32)) = f
540 case reflect.Float64:
541 f := new(float64)
542 if dv != nil {
543 *f = dv.(float64)
544 }
545 *(fptr.(**float64)) = f
546 case reflect.Int32:
547 // might be an enum
548 if ft := f.Type(); ft != int32PtrType {
549 // enum
550 f.Set(reflect.New(ft.Elem()))
551 if dv != nil {
552 f.Elem().SetInt(int64(dv.(int32)))
553 }
554 } else {
555 // int32 field
556 i := new(int32)
557 if dv != nil {
558 *i = dv.(int32)
559 }
560 *(fptr.(**int32)) = i
561 }
562 case reflect.Int64:
563 i := new(int64)
564 if dv != nil {
565 *i = dv.(int64)
566 }
567 *(fptr.(**int64)) = i
568 case reflect.String:
569 s := new(string)
570 if dv != nil {
571 *s = dv.(string)
572 }
573 *(fptr.(**string)) = s
574 case reflect.Uint8:
575 // exceptional case: []byte
576 var b []byte
577 if dv != nil {
578 db := dv.([]byte)
579 b = make([]byte, len(db))
580 copy(b, db)
581 } else {
582 b = []byte{}
583 }
584 *(fptr.(*[]byte)) = b
585 case reflect.Uint32:
586 u := new(uint32)
587 if dv != nil {
588 *u = dv.(uint32)
589 }
590 *(fptr.(**uint32)) = u
591 case reflect.Uint64:
592 u := new(uint64)
593 if dv != nil {
594 *u = dv.(uint64)
595 }
596 *(fptr.(**uint64)) = u
597 default:
598 log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind)
599 }
600 }
601
602 for _, ni := range dm.nested {
David Symonds814b9362011-12-13 09:10:47 +1100603 f := v.Field(ni)
604 if f.IsNil() {
605 continue
606 }
David Symonds472e2592013-07-15 11:10:07 +1000607 // f is *T or []*T
608 if f.Kind() == reflect.Ptr {
609 setDefaults(f, recur, zeros)
610 } else {
611 for i := 0; i < f.Len(); i++ {
612 e := f.Index(i)
613 if e.IsNil() {
614 continue
615 }
616 setDefaults(e, recur, zeros)
617 }
618 }
David Symondsb79d99b2011-08-29 16:38:49 +1000619 }
620}
621
622var (
623 // defaults maps a protocol buffer struct type to a slice of the fields,
624 // with its scalar fields set to their proto-declared non-zero default values.
David Symonds72607582011-11-01 12:52:01 +1100625 defaultMu sync.RWMutex
David Symondsb79d99b2011-08-29 16:38:49 +1000626 defaults = make(map[reflect.Type]defaultMessage)
627
628 int32PtrType = reflect.TypeOf((*int32)(nil))
629)
630
631// defaultMessage represents information about the default values of a message.
632type defaultMessage struct {
633 scalars []scalarField
634 nested []int // struct field index of nested messages
635}
636
637type scalarField struct {
638 index int // struct field index
639 kind reflect.Kind // element type (the T in *T or []T)
640 value interface{} // the proto-declared default value, or nil
641}
642
David Symonds472e2592013-07-15 11:10:07 +1000643func ptrToStruct(t reflect.Type) bool {
644 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
645}
646
David Symondsb79d99b2011-08-29 16:38:49 +1000647// t is a struct type.
648func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
649 sprop := GetProperties(t)
650 for _, prop := range sprop.Prop {
David Symonds2bba1b22012-09-26 14:53:08 +1000651 fi, ok := sprop.decoderTags.get(prop.Tag)
David Symonds6a6f82c2012-08-22 09:18:54 +1000652 if !ok {
653 // XXX_unrecognized
654 continue
655 }
David Symondsb79d99b2011-08-29 16:38:49 +1000656 ft := t.Field(fi).Type
657
658 // nested messages
David Symonds472e2592013-07-15 11:10:07 +1000659 if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) {
David Symondsb79d99b2011-08-29 16:38:49 +1000660 dm.nested = append(dm.nested, fi)
661 continue
662 }
663
664 sf := scalarField{
665 index: fi,
666 kind: ft.Elem().Kind(),
667 }
668
669 // scalar fields without defaults
670 if prop.Default == "" {
671 dm.scalars = append(dm.scalars, sf)
672 continue
673 }
674
675 // a scalar field: either *T or []byte
676 switch ft.Elem().Kind() {
677 case reflect.Bool:
David Symonds93be46f2011-12-08 12:58:23 +1100678 x, err := strconv.ParseBool(prop.Default)
David Symondsb79d99b2011-08-29 16:38:49 +1000679 if err != nil {
680 log.Printf("proto: bad default bool %q: %v", prop.Default, err)
681 continue
682 }
683 sf.value = x
684 case reflect.Float32:
David Symonds93be46f2011-12-08 12:58:23 +1100685 x, err := strconv.ParseFloat(prop.Default, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000686 if err != nil {
687 log.Printf("proto: bad default float32 %q: %v", prop.Default, err)
688 continue
689 }
David Symonds93be46f2011-12-08 12:58:23 +1100690 sf.value = float32(x)
David Symondsb79d99b2011-08-29 16:38:49 +1000691 case reflect.Float64:
David Symonds93be46f2011-12-08 12:58:23 +1100692 x, err := strconv.ParseFloat(prop.Default, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000693 if err != nil {
694 log.Printf("proto: bad default float64 %q: %v", prop.Default, err)
695 continue
696 }
697 sf.value = x
698 case reflect.Int32:
David Symonds93be46f2011-12-08 12:58:23 +1100699 x, err := strconv.ParseInt(prop.Default, 10, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000700 if err != nil {
701 log.Printf("proto: bad default int32 %q: %v", prop.Default, err)
702 continue
703 }
704 sf.value = int32(x)
705 case reflect.Int64:
David Symonds93be46f2011-12-08 12:58:23 +1100706 x, err := strconv.ParseInt(prop.Default, 10, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000707 if err != nil {
708 log.Printf("proto: bad default int64 %q: %v", prop.Default, err)
709 continue
710 }
711 sf.value = x
712 case reflect.String:
713 sf.value = prop.Default
714 case reflect.Uint8:
715 // []byte (not *uint8)
716 sf.value = []byte(prop.Default)
717 case reflect.Uint32:
David Symonds93be46f2011-12-08 12:58:23 +1100718 x, err := strconv.ParseUint(prop.Default, 10, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000719 if err != nil {
720 log.Printf("proto: bad default uint32 %q: %v", prop.Default, err)
721 continue
722 }
723 sf.value = uint32(x)
724 case reflect.Uint64:
David Symonds93be46f2011-12-08 12:58:23 +1100725 x, err := strconv.ParseUint(prop.Default, 10, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000726 if err != nil {
727 log.Printf("proto: bad default uint64 %q: %v", prop.Default, err)
728 continue
729 }
730 sf.value = x
731 default:
732 log.Printf("proto: unhandled def kind %v", ft.Elem().Kind())
733 continue
734 }
735
736 dm.scalars = append(dm.scalars, sf)
737 }
738
739 return dm
740}