mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-25 10:00:53 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			899 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			899 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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.
 | |
|   - Getters are only generated for message and oneof fields.
 | |
|   - 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/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"`
 | |
| 		// 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/golang/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"
 | |
| )
 | |
| 
 | |
| // Message is implemented by generated protocol buffer messages.
 | |
| type Message interface {
 | |
| 	Reset()
 | |
| 	String() string
 | |
| 	ProtoMessage()
 | |
| }
 | |
| 
 | |
| // Stats records allocation details about the protocol buffer encoders
 | |
| // and decoders.  Useful for tuning the library itself.
 | |
| type Stats struct {
 | |
| 	Emalloc uint64 // mallocs in encode
 | |
| 	Dmalloc uint64 // mallocs in decode
 | |
| 	Encode  uint64 // number of encodes
 | |
| 	Decode  uint64 // number of decodes
 | |
| 	Chit    uint64 // number of cache hits
 | |
| 	Cmiss   uint64 // number of cache misses
 | |
| 	Size    uint64 // number of sizes
 | |
| }
 | |
| 
 | |
| // Set to true to enable stats collection.
 | |
| const collectStats = false
 | |
| 
 | |
| var stats Stats
 | |
| 
 | |
| // GetStats returns a copy of the global Stats structure.
 | |
| func GetStats() Stats { return stats }
 | |
| 
 | |
| // 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
 | |
| 
 | |
| 	// pools of basic types to amortize allocation.
 | |
| 	bools   []bool
 | |
| 	uint32s []uint32
 | |
| 	uint64s []uint64
 | |
| 
 | |
| 	// extra pools, only used with pointer_reflect.go
 | |
| 	int32s   []int32
 | |
| 	int64s   []int64
 | |
| 	float32s []float32
 | |
| 	float64s []float64
 | |
| }
 | |
| 
 | |
| // 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 }
 | |
| 
 | |
| /*
 | |
|  * 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
 | |
| 	index := 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 = index
 | |
| }
 | |
| 
 | |
| // 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 pointer to a struct.
 | |
| func setDefaults(v reflect.Value, recur, zeros bool) {
 | |
| 	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 map[T]*T
 | |
| 		switch f.Kind() {
 | |
| 		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.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.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:
 | |
| 			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
 | |
| }
 | |
| 
 | |
| // Map fields may have key types of non-float scalars, strings and enums.
 | |
| // The easiest way to sort them in some deterministic order is to use fmt.
 | |
| // If this turns out to be inefficient we can always consider other options,
 | |
| // such as doing a Schwartzian transform.
 | |
| 
 | |
| 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
 | |
| }
 | |
| 
 | |
| 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
 | |
| }
 | |
| 
 | |
| // ProtoPackageIsVersion2 is referenced from generated protocol buffer files
 | |
| // to assert that that code is compatible with this version of the proto package.
 | |
| const ProtoPackageIsVersion2 = true
 | |
| 
 | |
| // ProtoPackageIsVersion1 is referenced from generated protocol buffer files
 | |
| // to assert that that code is compatible with this version of the proto package.
 | |
| const ProtoPackageIsVersion1 = true
 |