blob: dfb4206d3ccf7ddb2b03311945de1a409fba5216 [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 {
335 p := new(bool)
336 *p = v
337 return p
338}
339
340// Int32 is a helper routine that allocates a new int32 value
341// to store v and returns a pointer to it.
342func Int32(v int32) *int32 {
343 p := new(int32)
344 *p = v
345 return p
346}
347
348// Int is a helper routine that allocates a new int32 value
349// to store v and returns a pointer to it, but unlike Int32
350// its argument value is an int.
351func Int(v int) *int32 {
352 p := new(int32)
353 *p = int32(v)
354 return p
355}
356
357// Int64 is a helper routine that allocates a new int64 value
358// to store v and returns a pointer to it.
359func Int64(v int64) *int64 {
360 p := new(int64)
361 *p = v
362 return p
363}
364
365// Float32 is a helper routine that allocates a new float32 value
366// to store v and returns a pointer to it.
367func Float32(v float32) *float32 {
368 p := new(float32)
369 *p = v
370 return p
371}
372
373// Float64 is a helper routine that allocates a new float64 value
374// to store v and returns a pointer to it.
375func Float64(v float64) *float64 {
376 p := new(float64)
377 *p = v
378 return p
379}
380
381// Uint32 is a helper routine that allocates a new uint32 value
382// to store v and returns a pointer to it.
383func Uint32(v uint32) *uint32 {
384 p := new(uint32)
385 *p = v
386 return p
387}
388
389// Uint64 is a helper routine that allocates a new uint64 value
390// to store v and returns a pointer to it.
391func Uint64(v uint64) *uint64 {
392 p := new(uint64)
393 *p = v
394 return p
395}
396
397// String is a helper routine that allocates a new string value
398// to store v and returns a pointer to it.
399func String(v string) *string {
400 p := new(string)
401 *p = v
402 return p
403}
404
Rob Pikeaaa3a622010-03-20 22:32:34 -0700405// EnumName is a helper function to simplify printing protocol buffer enums
406// by name. Given an enum map and a value, it returns a useful string.
407func EnumName(m map[int32]string, v int32) string {
408 s, ok := m[v]
409 if ok {
410 return s
411 }
David Symondsf8a1fcc2013-05-03 08:51:23 +1000412 return strconv.Itoa(int(v))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700413}
414
David Symonds62539862012-08-04 10:06:55 +1000415// UnmarshalJSONEnum is a helper function to simplify recovering enum int values
416// from their JSON-encoded representation. Given a map from the enum's symbolic
417// names to its int values, and a byte buffer containing the JSON-encoded
418// value, it returns an int32 that can be cast to the enum type by the caller.
419//
420// The function can deal with older JSON representations, which represented
421// enums directly by their int32 values, or with newer representations, which
422// use the symbolic name as a string.
423func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
424 if data[0] == '"' {
425 // New style: enums are strings.
426 var repr string
427 if err := json.Unmarshal(data, &repr); err != nil {
428 return -1, err
429 }
430 val, ok := m[repr]
431 if !ok {
432 return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
433 }
434 return val, nil
435 }
436 // Old style: enums are ints.
437 var val int32
438 if err := json.Unmarshal(data, &val); err != nil {
439 return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
440 }
441 return val, nil
442}
443
Rob Pikeaaa3a622010-03-20 22:32:34 -0700444// DebugPrint dumps the encoded data in b in a debugging format with a header
445// including the string s. Used in testing but made available for general debugging.
446func (o *Buffer) DebugPrint(s string, b []byte) {
447 var u uint64
448
449 obuf := o.buf
450 index := o.index
451 o.buf = b
452 o.index = 0
453 depth := 0
454
455 fmt.Printf("\n--- %s ---\n", s)
456
457out:
458 for {
459 for i := 0; i < depth; i++ {
460 fmt.Print(" ")
461 }
462
463 index := o.index
464 if index == len(o.buf) {
465 break
466 }
467
468 op, err := o.DecodeVarint()
469 if err != nil {
470 fmt.Printf("%3d: fetching op err %v\n", index, err)
471 break out
472 }
473 tag := op >> 3
474 wire := op & 7
475
476 switch wire {
477 default:
478 fmt.Printf("%3d: t=%3d unknown wire=%d\n",
479 index, tag, wire)
480 break out
481
482 case WireBytes:
483 var r []byte
484
485 r, err = o.DecodeRawBytes(false)
486 if err != nil {
487 break out
488 }
489 fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r))
490 if len(r) <= 6 {
491 for i := 0; i < len(r); i++ {
492 fmt.Printf(" %.2x", r[i])
493 }
494 } else {
495 for i := 0; i < 3; i++ {
496 fmt.Printf(" %.2x", r[i])
497 }
498 fmt.Printf(" ..")
499 for i := len(r) - 3; i < len(r); i++ {
500 fmt.Printf(" %.2x", r[i])
501 }
502 }
503 fmt.Printf("\n")
504
505 case WireFixed32:
506 u, err = o.DecodeFixed32()
507 if err != nil {
508 fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err)
509 break out
510 }
511 fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u)
512
513 case WireFixed64:
514 u, err = o.DecodeFixed64()
515 if err != nil {
516 fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err)
517 break out
518 }
519 fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
520 break
521
522 case WireVarint:
523 u, err = o.DecodeVarint()
524 if err != nil {
525 fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err)
526 break out
527 }
528 fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
529
530 case WireStartGroup:
531 if err != nil {
532 fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err)
533 break out
534 }
535 fmt.Printf("%3d: t=%3d start\n", index, tag)
536 depth++
537
538 case WireEndGroup:
539 depth--
540 if err != nil {
541 fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err)
542 break out
543 }
544 fmt.Printf("%3d: t=%3d end\n", index, tag)
545 }
546 }
547
548 if depth != 0 {
549 fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth)
550 }
551 fmt.Printf("\n")
552
553 o.buf = obuf
554 o.index = index
555}
David Symondsb79d99b2011-08-29 16:38:49 +1000556
557// SetDefaults sets unset protocol buffer fields to their default values.
558// It only modifies fields that are both unset and have defined defaults.
559// It recursively sets default values in any non-nil sub-messages.
David Symonds9f60f432012-06-14 09:45:25 +1000560func SetDefaults(pb Message) {
561 setDefaults(reflect.ValueOf(pb), true, false)
David Symondsb79d99b2011-08-29 16:38:49 +1000562}
563
564// v is a pointer to a struct.
565func setDefaults(v reflect.Value, recur, zeros bool) {
566 v = v.Elem()
567
David Symonds72607582011-11-01 12:52:01 +1100568 defaultMu.RLock()
David Symondsb79d99b2011-08-29 16:38:49 +1000569 dm, ok := defaults[v.Type()]
David Symonds72607582011-11-01 12:52:01 +1100570 defaultMu.RUnlock()
David Symondsb79d99b2011-08-29 16:38:49 +1000571 if !ok {
572 dm = buildDefaultMessage(v.Type())
573 defaultMu.Lock()
574 defaults[v.Type()] = dm
575 defaultMu.Unlock()
576 }
577
578 for _, sf := range dm.scalars {
579 f := v.Field(sf.index)
580 if !f.IsNil() {
581 // field already set
582 continue
583 }
584 dv := sf.value
585 if dv == nil && !zeros {
586 // no explicit default, and don't want to set zeros
587 continue
588 }
589 fptr := f.Addr().Interface() // **T
590 // TODO: Consider batching the allocations we do here.
591 switch sf.kind {
592 case reflect.Bool:
593 b := new(bool)
594 if dv != nil {
595 *b = dv.(bool)
596 }
597 *(fptr.(**bool)) = b
598 case reflect.Float32:
599 f := new(float32)
600 if dv != nil {
601 *f = dv.(float32)
602 }
603 *(fptr.(**float32)) = f
604 case reflect.Float64:
605 f := new(float64)
606 if dv != nil {
607 *f = dv.(float64)
608 }
609 *(fptr.(**float64)) = f
610 case reflect.Int32:
611 // might be an enum
612 if ft := f.Type(); ft != int32PtrType {
613 // enum
614 f.Set(reflect.New(ft.Elem()))
615 if dv != nil {
616 f.Elem().SetInt(int64(dv.(int32)))
617 }
618 } else {
619 // int32 field
620 i := new(int32)
621 if dv != nil {
622 *i = dv.(int32)
623 }
624 *(fptr.(**int32)) = i
625 }
626 case reflect.Int64:
627 i := new(int64)
628 if dv != nil {
629 *i = dv.(int64)
630 }
631 *(fptr.(**int64)) = i
632 case reflect.String:
633 s := new(string)
634 if dv != nil {
635 *s = dv.(string)
636 }
637 *(fptr.(**string)) = s
638 case reflect.Uint8:
639 // exceptional case: []byte
640 var b []byte
641 if dv != nil {
642 db := dv.([]byte)
643 b = make([]byte, len(db))
644 copy(b, db)
645 } else {
646 b = []byte{}
647 }
648 *(fptr.(*[]byte)) = b
649 case reflect.Uint32:
650 u := new(uint32)
651 if dv != nil {
652 *u = dv.(uint32)
653 }
654 *(fptr.(**uint32)) = u
655 case reflect.Uint64:
656 u := new(uint64)
657 if dv != nil {
658 *u = dv.(uint64)
659 }
660 *(fptr.(**uint64)) = u
661 default:
662 log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind)
663 }
664 }
665
666 for _, ni := range dm.nested {
David Symonds814b9362011-12-13 09:10:47 +1100667 f := v.Field(ni)
668 if f.IsNil() {
669 continue
670 }
David Symonds472e2592013-07-15 11:10:07 +1000671 // f is *T or []*T
672 if f.Kind() == reflect.Ptr {
673 setDefaults(f, recur, zeros)
674 } else {
675 for i := 0; i < f.Len(); i++ {
676 e := f.Index(i)
677 if e.IsNil() {
678 continue
679 }
680 setDefaults(e, recur, zeros)
681 }
682 }
David Symondsb79d99b2011-08-29 16:38:49 +1000683 }
684}
685
686var (
687 // defaults maps a protocol buffer struct type to a slice of the fields,
688 // with its scalar fields set to their proto-declared non-zero default values.
David Symonds72607582011-11-01 12:52:01 +1100689 defaultMu sync.RWMutex
David Symondsb79d99b2011-08-29 16:38:49 +1000690 defaults = make(map[reflect.Type]defaultMessage)
691
692 int32PtrType = reflect.TypeOf((*int32)(nil))
693)
694
695// defaultMessage represents information about the default values of a message.
696type defaultMessage struct {
697 scalars []scalarField
698 nested []int // struct field index of nested messages
699}
700
701type scalarField struct {
702 index int // struct field index
703 kind reflect.Kind // element type (the T in *T or []T)
704 value interface{} // the proto-declared default value, or nil
705}
706
David Symonds472e2592013-07-15 11:10:07 +1000707func ptrToStruct(t reflect.Type) bool {
708 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
709}
710
David Symondsb79d99b2011-08-29 16:38:49 +1000711// t is a struct type.
712func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
713 sprop := GetProperties(t)
714 for _, prop := range sprop.Prop {
David Symonds2bba1b22012-09-26 14:53:08 +1000715 fi, ok := sprop.decoderTags.get(prop.Tag)
David Symonds6a6f82c2012-08-22 09:18:54 +1000716 if !ok {
717 // XXX_unrecognized
718 continue
719 }
David Symondsb79d99b2011-08-29 16:38:49 +1000720 ft := t.Field(fi).Type
721
722 // nested messages
David Symonds472e2592013-07-15 11:10:07 +1000723 if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) {
David Symondsb79d99b2011-08-29 16:38:49 +1000724 dm.nested = append(dm.nested, fi)
725 continue
726 }
727
728 sf := scalarField{
729 index: fi,
730 kind: ft.Elem().Kind(),
731 }
732
733 // scalar fields without defaults
734 if prop.Default == "" {
735 dm.scalars = append(dm.scalars, sf)
736 continue
737 }
738
739 // a scalar field: either *T or []byte
740 switch ft.Elem().Kind() {
741 case reflect.Bool:
David Symonds93be46f2011-12-08 12:58:23 +1100742 x, err := strconv.ParseBool(prop.Default)
David Symondsb79d99b2011-08-29 16:38:49 +1000743 if err != nil {
744 log.Printf("proto: bad default bool %q: %v", prop.Default, err)
745 continue
746 }
747 sf.value = x
748 case reflect.Float32:
David Symonds93be46f2011-12-08 12:58:23 +1100749 x, err := strconv.ParseFloat(prop.Default, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000750 if err != nil {
751 log.Printf("proto: bad default float32 %q: %v", prop.Default, err)
752 continue
753 }
David Symonds93be46f2011-12-08 12:58:23 +1100754 sf.value = float32(x)
David Symondsb79d99b2011-08-29 16:38:49 +1000755 case reflect.Float64:
David Symonds93be46f2011-12-08 12:58:23 +1100756 x, err := strconv.ParseFloat(prop.Default, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000757 if err != nil {
758 log.Printf("proto: bad default float64 %q: %v", prop.Default, err)
759 continue
760 }
761 sf.value = x
762 case reflect.Int32:
David Symonds93be46f2011-12-08 12:58:23 +1100763 x, err := strconv.ParseInt(prop.Default, 10, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000764 if err != nil {
765 log.Printf("proto: bad default int32 %q: %v", prop.Default, err)
766 continue
767 }
768 sf.value = int32(x)
769 case reflect.Int64:
David Symonds93be46f2011-12-08 12:58:23 +1100770 x, err := strconv.ParseInt(prop.Default, 10, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000771 if err != nil {
772 log.Printf("proto: bad default int64 %q: %v", prop.Default, err)
773 continue
774 }
775 sf.value = x
776 case reflect.String:
777 sf.value = prop.Default
778 case reflect.Uint8:
779 // []byte (not *uint8)
780 sf.value = []byte(prop.Default)
781 case reflect.Uint32:
David Symonds93be46f2011-12-08 12:58:23 +1100782 x, err := strconv.ParseUint(prop.Default, 10, 32)
David Symondsb79d99b2011-08-29 16:38:49 +1000783 if err != nil {
784 log.Printf("proto: bad default uint32 %q: %v", prop.Default, err)
785 continue
786 }
787 sf.value = uint32(x)
788 case reflect.Uint64:
David Symonds93be46f2011-12-08 12:58:23 +1100789 x, err := strconv.ParseUint(prop.Default, 10, 64)
David Symondsb79d99b2011-08-29 16:38:49 +1000790 if err != nil {
791 log.Printf("proto: bad default uint64 %q: %v", prop.Default, err)
792 continue
793 }
794 sf.value = x
795 default:
796 log.Printf("proto: unhandled def kind %v", ft.Elem().Kind())
797 continue
798 }
799
800 dm.scalars = append(dm.scalars, sf)
801 }
802
803 return dm
804}