| // Go support for Protocol Buffers - Google's data interchange format | |
| // | |
| // Copyright 2010 The Go Authors. All rights reserved. | |
| // https://github.com/golang/protobuf | |
| // | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions are | |
| // met: | |
| // | |
| // * Redistributions of source code must retain the above copyright | |
| // notice, this list of conditions and the following disclaimer. | |
| // * Redistributions in binary form must reproduce the above | |
| // copyright notice, this list of conditions and the following disclaimer | |
| // in the documentation and/or other materials provided with the | |
| // distribution. | |
| // * Neither the name of Google Inc. nor the names of its | |
| // contributors may be used to endorse or promote products derived from | |
| // this software without specific prior written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| /* | |
| Package proto converts data structures to and from the wire format of | |
| protocol buffers. It works in concert with the Go source code generated | |
| for .proto files by the protocol compiler. | |
| A summary of the properties of the protocol buffer interface | |
| for a protocol buffer variable v: | |
| - Names are turned from camel_case to CamelCase for export. | |
| - There are no methods on v to set fields; just treat | |
| them as structure fields. | |
| - There are getters that return a field's value if set, | |
| and return the field's default value if unset. | |
| The getters work even if the receiver is a nil message. | |
| - The zero value for a struct is its correct initialization state. | |
| All desired fields must be set before marshaling. | |
| - A Reset() method will restore a protobuf struct to its zero state. | |
| - Non-repeated fields are pointers to the values; nil means unset. | |
| That is, optional or required field int32 f becomes F *int32. | |
| - Repeated fields are slices. | |
| - Helper functions are available to aid the setting of fields. | |
| msg.Foo = proto.String("hello") // set field | |
| - Constants are defined to hold the default values of all fields that | |
| have them. They have the form Default_StructName_FieldName. | |
| Because the getter methods handle defaulted values, | |
| direct use of these constants should be rare. | |
| - Enums are given type names and maps from names to values. | |
| Enum values are prefixed by the enclosing message's name, or by the | |
| enum's type name if it is a top-level enum. Enum types have a String | |
| method, and a Enum method to assist in message construction. | |
| - Nested messages, groups and enums have type names prefixed with the name of | |
| the surrounding message type. | |
| - Extensions are given descriptor names that start with E_, | |
| followed by an underscore-delimited list of the nested messages | |
| that contain it (if any) followed by the CamelCased name of the | |
| extension field itself. HasExtension, ClearExtension, GetExtension | |
| and SetExtension are functions for manipulating extensions. | |
| - Oneof field sets are given a single field in their message, | |
| with distinguished wrapper types for each possible field value. | |
| - Marshal and Unmarshal are functions to encode and decode the wire format. | |
| When the .proto file specifies `syntax="proto3"`, there are some differences: | |
| - Non-repeated fields of non-message type are values instead of pointers. | |
| - Enum types do not get an Enum method. | |
| The simplest way to describe this is to see an example. | |
| Given file test.proto, containing | |
| package example; | |
| enum FOO { X = 17; } | |
| message Test { | |
| required string label = 1; | |
| optional int32 type = 2 [default=77]; | |
| repeated int64 reps = 3; | |
| optional group OptionalGroup = 4 { | |
| required string RequiredField = 5; | |
| } | |
| oneof union { | |
| int32 number = 6; | |
| string name = 7; | |
| } | |
| } | |
| The resulting file, test.pb.go, is: | |
| package example | |
| import proto "github.com/gogo/protobuf/proto" | |
| import math "math" | |
| type FOO int32 | |
| const ( | |
| FOO_X FOO = 17 | |
| ) | |
| var FOO_name = map[int32]string{ | |
| 17: "X", | |
| } | |
| var FOO_value = map[string]int32{ | |
| "X": 17, | |
| } | |
| func (x FOO) Enum() *FOO { | |
| p := new(FOO) | |
| *p = x | |
| return p | |
| } | |
| func (x FOO) String() string { | |
| return proto.EnumName(FOO_name, int32(x)) | |
| } | |
| func (x *FOO) UnmarshalJSON(data []byte) error { | |
| value, err := proto.UnmarshalJSONEnum(FOO_value, data) | |
| if err != nil { | |
| return err | |
| } | |
| *x = FOO(value) | |
| return nil | |
| } | |
| type Test struct { | |
| Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` | |
| Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` | |
| Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` | |
| Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` | |
| // Types that are valid to be assigned to Union: | |
| // *Test_Number | |
| // *Test_Name | |
| Union isTest_Union `protobuf_oneof:"union"` | |
| XXX_unrecognized []byte `json:"-"` | |
| } | |
| func (m *Test) Reset() { *m = Test{} } | |
| func (m *Test) String() string { return proto.CompactTextString(m) } | |
| func (*Test) ProtoMessage() {} | |
| type isTest_Union interface { | |
| isTest_Union() | |
| } | |
| type Test_Number struct { | |
| Number int32 `protobuf:"varint,6,opt,name=number"` | |
| } | |
| type Test_Name struct { | |
| Name string `protobuf:"bytes,7,opt,name=name"` | |
| } | |
| func (*Test_Number) isTest_Union() {} | |
| func (*Test_Name) isTest_Union() {} | |
| func (m *Test) GetUnion() isTest_Union { | |
| if m != nil { | |
| return m.Union | |
| } | |
| return nil | |
| } | |
| const Default_Test_Type int32 = 77 | |
| func (m *Test) GetLabel() string { | |
| if m != nil && m.Label != nil { | |
| return *m.Label | |
| } | |
| return "" | |
| } | |
| func (m *Test) GetType() int32 { | |
| if m != nil && m.Type != nil { | |
| return *m.Type | |
| } | |
| return Default_Test_Type | |
| } | |
| func (m *Test) GetOptionalgroup() *Test_OptionalGroup { | |
| if m != nil { | |
| return m.Optionalgroup | |
| } | |
| return nil | |
| } | |
| type Test_OptionalGroup struct { | |
| RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` | |
| } | |
| func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } | |
| func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } | |
| func (m *Test_OptionalGroup) GetRequiredField() string { | |
| if m != nil && m.RequiredField != nil { | |
| return *m.RequiredField | |
| } | |
| return "" | |
| } | |
| func (m *Test) GetNumber() int32 { | |
| if x, ok := m.GetUnion().(*Test_Number); ok { | |
| return x.Number | |
| } | |
| return 0 | |
| } | |
| func (m *Test) GetName() string { | |
| if x, ok := m.GetUnion().(*Test_Name); ok { | |
| return x.Name | |
| } | |
| return "" | |
| } | |
| func init() { | |
| proto.RegisterEnum("example.FOO", FOO_name, FOO_value) | |
| } | |
| To create and play with a Test object: | |
| package main | |
| import ( | |
| "log" | |
| "github.com/gogo/protobuf/proto" | |
| pb "./example.pb" | |
| ) | |
| func main() { | |
| test := &pb.Test{ | |
| Label: proto.String("hello"), | |
| Type: proto.Int32(17), | |
| Reps: []int64{1, 2, 3}, | |
| Optionalgroup: &pb.Test_OptionalGroup{ | |
| RequiredField: proto.String("good bye"), | |
| }, | |
| Union: &pb.Test_Name{"fred"}, | |
| } | |
| data, err := proto.Marshal(test) | |
| if err != nil { | |
| log.Fatal("marshaling error: ", err) | |
| } | |
| newTest := &pb.Test{} | |
| err = proto.Unmarshal(data, newTest) | |
| if err != nil { | |
| log.Fatal("unmarshaling error: ", err) | |
| } | |
| // Now test and newTest contain the same data. | |
| if test.GetLabel() != newTest.GetLabel() { | |
| log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) | |
| } | |
| // Use a type switch to determine which oneof was set. | |
| switch u := test.Union.(type) { | |
| case *pb.Test_Number: // u.Number contains the number. | |
| case *pb.Test_Name: // u.Name contains the string. | |
| } | |
| // etc. | |
| } | |
| */ | |
| package proto | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "log" | |
| "reflect" | |
| "sort" | |
| "strconv" | |
| "sync" | |
| ) | |
| // RequiredNotSetError is an error type returned by either Marshal or Unmarshal. | |
| // Marshal reports this when a required field is not initialized. | |
| // Unmarshal reports this when a required field is missing from the wire data. | |
| type RequiredNotSetError struct{ field string } | |
| func (e *RequiredNotSetError) Error() string { | |
| if e.field == "" { | |
| return fmt.Sprintf("proto: required field not set") | |
| } | |
| return fmt.Sprintf("proto: required field %q not set", e.field) | |
| } | |
| func (e *RequiredNotSetError) RequiredNotSet() bool { | |
| return true | |
| } | |
| type invalidUTF8Error struct{ field string } | |
| func (e *invalidUTF8Error) Error() string { | |
| if e.field == "" { | |
| return "proto: invalid UTF-8 detected" | |
| } | |
| return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field) | |
| } | |
| func (e *invalidUTF8Error) InvalidUTF8() bool { | |
| return true | |
| } | |
| // errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8. | |
| // This error should not be exposed to the external API as such errors should | |
| // be recreated with the field information. | |
| var errInvalidUTF8 = &invalidUTF8Error{} | |
| // isNonFatal reports whether the error is either a RequiredNotSet error | |
| // or a InvalidUTF8 error. | |
| func isNonFatal(err error) bool { | |
| if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() { | |
| return true | |
| } | |
| if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() { | |
| return true | |
| } | |
| return false | |
| } | |
| type nonFatal struct{ E error } | |
| // Merge merges err into nf and reports whether it was successful. | |
| // Otherwise it returns false for any fatal non-nil errors. | |
| func (nf *nonFatal) Merge(err error) (ok bool) { | |
| if err == nil { | |
| return true // not an error | |
| } | |
| if !isNonFatal(err) { | |
| return false // fatal error | |
| } | |
| if nf.E == nil { | |
| nf.E = err // store first instance of non-fatal error | |
| } | |
| return true | |
| } | |
| // Message is implemented by generated protocol buffer messages. | |
| type Message interface { | |
| Reset() | |
| String() string | |
| ProtoMessage() | |
| } | |
| // A Buffer is a buffer manager for marshaling and unmarshaling | |
| // protocol buffers. It may be reused between invocations to | |
| // reduce memory usage. It is not necessary to use a Buffer; | |
| // the global functions Marshal and Unmarshal create a | |
| // temporary Buffer and are fine for most applications. | |
| type Buffer struct { | |
| buf []byte // encode/decode byte stream | |
| index int // read point | |
| deterministic bool | |
| } | |
| // NewBuffer allocates a new Buffer and initializes its internal data to | |
| // the contents of the argument slice. | |
| func NewBuffer(e []byte) *Buffer { | |
| return &Buffer{buf: e} | |
| } | |
| // Reset resets the Buffer, ready for marshaling a new protocol buffer. | |
| func (p *Buffer) Reset() { | |
| p.buf = p.buf[0:0] // for reading/writing | |
| p.index = 0 // for reading | |
| } | |
| // SetBuf replaces the internal buffer with the slice, | |
| // ready for unmarshaling the contents of the slice. | |
| func (p *Buffer) SetBuf(s []byte) { | |
| p.buf = s | |
| p.index = 0 | |
| } | |
| // Bytes returns the contents of the Buffer. | |
| func (p *Buffer) Bytes() []byte { return p.buf } | |
| // SetDeterministic sets whether to use deterministic serialization. | |
| // | |
| // Deterministic serialization guarantees that for a given binary, equal | |
| // messages will always be serialized to the same bytes. This implies: | |
| // | |
| // - Repeated serialization of a message will return the same bytes. | |
| // - Different processes of the same binary (which may be executing on | |
| // different machines) will serialize equal messages to the same bytes. | |
| // | |
| // Note that the deterministic serialization is NOT canonical across | |
| // languages. It is not guaranteed to remain stable over time. It is unstable | |
| // across different builds with schema changes due to unknown fields. | |
| // Users who need canonical serialization (e.g., persistent storage in a | |
| // canonical form, fingerprinting, etc.) should define their own | |
| // canonicalization specification and implement their own serializer rather | |
| // than relying on this API. | |
| // | |
| // If deterministic serialization is requested, map entries will be sorted | |
| // by keys in lexographical order. This is an implementation detail and | |
| // subject to change. | |
| func (p *Buffer) SetDeterministic(deterministic bool) { | |
| p.deterministic = deterministic | |
| } | |
| /* | |
| * Helper routines for simplifying the creation of optional fields of basic type. | |
| */ | |
| // Bool is a helper routine that allocates a new bool value | |
| // to store v and returns a pointer to it. | |
| func Bool(v bool) *bool { | |
| return &v | |
| } | |
| // Int32 is a helper routine that allocates a new int32 value | |
| // to store v and returns a pointer to it. | |
| func Int32(v int32) *int32 { | |
| return &v | |
| } | |
| // Int is a helper routine that allocates a new int32 value | |
| // to store v and returns a pointer to it, but unlike Int32 | |
| // its argument value is an int. | |
| func Int(v int) *int32 { | |
| p := new(int32) | |
| *p = int32(v) | |
| return p | |
| } | |
| // Int64 is a helper routine that allocates a new int64 value | |
| // to store v and returns a pointer to it. | |
| func Int64(v int64) *int64 { | |
| return &v | |
| } | |
| // Float32 is a helper routine that allocates a new float32 value | |
| // to store v and returns a pointer to it. | |
| func Float32(v float32) *float32 { | |
| return &v | |
| } | |
| // Float64 is a helper routine that allocates a new float64 value | |
| // to store v and returns a pointer to it. | |
| func Float64(v float64) *float64 { | |
| return &v | |
| } | |
| // Uint32 is a helper routine that allocates a new uint32 value | |
| // to store v and returns a pointer to it. | |
| func Uint32(v uint32) *uint32 { | |
| return &v | |
| } | |
| // Uint64 is a helper routine that allocates a new uint64 value | |
| // to store v and returns a pointer to it. | |
| func Uint64(v uint64) *uint64 { | |
| return &v | |
| } | |
| // String is a helper routine that allocates a new string value | |
| // to store v and returns a pointer to it. | |
| func String(v string) *string { | |
| return &v | |
| } | |
| // EnumName is a helper function to simplify printing protocol buffer enums | |
| // by name. Given an enum map and a value, it returns a useful string. | |
| func EnumName(m map[int32]string, v int32) string { | |
| s, ok := m[v] | |
| if ok { | |
| return s | |
| } | |
| return strconv.Itoa(int(v)) | |
| } | |
| // UnmarshalJSONEnum is a helper function to simplify recovering enum int values | |
| // from their JSON-encoded representation. Given a map from the enum's symbolic | |
| // names to its int values, and a byte buffer containing the JSON-encoded | |
| // value, it returns an int32 that can be cast to the enum type by the caller. | |
| // | |
| // The function can deal with both JSON representations, numeric and symbolic. | |
| func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { | |
| if data[0] == '"' { | |
| // New style: enums are strings. | |
| var repr string | |
| if err := json.Unmarshal(data, &repr); err != nil { | |
| return -1, err | |
| } | |
| val, ok := m[repr] | |
| if !ok { | |
| return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) | |
| } | |
| return val, nil | |
| } | |
| // Old style: enums are ints. | |
| var val int32 | |
| if err := json.Unmarshal(data, &val); err != nil { | |
| return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) | |
| } | |
| return val, nil | |
| } | |
| // DebugPrint dumps the encoded data in b in a debugging format with a header | |
| // including the string s. Used in testing but made available for general debugging. | |
| func (p *Buffer) DebugPrint(s string, b []byte) { | |
| var u uint64 | |
| obuf := p.buf | |
| sindex := p.index | |
| p.buf = b | |
| p.index = 0 | |
| depth := 0 | |
| fmt.Printf("\n--- %s ---\n", s) | |
| out: | |
| for { | |
| for i := 0; i < depth; i++ { | |
| fmt.Print(" ") | |
| } | |
| index := p.index | |
| if index == len(p.buf) { | |
| break | |
| } | |
| op, err := p.DecodeVarint() | |
| if err != nil { | |
| fmt.Printf("%3d: fetching op err %v\n", index, err) | |
| break out | |
| } | |
| tag := op >> 3 | |
| wire := op & 7 | |
| switch wire { | |
| default: | |
| fmt.Printf("%3d: t=%3d unknown wire=%d\n", | |
| index, tag, wire) | |
| break out | |
| case WireBytes: | |
| var r []byte | |
| r, err = p.DecodeRawBytes(false) | |
| if err != nil { | |
| break out | |
| } | |
| fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) | |
| if len(r) <= 6 { | |
| for i := 0; i < len(r); i++ { | |
| fmt.Printf(" %.2x", r[i]) | |
| } | |
| } else { | |
| for i := 0; i < 3; i++ { | |
| fmt.Printf(" %.2x", r[i]) | |
| } | |
| fmt.Printf(" ..") | |
| for i := len(r) - 3; i < len(r); i++ { | |
| fmt.Printf(" %.2x", r[i]) | |
| } | |
| } | |
| fmt.Printf("\n") | |
| case WireFixed32: | |
| u, err = p.DecodeFixed32() | |
| if err != nil { | |
| fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) | |
| break out | |
| } | |
| fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) | |
| case WireFixed64: | |
| u, err = p.DecodeFixed64() | |
| if err != nil { | |
| fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) | |
| break out | |
| } | |
| fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) | |
| case WireVarint: | |
| u, err = p.DecodeVarint() | |
| if err != nil { | |
| fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) | |
| break out | |
| } | |
| fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) | |
| case WireStartGroup: | |
| fmt.Printf("%3d: t=%3d start\n", index, tag) | |
| depth++ | |
| case WireEndGroup: | |
| depth-- | |
| fmt.Printf("%3d: t=%3d end\n", index, tag) | |
| } | |
| } | |
| if depth != 0 { | |
| fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) | |
| } | |
| fmt.Printf("\n") | |
| p.buf = obuf | |
| p.index = sindex | |
| } | |
| // SetDefaults sets unset protocol buffer fields to their default values. | |
| // It only modifies fields that are both unset and have defined defaults. | |
| // It recursively sets default values in any non-nil sub-messages. | |
| func SetDefaults(pb Message) { | |
| setDefaults(reflect.ValueOf(pb), true, false) | |
| } | |
| // v is a struct. | |
| func setDefaults(v reflect.Value, recur, zeros bool) { | |
| if v.Kind() == reflect.Ptr { | |
| v = v.Elem() | |
| } | |
| defaultMu.RLock() | |
| dm, ok := defaults[v.Type()] | |
| defaultMu.RUnlock() | |
| if !ok { | |
| dm = buildDefaultMessage(v.Type()) | |
| defaultMu.Lock() | |
| defaults[v.Type()] = dm | |
| defaultMu.Unlock() | |
| } | |
| for _, sf := range dm.scalars { | |
| f := v.Field(sf.index) | |
| if !f.IsNil() { | |
| // field already set | |
| continue | |
| } | |
| dv := sf.value | |
| if dv == nil && !zeros { | |
| // no explicit default, and don't want to set zeros | |
| continue | |
| } | |
| fptr := f.Addr().Interface() // **T | |
| // TODO: Consider batching the allocations we do here. | |
| switch sf.kind { | |
| case reflect.Bool: | |
| b := new(bool) | |
| if dv != nil { | |
| *b = dv.(bool) | |
| } | |
| *(fptr.(**bool)) = b | |
| case reflect.Float32: | |
| f := new(float32) | |
| if dv != nil { | |
| *f = dv.(float32) | |
| } | |
| *(fptr.(**float32)) = f | |
| case reflect.Float64: | |
| f := new(float64) | |
| if dv != nil { | |
| *f = dv.(float64) | |
| } | |
| *(fptr.(**float64)) = f | |
| case reflect.Int32: | |
| // might be an enum | |
| if ft := f.Type(); ft != int32PtrType { | |
| // enum | |
| f.Set(reflect.New(ft.Elem())) | |
| if dv != nil { | |
| f.Elem().SetInt(int64(dv.(int32))) | |
| } | |
| } else { | |
| // int32 field | |
| i := new(int32) | |
| if dv != nil { | |
| *i = dv.(int32) | |
| } | |
| *(fptr.(**int32)) = i | |
| } | |
| case reflect.Int64: | |
| i := new(int64) | |
| if dv != nil { | |
| *i = dv.(int64) | |
| } | |
| *(fptr.(**int64)) = i | |
| case reflect.String: | |
| s := new(string) | |
| if dv != nil { | |
| *s = dv.(string) | |
| } | |
| *(fptr.(**string)) = s | |
| case reflect.Uint8: | |
| // exceptional case: []byte | |
| var b []byte | |
| if dv != nil { | |
| db := dv.([]byte) | |
| b = make([]byte, len(db)) | |
| copy(b, db) | |
| } else { | |
| b = []byte{} | |
| } | |
| *(fptr.(*[]byte)) = b | |
| case reflect.Uint32: | |
| u := new(uint32) | |
| if dv != nil { | |
| *u = dv.(uint32) | |
| } | |
| *(fptr.(**uint32)) = u | |
| case reflect.Uint64: | |
| u := new(uint64) | |
| if dv != nil { | |
| *u = dv.(uint64) | |
| } | |
| *(fptr.(**uint64)) = u | |
| default: | |
| log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) | |
| } | |
| } | |
| for _, ni := range dm.nested { | |
| f := v.Field(ni) | |
| // f is *T or T or []*T or []T | |
| switch f.Kind() { | |
| case reflect.Struct: | |
| setDefaults(f, recur, zeros) | |
| case reflect.Ptr: | |
| if f.IsNil() { | |
| continue | |
| } | |
| setDefaults(f, recur, zeros) | |
| case reflect.Slice: | |
| for i := 0; i < f.Len(); i++ { | |
| e := f.Index(i) | |
| if e.Kind() == reflect.Ptr && e.IsNil() { | |
| continue | |
| } | |
| setDefaults(e, recur, zeros) | |
| } | |
| case reflect.Map: | |
| for _, k := range f.MapKeys() { | |
| e := f.MapIndex(k) | |
| if e.IsNil() { | |
| continue | |
| } | |
| setDefaults(e, recur, zeros) | |
| } | |
| } | |
| } | |
| } | |
| var ( | |
| // defaults maps a protocol buffer struct type to a slice of the fields, | |
| // with its scalar fields set to their proto-declared non-zero default values. | |
| defaultMu sync.RWMutex | |
| defaults = make(map[reflect.Type]defaultMessage) | |
| int32PtrType = reflect.TypeOf((*int32)(nil)) | |
| ) | |
| // defaultMessage represents information about the default values of a message. | |
| type defaultMessage struct { | |
| scalars []scalarField | |
| nested []int // struct field index of nested messages | |
| } | |
| type scalarField struct { | |
| index int // struct field index | |
| kind reflect.Kind // element type (the T in *T or []T) | |
| value interface{} // the proto-declared default value, or nil | |
| } | |
| // t is a struct type. | |
| func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { | |
| sprop := GetProperties(t) | |
| for _, prop := range sprop.Prop { | |
| fi, ok := sprop.decoderTags.get(prop.Tag) | |
| if !ok { | |
| // XXX_unrecognized | |
| continue | |
| } | |
| ft := t.Field(fi).Type | |
| sf, nested, err := fieldDefault(ft, prop) | |
| switch { | |
| case err != nil: | |
| log.Print(err) | |
| case nested: | |
| dm.nested = append(dm.nested, fi) | |
| case sf != nil: | |
| sf.index = fi | |
| dm.scalars = append(dm.scalars, *sf) | |
| } | |
| } | |
| return dm | |
| } | |
| // fieldDefault returns the scalarField for field type ft. | |
| // sf will be nil if the field can not have a default. | |
| // nestedMessage will be true if this is a nested message. | |
| // Note that sf.index is not set on return. | |
| func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { | |
| var canHaveDefault bool | |
| switch ft.Kind() { | |
| case reflect.Struct: | |
| nestedMessage = true // non-nullable | |
| case reflect.Ptr: | |
| if ft.Elem().Kind() == reflect.Struct { | |
| nestedMessage = true | |
| } else { | |
| canHaveDefault = true // proto2 scalar field | |
| } | |
| case reflect.Slice: | |
| switch ft.Elem().Kind() { | |
| case reflect.Ptr, reflect.Struct: | |
| nestedMessage = true // repeated message | |
| case reflect.Uint8: | |
| canHaveDefault = true // bytes field | |
| } | |
| case reflect.Map: | |
| if ft.Elem().Kind() == reflect.Ptr { | |
| nestedMessage = true // map with message values | |
| } | |
| } | |
| if !canHaveDefault { | |
| if nestedMessage { | |
| return nil, true, nil | |
| } | |
| return nil, false, nil | |
| } | |
| // We now know that ft is a pointer or slice. | |
| sf = &scalarField{kind: ft.Elem().Kind()} | |
| // scalar fields without defaults | |
| if !prop.HasDefault { | |
| return sf, false, nil | |
| } | |
| // a scalar field: either *T or []byte | |
| switch ft.Elem().Kind() { | |
| case reflect.Bool: | |
| x, err := strconv.ParseBool(prop.Default) | |
| if err != nil { | |
| return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) | |
| } | |
| sf.value = x | |
| case reflect.Float32: | |
| x, err := strconv.ParseFloat(prop.Default, 32) | |
| if err != nil { | |
| return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) | |
| } | |
| sf.value = float32(x) | |
| case reflect.Float64: | |
| x, err := strconv.ParseFloat(prop.Default, 64) | |
| if err != nil { | |
| return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) | |
| } | |
| sf.value = x | |
| case reflect.Int32: | |
| x, err := strconv.ParseInt(prop.Default, 10, 32) | |
| if err != nil { | |
| return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) | |
| } | |
| sf.value = int32(x) | |
| case reflect.Int64: | |
| x, err := strconv.ParseInt(prop.Default, 10, 64) | |
| if err != nil { | |
| return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) | |
| } | |
| sf.value = x | |
| case reflect.String: | |
| sf.value = prop.Default | |
| case reflect.Uint8: | |
| // []byte (not *uint8) | |
| sf.value = []byte(prop.Default) | |
| case reflect.Uint32: | |
| x, err := strconv.ParseUint(prop.Default, 10, 32) | |
| if err != nil { | |
| return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) | |
| } | |
| sf.value = uint32(x) | |
| case reflect.Uint64: | |
| x, err := strconv.ParseUint(prop.Default, 10, 64) | |
| if err != nil { | |
| return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) | |
| } | |
| sf.value = x | |
| default: | |
| return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) | |
| } | |
| return sf, false, nil | |
| } | |
| // mapKeys returns a sort.Interface to be used for sorting the map keys. | |
| // Map fields may have key types of non-float scalars, strings and enums. | |
| func mapKeys(vs []reflect.Value) sort.Interface { | |
| s := mapKeySorter{vs: vs} | |
| // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. | |
| if len(vs) == 0 { | |
| return s | |
| } | |
| switch vs[0].Kind() { | |
| case reflect.Int32, reflect.Int64: | |
| s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } | |
| case reflect.Uint32, reflect.Uint64: | |
| s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } | |
| case reflect.Bool: | |
| s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true | |
| case reflect.String: | |
| s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } | |
| default: | |
| panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) | |
| } | |
| return s | |
| } | |
| type mapKeySorter struct { | |
| vs []reflect.Value | |
| less func(a, b reflect.Value) bool | |
| } | |
| func (s mapKeySorter) Len() int { return len(s.vs) } | |
| func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } | |
| func (s mapKeySorter) Less(i, j int) bool { | |
| return s.less(s.vs[i], s.vs[j]) | |
| } | |
| // isProto3Zero reports whether v is a zero proto3 value. | |
| func isProto3Zero(v reflect.Value) bool { | |
| switch v.Kind() { | |
| case reflect.Bool: | |
| return !v.Bool() | |
| case reflect.Int32, reflect.Int64: | |
| return v.Int() == 0 | |
| case reflect.Uint32, reflect.Uint64: | |
| return v.Uint() == 0 | |
| case reflect.Float32, reflect.Float64: | |
| return v.Float() == 0 | |
| case reflect.String: | |
| return v.String() == "" | |
| } | |
| return false | |
| } | |
| const ( | |
| // ProtoPackageIsVersion3 is referenced from generated protocol buffer files | |
| // to assert that that code is compatible with this version of the proto package. | |
| GoGoProtoPackageIsVersion3 = true | |
| // ProtoPackageIsVersion2 is referenced from generated protocol buffer files | |
| // to assert that that code is compatible with this version of the proto package. | |
| GoGoProtoPackageIsVersion2 = true | |
| // ProtoPackageIsVersion1 is referenced from generated protocol buffer files | |
| // to assert that that code is compatible with this version of the proto package. | |
| GoGoProtoPackageIsVersion1 = true | |
| ) | |
| // InternalMessageInfo is a type used internally by generated .pb.go files. | |
| // This type is not intended to be used by non-generated code. | |
| // This type is not subject to any compatibility guarantee. | |
| type InternalMessageInfo struct { | |
| marshal *marshalInfo | |
| unmarshal *unmarshalInfo | |
| merge *mergeInfo | |
| discard *discardInfo | |
| } |