|
@@ -30,179 +30,230 @@
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
// 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.
|
|
|
|
- - Marshal and Unmarshal are functions to encode and decode the wire format.
|
|
|
|
-
|
|
|
|
- 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;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- The resulting file, test.pb.go, is:
|
|
|
|
-
|
|
|
|
- package example
|
|
|
|
-
|
|
|
|
- import proto "github.com/golang/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
|
|
|
|
|
|
+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.
|
|
|
|
+
|
|
|
|
+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/golang/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"`
|
|
|
|
- XXX_unrecognized []byte `json:"-"`
|
|
|
|
|
|
+ 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
|
|
}
|
|
}
|
|
- func (m *Test) Reset() { *m = Test{} }
|
|
|
|
- func (m *Test) String() string { return proto.CompactTextString(m) }
|
|
|
|
- func (*Test) ProtoMessage() {}
|
|
|
|
- const Default_Test_Type int32 = 77
|
|
|
|
|
|
+ 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) 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) 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
|
|
|
|
|
|
+ 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) }
|
|
|
|
|
|
- type Test_OptionalGroup struct {
|
|
|
|
- RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
|
|
|
|
|
|
+ func (m *Test_OptionalGroup) GetRequiredField() string {
|
|
|
|
+ if m != nil && m.RequiredField != nil {
|
|
|
|
+ return *m.RequiredField
|
|
}
|
|
}
|
|
- func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} }
|
|
|
|
- func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) }
|
|
|
|
|
|
+ return ""
|
|
|
|
+ }
|
|
|
|
|
|
- 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 init() {
|
|
|
|
- proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
|
|
|
|
|
|
+ func (m *Test) GetName() string {
|
|
|
|
+ if x, ok := m.GetUnion().(*Test_Name); ok {
|
|
|
|
+ return x.Name
|
|
}
|
|
}
|
|
|
|
+ return ""
|
|
|
|
+ }
|
|
|
|
|
|
- To create and play with a Test object:
|
|
|
|
|
|
+ func init() {
|
|
|
|
+ proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
|
|
|
|
+ }
|
|
|
|
|
|
- package main
|
|
|
|
|
|
+To create and play with a Test object:
|
|
|
|
|
|
- import (
|
|
|
|
- "log"
|
|
|
|
|
|
+ package main
|
|
|
|
|
|
- "github.com/golang/protobuf/proto"
|
|
|
|
- pb "./example.pb"
|
|
|
|
- )
|
|
|
|
|
|
+ import (
|
|
|
|
+ "log"
|
|
|
|
|
|
- func main() {
|
|
|
|
- test := &pb.Test{
|
|
|
|
- Label: proto.String("hello"),
|
|
|
|
- Type: proto.Int32(17),
|
|
|
|
- Optionalgroup: &pb.Test_OptionalGroup{
|
|
|
|
- RequiredField: proto.String("good bye"),
|
|
|
|
- },
|
|
|
|
- }
|
|
|
|
- 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())
|
|
|
|
- }
|
|
|
|
- // etc.
|
|
|
|
|
|
+ "github.com/golang/protobuf/proto"
|
|
|
|
+ pb "./example.pb"
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ func main() {
|
|
|
|
+ test := &pb.Test{
|
|
|
|
+ Label: proto.String("hello"),
|
|
|
|
+ Type: proto.Int32(17),
|
|
|
|
+ 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
|
|
package proto
|
|
|
|
|
|
@@ -211,6 +262,7 @@ import (
|
|
"fmt"
|
|
"fmt"
|
|
"log"
|
|
"log"
|
|
"reflect"
|
|
"reflect"
|
|
|
|
+ "sort"
|
|
"strconv"
|
|
"strconv"
|
|
"sync"
|
|
"sync"
|
|
)
|
|
)
|
|
@@ -385,13 +437,13 @@ func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32,
|
|
|
|
|
|
// DebugPrint dumps the encoded data in b in a debugging format with a header
|
|
// 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.
|
|
// including the string s. Used in testing but made available for general debugging.
|
|
-func (o *Buffer) DebugPrint(s string, b []byte) {
|
|
|
|
|
|
+func (p *Buffer) DebugPrint(s string, b []byte) {
|
|
var u uint64
|
|
var u uint64
|
|
|
|
|
|
- obuf := o.buf
|
|
|
|
- index := o.index
|
|
|
|
- o.buf = b
|
|
|
|
- o.index = 0
|
|
|
|
|
|
+ obuf := p.buf
|
|
|
|
+ index := p.index
|
|
|
|
+ p.buf = b
|
|
|
|
+ p.index = 0
|
|
depth := 0
|
|
depth := 0
|
|
|
|
|
|
fmt.Printf("\n--- %s ---\n", s)
|
|
fmt.Printf("\n--- %s ---\n", s)
|
|
@@ -402,12 +454,12 @@ out:
|
|
fmt.Print(" ")
|
|
fmt.Print(" ")
|
|
}
|
|
}
|
|
|
|
|
|
- index := o.index
|
|
|
|
- if index == len(o.buf) {
|
|
|
|
|
|
+ index := p.index
|
|
|
|
+ if index == len(p.buf) {
|
|
break
|
|
break
|
|
}
|
|
}
|
|
|
|
|
|
- op, err := o.DecodeVarint()
|
|
|
|
|
|
+ op, err := p.DecodeVarint()
|
|
if err != nil {
|
|
if err != nil {
|
|
fmt.Printf("%3d: fetching op err %v\n", index, err)
|
|
fmt.Printf("%3d: fetching op err %v\n", index, err)
|
|
break out
|
|
break out
|
|
@@ -424,7 +476,7 @@ out:
|
|
case WireBytes:
|
|
case WireBytes:
|
|
var r []byte
|
|
var r []byte
|
|
|
|
|
|
- r, err = o.DecodeRawBytes(false)
|
|
|
|
|
|
+ r, err = p.DecodeRawBytes(false)
|
|
if err != nil {
|
|
if err != nil {
|
|
break out
|
|
break out
|
|
}
|
|
}
|
|
@@ -445,7 +497,7 @@ out:
|
|
fmt.Printf("\n")
|
|
fmt.Printf("\n")
|
|
|
|
|
|
case WireFixed32:
|
|
case WireFixed32:
|
|
- u, err = o.DecodeFixed32()
|
|
|
|
|
|
+ u, err = p.DecodeFixed32()
|
|
if err != nil {
|
|
if err != nil {
|
|
fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err)
|
|
fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err)
|
|
break out
|
|
break out
|
|
@@ -453,16 +505,15 @@ out:
|
|
fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u)
|
|
fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u)
|
|
|
|
|
|
case WireFixed64:
|
|
case WireFixed64:
|
|
- u, err = o.DecodeFixed64()
|
|
|
|
|
|
+ u, err = p.DecodeFixed64()
|
|
if err != nil {
|
|
if err != nil {
|
|
fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err)
|
|
fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err)
|
|
break out
|
|
break out
|
|
}
|
|
}
|
|
fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
|
|
fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
|
|
- break
|
|
|
|
|
|
|
|
case WireVarint:
|
|
case WireVarint:
|
|
- u, err = o.DecodeVarint()
|
|
|
|
|
|
+ u, err = p.DecodeVarint()
|
|
if err != nil {
|
|
if err != nil {
|
|
fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err)
|
|
fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err)
|
|
break out
|
|
break out
|
|
@@ -470,30 +521,22 @@ out:
|
|
fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
|
|
fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
|
|
|
|
|
|
case WireStartGroup:
|
|
case WireStartGroup:
|
|
- if err != nil {
|
|
|
|
- fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err)
|
|
|
|
- break out
|
|
|
|
- }
|
|
|
|
fmt.Printf("%3d: t=%3d start\n", index, tag)
|
|
fmt.Printf("%3d: t=%3d start\n", index, tag)
|
|
depth++
|
|
depth++
|
|
|
|
|
|
case WireEndGroup:
|
|
case WireEndGroup:
|
|
depth--
|
|
depth--
|
|
- if err != nil {
|
|
|
|
- fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err)
|
|
|
|
- break out
|
|
|
|
- }
|
|
|
|
fmt.Printf("%3d: t=%3d end\n", index, tag)
|
|
fmt.Printf("%3d: t=%3d end\n", index, tag)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if depth != 0 {
|
|
if depth != 0 {
|
|
- fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth)
|
|
|
|
|
|
+ fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth)
|
|
}
|
|
}
|
|
fmt.Printf("\n")
|
|
fmt.Printf("\n")
|
|
|
|
|
|
- o.buf = obuf
|
|
|
|
- o.index = index
|
|
|
|
|
|
+ p.buf = obuf
|
|
|
|
+ p.index = index
|
|
}
|
|
}
|
|
|
|
|
|
// SetDefaults sets unset protocol buffer fields to their default values.
|
|
// SetDefaults sets unset protocol buffer fields to their default values.
|
|
@@ -607,13 +650,15 @@ func setDefaults(v reflect.Value, recur, zeros bool) {
|
|
|
|
|
|
for _, ni := range dm.nested {
|
|
for _, ni := range dm.nested {
|
|
f := v.Field(ni)
|
|
f := v.Field(ni)
|
|
- if f.IsNil() {
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- // f is *T or []*T
|
|
|
|
- if f.Kind() == reflect.Ptr {
|
|
|
|
|
|
+ // f is *T or []*T or map[T]*T
|
|
|
|
+ switch f.Kind() {
|
|
|
|
+ case reflect.Ptr:
|
|
|
|
+ if f.IsNil() {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
setDefaults(f, recur, zeros)
|
|
setDefaults(f, recur, zeros)
|
|
- } else {
|
|
|
|
|
|
+
|
|
|
|
+ case reflect.Slice:
|
|
for i := 0; i < f.Len(); i++ {
|
|
for i := 0; i < f.Len(); i++ {
|
|
e := f.Index(i)
|
|
e := f.Index(i)
|
|
if e.IsNil() {
|
|
if e.IsNil() {
|
|
@@ -621,6 +666,15 @@ func setDefaults(v reflect.Value, recur, zeros bool) {
|
|
}
|
|
}
|
|
setDefaults(e, recur, zeros)
|
|
setDefaults(e, recur, zeros)
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ case reflect.Map:
|
|
|
|
+ for _, k := range f.MapKeys() {
|
|
|
|
+ e := f.MapIndex(k)
|
|
|
|
+ if e.IsNil() {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ setDefaults(e, recur, zeros)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -646,10 +700,6 @@ type scalarField struct {
|
|
value interface{} // the proto-declared default value, or nil
|
|
value interface{} // the proto-declared default value, or nil
|
|
}
|
|
}
|
|
|
|
|
|
-func ptrToStruct(t reflect.Type) bool {
|
|
|
|
- return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
// t is a struct type.
|
|
// t is a struct type.
|
|
func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
|
|
func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
|
|
sprop := GetProperties(t)
|
|
sprop := GetProperties(t)
|
|
@@ -661,88 +711,118 @@ func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
|
|
}
|
|
}
|
|
ft := t.Field(fi).Type
|
|
ft := t.Field(fi).Type
|
|
|
|
|
|
- // nested messages
|
|
|
|
- if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) {
|
|
|
|
|
|
+ sf, nested, err := fieldDefault(ft, prop)
|
|
|
|
+ switch {
|
|
|
|
+ case err != nil:
|
|
|
|
+ log.Print(err)
|
|
|
|
+ case nested:
|
|
dm.nested = append(dm.nested, fi)
|
|
dm.nested = append(dm.nested, fi)
|
|
- continue
|
|
|
|
|
|
+ case sf != nil:
|
|
|
|
+ sf.index = fi
|
|
|
|
+ dm.scalars = append(dm.scalars, *sf)
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- sf := scalarField{
|
|
|
|
- index: fi,
|
|
|
|
- kind: ft.Elem().Kind(),
|
|
|
|
- }
|
|
|
|
|
|
+ return dm
|
|
|
|
+}
|
|
|
|
|
|
- // scalar fields without defaults
|
|
|
|
- if !prop.HasDefault {
|
|
|
|
- dm.scalars = append(dm.scalars, sf)
|
|
|
|
- continue
|
|
|
|
|
|
+// 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.Ptr:
|
|
|
|
+ if ft.Elem().Kind() == reflect.Struct {
|
|
|
|
+ nestedMessage = true
|
|
|
|
+ } else {
|
|
|
|
+ canHaveDefault = true // proto2 scalar field
|
|
}
|
|
}
|
|
|
|
|
|
- // a scalar field: either *T or []byte
|
|
|
|
|
|
+ case reflect.Slice:
|
|
switch ft.Elem().Kind() {
|
|
switch ft.Elem().Kind() {
|
|
- case reflect.Bool:
|
|
|
|
- x, err := strconv.ParseBool(prop.Default)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Printf("proto: bad default bool %q: %v", prop.Default, err)
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- sf.value = x
|
|
|
|
- case reflect.Float32:
|
|
|
|
- x, err := strconv.ParseFloat(prop.Default, 32)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Printf("proto: bad default float32 %q: %v", prop.Default, err)
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- sf.value = float32(x)
|
|
|
|
- case reflect.Float64:
|
|
|
|
- x, err := strconv.ParseFloat(prop.Default, 64)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Printf("proto: bad default float64 %q: %v", prop.Default, err)
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- sf.value = x
|
|
|
|
- case reflect.Int32:
|
|
|
|
- x, err := strconv.ParseInt(prop.Default, 10, 32)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Printf("proto: bad default int32 %q: %v", prop.Default, err)
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- sf.value = int32(x)
|
|
|
|
- case reflect.Int64:
|
|
|
|
- x, err := strconv.ParseInt(prop.Default, 10, 64)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Printf("proto: bad default int64 %q: %v", prop.Default, err)
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- sf.value = x
|
|
|
|
- case reflect.String:
|
|
|
|
- sf.value = prop.Default
|
|
|
|
|
|
+ case reflect.Ptr:
|
|
|
|
+ nestedMessage = true // repeated message
|
|
case reflect.Uint8:
|
|
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 {
|
|
|
|
- log.Printf("proto: bad default uint32 %q: %v", prop.Default, err)
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- sf.value = uint32(x)
|
|
|
|
- case reflect.Uint64:
|
|
|
|
- x, err := strconv.ParseUint(prop.Default, 10, 64)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Printf("proto: bad default uint64 %q: %v", prop.Default, err)
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- sf.value = x
|
|
|
|
- default:
|
|
|
|
- log.Printf("proto: unhandled def kind %v", ft.Elem().Kind())
|
|
|
|
- continue
|
|
|
|
|
|
+ canHaveDefault = true // bytes field
|
|
}
|
|
}
|
|
|
|
|
|
- dm.scalars = append(dm.scalars, sf)
|
|
|
|
|
|
+ case reflect.Map:
|
|
|
|
+ if ft.Elem().Kind() == reflect.Ptr {
|
|
|
|
+ nestedMessage = true // map with message values
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- return dm
|
|
|
|
|
|
+ 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
|
|
}
|
|
}
|
|
|
|
|
|
// Map fields may have key types of non-float scalars, strings and enums.
|
|
// Map fields may have key types of non-float scalars, strings and enums.
|
|
@@ -750,10 +830,54 @@ func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
|
|
// If this turns out to be inefficient we can always consider other options,
|
|
// If this turns out to be inefficient we can always consider other options,
|
|
// such as doing a Schwartzian transform.
|
|
// such as doing a Schwartzian transform.
|
|
|
|
|
|
-type mapKeys []reflect.Value
|
|
|
|
|
|
+func mapKeys(vs []reflect.Value) sort.Interface {
|
|
|
|
+ s := mapKeySorter{
|
|
|
|
+ vs: vs,
|
|
|
|
+ // default Less function: textual comparison
|
|
|
|
+ less: func(a, b reflect.Value) bool {
|
|
|
|
+ return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface())
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps;
|
|
|
|
+ // numeric keys are sorted numerically.
|
|
|
|
+ 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() }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return s
|
|
|
|
+}
|
|
|
|
|
|
-func (s mapKeys) Len() int { return len(s) }
|
|
|
|
-func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
-func (s mapKeys) Less(i, j int) bool {
|
|
|
|
- return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
|
|
|
|
|
|
+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
|
|
}
|
|
}
|