...

Source file src/github.com/gogo/protobuf/proto/properties.go

Documentation: github.com/gogo/protobuf/proto

     1  // Protocol Buffers for Go with Gadgets
     2  //
     3  // Copyright (c) 2013, The GoGo Authors. All rights reserved.
     4  // http://github.com/gogo/protobuf
     5  //
     6  // Go support for Protocol Buffers - Google's data interchange format
     7  //
     8  // Copyright 2010 The Go Authors.  All rights reserved.
     9  // https://github.com/golang/protobuf
    10  //
    11  // Redistribution and use in source and binary forms, with or without
    12  // modification, are permitted provided that the following conditions are
    13  // met:
    14  //
    15  //     * Redistributions of source code must retain the above copyright
    16  // notice, this list of conditions and the following disclaimer.
    17  //     * Redistributions in binary form must reproduce the above
    18  // copyright notice, this list of conditions and the following disclaimer
    19  // in the documentation and/or other materials provided with the
    20  // distribution.
    21  //     * Neither the name of Google Inc. nor the names of its
    22  // contributors may be used to endorse or promote products derived from
    23  // this software without specific prior written permission.
    24  //
    25  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    26  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    27  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    28  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    29  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    30  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    31  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    32  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    33  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    34  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    35  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    36  
    37  package proto
    38  
    39  /*
    40   * Routines for encoding data into the wire format for protocol buffers.
    41   */
    42  
    43  import (
    44  	"fmt"
    45  	"log"
    46  	"reflect"
    47  	"sort"
    48  	"strconv"
    49  	"strings"
    50  	"sync"
    51  )
    52  
    53  const debug bool = false
    54  
    55  // Constants that identify the encoding of a value on the wire.
    56  const (
    57  	WireVarint     = 0
    58  	WireFixed64    = 1
    59  	WireBytes      = 2
    60  	WireStartGroup = 3
    61  	WireEndGroup   = 4
    62  	WireFixed32    = 5
    63  )
    64  
    65  // tagMap is an optimization over map[int]int for typical protocol buffer
    66  // use-cases. Encoded protocol buffers are often in tag order with small tag
    67  // numbers.
    68  type tagMap struct {
    69  	fastTags []int
    70  	slowTags map[int]int
    71  }
    72  
    73  // tagMapFastLimit is the upper bound on the tag number that will be stored in
    74  // the tagMap slice rather than its map.
    75  const tagMapFastLimit = 1024
    76  
    77  func (p *tagMap) get(t int) (int, bool) {
    78  	if t > 0 && t < tagMapFastLimit {
    79  		if t >= len(p.fastTags) {
    80  			return 0, false
    81  		}
    82  		fi := p.fastTags[t]
    83  		return fi, fi >= 0
    84  	}
    85  	fi, ok := p.slowTags[t]
    86  	return fi, ok
    87  }
    88  
    89  func (p *tagMap) put(t int, fi int) {
    90  	if t > 0 && t < tagMapFastLimit {
    91  		for len(p.fastTags) < t+1 {
    92  			p.fastTags = append(p.fastTags, -1)
    93  		}
    94  		p.fastTags[t] = fi
    95  		return
    96  	}
    97  	if p.slowTags == nil {
    98  		p.slowTags = make(map[int]int)
    99  	}
   100  	p.slowTags[t] = fi
   101  }
   102  
   103  // StructProperties represents properties for all the fields of a struct.
   104  // decoderTags and decoderOrigNames should only be used by the decoder.
   105  type StructProperties struct {
   106  	Prop             []*Properties  // properties for each field
   107  	reqCount         int            // required count
   108  	decoderTags      tagMap         // map from proto tag to struct field number
   109  	decoderOrigNames map[string]int // map from original name to struct field number
   110  	order            []int          // list of struct field numbers in tag order
   111  
   112  	// OneofTypes contains information about the oneof fields in this message.
   113  	// It is keyed by the original name of a field.
   114  	OneofTypes map[string]*OneofProperties
   115  }
   116  
   117  // OneofProperties represents information about a specific field in a oneof.
   118  type OneofProperties struct {
   119  	Type  reflect.Type // pointer to generated struct type for this oneof field
   120  	Field int          // struct field number of the containing oneof in the message
   121  	Prop  *Properties
   122  }
   123  
   124  // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
   125  // See encode.go, (*Buffer).enc_struct.
   126  
   127  func (sp *StructProperties) Len() int { return len(sp.order) }
   128  func (sp *StructProperties) Less(i, j int) bool {
   129  	return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
   130  }
   131  func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
   132  
   133  // Properties represents the protocol-specific behavior of a single struct field.
   134  type Properties struct {
   135  	Name     string // name of the field, for error messages
   136  	OrigName string // original name before protocol compiler (always set)
   137  	JSONName string // name to use for JSON; determined by protoc
   138  	Wire     string
   139  	WireType int
   140  	Tag      int
   141  	Required bool
   142  	Optional bool
   143  	Repeated bool
   144  	Packed   bool   // relevant for repeated primitives only
   145  	Enum     string // set for enum types only
   146  	proto3   bool   // whether this is known to be a proto3 field
   147  	oneof    bool   // whether this is a oneof field
   148  
   149  	Default     string // default value
   150  	HasDefault  bool   // whether an explicit default was provided
   151  	CustomType  string
   152  	CastType    string
   153  	StdTime     bool
   154  	StdDuration bool
   155  	WktPointer  bool
   156  
   157  	stype reflect.Type      // set for struct types only
   158  	ctype reflect.Type      // set for custom types only
   159  	sprop *StructProperties // set for struct types only
   160  
   161  	mtype      reflect.Type // set for map types only
   162  	MapKeyProp *Properties  // set for map types only
   163  	MapValProp *Properties  // set for map types only
   164  }
   165  
   166  // String formats the properties in the protobuf struct field tag style.
   167  func (p *Properties) String() string {
   168  	s := p.Wire
   169  	s += ","
   170  	s += strconv.Itoa(p.Tag)
   171  	if p.Required {
   172  		s += ",req"
   173  	}
   174  	if p.Optional {
   175  		s += ",opt"
   176  	}
   177  	if p.Repeated {
   178  		s += ",rep"
   179  	}
   180  	if p.Packed {
   181  		s += ",packed"
   182  	}
   183  	s += ",name=" + p.OrigName
   184  	if p.JSONName != p.OrigName {
   185  		s += ",json=" + p.JSONName
   186  	}
   187  	if p.proto3 {
   188  		s += ",proto3"
   189  	}
   190  	if p.oneof {
   191  		s += ",oneof"
   192  	}
   193  	if len(p.Enum) > 0 {
   194  		s += ",enum=" + p.Enum
   195  	}
   196  	if p.HasDefault {
   197  		s += ",def=" + p.Default
   198  	}
   199  	return s
   200  }
   201  
   202  // Parse populates p by parsing a string in the protobuf struct field tag style.
   203  func (p *Properties) Parse(s string) {
   204  	// "bytes,49,opt,name=foo,def=hello!"
   205  	fields := strings.Split(s, ",") // breaks def=, but handled below.
   206  	if len(fields) < 2 {
   207  		log.Printf("proto: tag has too few fields: %q", s)
   208  		return
   209  	}
   210  
   211  	p.Wire = fields[0]
   212  	switch p.Wire {
   213  	case "varint":
   214  		p.WireType = WireVarint
   215  	case "fixed32":
   216  		p.WireType = WireFixed32
   217  	case "fixed64":
   218  		p.WireType = WireFixed64
   219  	case "zigzag32":
   220  		p.WireType = WireVarint
   221  	case "zigzag64":
   222  		p.WireType = WireVarint
   223  	case "bytes", "group":
   224  		p.WireType = WireBytes
   225  		// no numeric converter for non-numeric types
   226  	default:
   227  		log.Printf("proto: tag has unknown wire type: %q", s)
   228  		return
   229  	}
   230  
   231  	var err error
   232  	p.Tag, err = strconv.Atoi(fields[1])
   233  	if err != nil {
   234  		return
   235  	}
   236  
   237  outer:
   238  	for i := 2; i < len(fields); i++ {
   239  		f := fields[i]
   240  		switch {
   241  		case f == "req":
   242  			p.Required = true
   243  		case f == "opt":
   244  			p.Optional = true
   245  		case f == "rep":
   246  			p.Repeated = true
   247  		case f == "packed":
   248  			p.Packed = true
   249  		case strings.HasPrefix(f, "name="):
   250  			p.OrigName = f[5:]
   251  		case strings.HasPrefix(f, "json="):
   252  			p.JSONName = f[5:]
   253  		case strings.HasPrefix(f, "enum="):
   254  			p.Enum = f[5:]
   255  		case f == "proto3":
   256  			p.proto3 = true
   257  		case f == "oneof":
   258  			p.oneof = true
   259  		case strings.HasPrefix(f, "def="):
   260  			p.HasDefault = true
   261  			p.Default = f[4:] // rest of string
   262  			if i+1 < len(fields) {
   263  				// Commas aren't escaped, and def is always last.
   264  				p.Default += "," + strings.Join(fields[i+1:], ",")
   265  				break outer
   266  			}
   267  		case strings.HasPrefix(f, "embedded="):
   268  			p.OrigName = strings.Split(f, "=")[1]
   269  		case strings.HasPrefix(f, "customtype="):
   270  			p.CustomType = strings.Split(f, "=")[1]
   271  		case strings.HasPrefix(f, "casttype="):
   272  			p.CastType = strings.Split(f, "=")[1]
   273  		case f == "stdtime":
   274  			p.StdTime = true
   275  		case f == "stdduration":
   276  			p.StdDuration = true
   277  		case f == "wktptr":
   278  			p.WktPointer = true
   279  		}
   280  	}
   281  }
   282  
   283  var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
   284  
   285  // setFieldProps initializes the field properties for submessages and maps.
   286  func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
   287  	isMap := typ.Kind() == reflect.Map
   288  	if len(p.CustomType) > 0 && !isMap {
   289  		p.ctype = typ
   290  		p.setTag(lockGetProp)
   291  		return
   292  	}
   293  	if p.StdTime && !isMap {
   294  		p.setTag(lockGetProp)
   295  		return
   296  	}
   297  	if p.StdDuration && !isMap {
   298  		p.setTag(lockGetProp)
   299  		return
   300  	}
   301  	if p.WktPointer && !isMap {
   302  		p.setTag(lockGetProp)
   303  		return
   304  	}
   305  	switch t1 := typ; t1.Kind() {
   306  	case reflect.Struct:
   307  		p.stype = typ
   308  	case reflect.Ptr:
   309  		if t1.Elem().Kind() == reflect.Struct {
   310  			p.stype = t1.Elem()
   311  		}
   312  	case reflect.Slice:
   313  		switch t2 := t1.Elem(); t2.Kind() {
   314  		case reflect.Ptr:
   315  			switch t3 := t2.Elem(); t3.Kind() {
   316  			case reflect.Struct:
   317  				p.stype = t3
   318  			}
   319  		case reflect.Struct:
   320  			p.stype = t2
   321  		}
   322  
   323  	case reflect.Map:
   324  
   325  		p.mtype = t1
   326  		p.MapKeyProp = &Properties{}
   327  		p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
   328  		p.MapValProp = &Properties{}
   329  		vtype := p.mtype.Elem()
   330  		if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
   331  			// The value type is not a message (*T) or bytes ([]byte),
   332  			// so we need encoders for the pointer to this type.
   333  			vtype = reflect.PtrTo(vtype)
   334  		}
   335  
   336  		p.MapValProp.CustomType = p.CustomType
   337  		p.MapValProp.StdDuration = p.StdDuration
   338  		p.MapValProp.StdTime = p.StdTime
   339  		p.MapValProp.WktPointer = p.WktPointer
   340  		p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
   341  	}
   342  	p.setTag(lockGetProp)
   343  }
   344  
   345  func (p *Properties) setTag(lockGetProp bool) {
   346  	if p.stype != nil {
   347  		if lockGetProp {
   348  			p.sprop = GetProperties(p.stype)
   349  		} else {
   350  			p.sprop = getPropertiesLocked(p.stype)
   351  		}
   352  	}
   353  }
   354  
   355  var (
   356  	marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
   357  )
   358  
   359  // Init populates the properties from a protocol buffer struct tag.
   360  func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
   361  	p.init(typ, name, tag, f, true)
   362  }
   363  
   364  func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
   365  	// "bytes,49,opt,def=hello!"
   366  	p.Name = name
   367  	p.OrigName = name
   368  	if tag == "" {
   369  		return
   370  	}
   371  	p.Parse(tag)
   372  	p.setFieldProps(typ, f, lockGetProp)
   373  }
   374  
   375  var (
   376  	propertiesMu  sync.RWMutex
   377  	propertiesMap = make(map[reflect.Type]*StructProperties)
   378  )
   379  
   380  // GetProperties returns the list of properties for the type represented by t.
   381  // t must represent a generated struct type of a protocol message.
   382  func GetProperties(t reflect.Type) *StructProperties {
   383  	if t.Kind() != reflect.Struct {
   384  		panic("proto: type must have kind struct")
   385  	}
   386  
   387  	// Most calls to GetProperties in a long-running program will be
   388  	// retrieving details for types we have seen before.
   389  	propertiesMu.RLock()
   390  	sprop, ok := propertiesMap[t]
   391  	propertiesMu.RUnlock()
   392  	if ok {
   393  		return sprop
   394  	}
   395  
   396  	propertiesMu.Lock()
   397  	sprop = getPropertiesLocked(t)
   398  	propertiesMu.Unlock()
   399  	return sprop
   400  }
   401  
   402  type (
   403  	oneofFuncsIface interface {
   404  		XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
   405  	}
   406  	oneofWrappersIface interface {
   407  		XXX_OneofWrappers() []interface{}
   408  	}
   409  )
   410  
   411  // getPropertiesLocked requires that propertiesMu is held.
   412  func getPropertiesLocked(t reflect.Type) *StructProperties {
   413  	if prop, ok := propertiesMap[t]; ok {
   414  		return prop
   415  	}
   416  
   417  	prop := new(StructProperties)
   418  	// in case of recursive protos, fill this in now.
   419  	propertiesMap[t] = prop
   420  
   421  	// build properties
   422  	prop.Prop = make([]*Properties, t.NumField())
   423  	prop.order = make([]int, t.NumField())
   424  
   425  	isOneofMessage := false
   426  	for i := 0; i < t.NumField(); i++ {
   427  		f := t.Field(i)
   428  		p := new(Properties)
   429  		name := f.Name
   430  		p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
   431  
   432  		oneof := f.Tag.Get("protobuf_oneof") // special case
   433  		if oneof != "" {
   434  			isOneofMessage = true
   435  			// Oneof fields don't use the traditional protobuf tag.
   436  			p.OrigName = oneof
   437  		}
   438  		prop.Prop[i] = p
   439  		prop.order[i] = i
   440  		if debug {
   441  			print(i, " ", f.Name, " ", t.String(), " ")
   442  			if p.Tag > 0 {
   443  				print(p.String())
   444  			}
   445  			print("\n")
   446  		}
   447  	}
   448  
   449  	// Re-order prop.order.
   450  	sort.Sort(prop)
   451  
   452  	if isOneofMessage {
   453  		var oots []interface{}
   454  		switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
   455  		case oneofFuncsIface:
   456  			_, _, _, oots = m.XXX_OneofFuncs()
   457  		case oneofWrappersIface:
   458  			oots = m.XXX_OneofWrappers()
   459  		}
   460  		if len(oots) > 0 {
   461  			// Interpret oneof metadata.
   462  			prop.OneofTypes = make(map[string]*OneofProperties)
   463  			for _, oot := range oots {
   464  				oop := &OneofProperties{
   465  					Type: reflect.ValueOf(oot).Type(), // *T
   466  					Prop: new(Properties),
   467  				}
   468  				sft := oop.Type.Elem().Field(0)
   469  				oop.Prop.Name = sft.Name
   470  				oop.Prop.Parse(sft.Tag.Get("protobuf"))
   471  				// There will be exactly one interface field that
   472  				// this new value is assignable to.
   473  				for i := 0; i < t.NumField(); i++ {
   474  					f := t.Field(i)
   475  					if f.Type.Kind() != reflect.Interface {
   476  						continue
   477  					}
   478  					if !oop.Type.AssignableTo(f.Type) {
   479  						continue
   480  					}
   481  					oop.Field = i
   482  					break
   483  				}
   484  				prop.OneofTypes[oop.Prop.OrigName] = oop
   485  			}
   486  		}
   487  	}
   488  
   489  	// build required counts
   490  	// build tags
   491  	reqCount := 0
   492  	prop.decoderOrigNames = make(map[string]int)
   493  	for i, p := range prop.Prop {
   494  		if strings.HasPrefix(p.Name, "XXX_") {
   495  			// Internal fields should not appear in tags/origNames maps.
   496  			// They are handled specially when encoding and decoding.
   497  			continue
   498  		}
   499  		if p.Required {
   500  			reqCount++
   501  		}
   502  		prop.decoderTags.put(p.Tag, i)
   503  		prop.decoderOrigNames[p.OrigName] = i
   504  	}
   505  	prop.reqCount = reqCount
   506  
   507  	return prop
   508  }
   509  
   510  // A global registry of enum types.
   511  // The generated code will register the generated maps by calling RegisterEnum.
   512  
   513  var enumValueMaps = make(map[string]map[string]int32)
   514  var enumStringMaps = make(map[string]map[int32]string)
   515  
   516  // RegisterEnum is called from the generated code to install the enum descriptor
   517  // maps into the global table to aid parsing text format protocol buffers.
   518  func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
   519  	if _, ok := enumValueMaps[typeName]; ok {
   520  		panic("proto: duplicate enum registered: " + typeName)
   521  	}
   522  	enumValueMaps[typeName] = valueMap
   523  	if _, ok := enumStringMaps[typeName]; ok {
   524  		panic("proto: duplicate enum registered: " + typeName)
   525  	}
   526  	enumStringMaps[typeName] = unusedNameMap
   527  }
   528  
   529  // EnumValueMap returns the mapping from names to integers of the
   530  // enum type enumType, or a nil if not found.
   531  func EnumValueMap(enumType string) map[string]int32 {
   532  	return enumValueMaps[enumType]
   533  }
   534  
   535  // A registry of all linked message types.
   536  // The string is a fully-qualified proto name ("pkg.Message").
   537  var (
   538  	protoTypedNils = make(map[string]Message)      // a map from proto names to typed nil pointers
   539  	protoMapTypes  = make(map[string]reflect.Type) // a map from proto names to map types
   540  	revProtoTypes  = make(map[reflect.Type]string)
   541  )
   542  
   543  // RegisterType is called from generated code and maps from the fully qualified
   544  // proto name to the type (pointer to struct) of the protocol buffer.
   545  func RegisterType(x Message, name string) {
   546  	if _, ok := protoTypedNils[name]; ok {
   547  		// TODO: Some day, make this a panic.
   548  		log.Printf("proto: duplicate proto type registered: %s", name)
   549  		return
   550  	}
   551  	t := reflect.TypeOf(x)
   552  	if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 {
   553  		// Generated code always calls RegisterType with nil x.
   554  		// This check is just for extra safety.
   555  		protoTypedNils[name] = x
   556  	} else {
   557  		protoTypedNils[name] = reflect.Zero(t).Interface().(Message)
   558  	}
   559  	revProtoTypes[t] = name
   560  }
   561  
   562  // RegisterMapType is called from generated code and maps from the fully qualified
   563  // proto name to the native map type of the proto map definition.
   564  func RegisterMapType(x interface{}, name string) {
   565  	if reflect.TypeOf(x).Kind() != reflect.Map {
   566  		panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name))
   567  	}
   568  	if _, ok := protoMapTypes[name]; ok {
   569  		log.Printf("proto: duplicate proto type registered: %s", name)
   570  		return
   571  	}
   572  	t := reflect.TypeOf(x)
   573  	protoMapTypes[name] = t
   574  	revProtoTypes[t] = name
   575  }
   576  
   577  // MessageName returns the fully-qualified proto name for the given message type.
   578  func MessageName(x Message) string {
   579  	type xname interface {
   580  		XXX_MessageName() string
   581  	}
   582  	if m, ok := x.(xname); ok {
   583  		return m.XXX_MessageName()
   584  	}
   585  	return revProtoTypes[reflect.TypeOf(x)]
   586  }
   587  
   588  // MessageType returns the message type (pointer to struct) for a named message.
   589  // The type is not guaranteed to implement proto.Message if the name refers to a
   590  // map entry.
   591  func MessageType(name string) reflect.Type {
   592  	if t, ok := protoTypedNils[name]; ok {
   593  		return reflect.TypeOf(t)
   594  	}
   595  	return protoMapTypes[name]
   596  }
   597  
   598  // A registry of all linked proto files.
   599  var (
   600  	protoFiles = make(map[string][]byte) // file name => fileDescriptor
   601  )
   602  
   603  // RegisterFile is called from generated code and maps from the
   604  // full file name of a .proto file to its compressed FileDescriptorProto.
   605  func RegisterFile(filename string, fileDescriptor []byte) {
   606  	protoFiles[filename] = fileDescriptor
   607  }
   608  
   609  // FileDescriptor returns the compressed FileDescriptorProto for a .proto file.
   610  func FileDescriptor(filename string) []byte { return protoFiles[filename] }
   611  

View as plain text