github.com/matm/etcd@v0.3.1-0.20140328024009-5b4a473f1453/third_party/code.google.com/p/goprotobuf/proto/properties.go (about)

     1  // Go support for Protocol Buffers - Google's data interchange format
     2  //
     3  // Copyright 2010 The Go Authors.  All rights reserved.
     4  // http://code.google.com/p/goprotobuf/
     5  //
     6  // Redistribution and use in source and binary forms, with or without
     7  // modification, are permitted provided that the following conditions are
     8  // met:
     9  //
    10  //     * Redistributions of source code must retain the above copyright
    11  // notice, this list of conditions and the following disclaimer.
    12  //     * Redistributions in binary form must reproduce the above
    13  // copyright notice, this list of conditions and the following disclaimer
    14  // in the documentation and/or other materials provided with the
    15  // distribution.
    16  //     * Neither the name of Google Inc. nor the names of its
    17  // contributors may be used to endorse or promote products derived from
    18  // this software without specific prior written permission.
    19  //
    20  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  
    32  package proto
    33  
    34  /*
    35   * Routines for encoding data into the wire format for protocol buffers.
    36   */
    37  
    38  import (
    39  	"fmt"
    40  	"os"
    41  	"reflect"
    42  	"sort"
    43  	"strconv"
    44  	"strings"
    45  	"sync"
    46  )
    47  
    48  const debug bool = false
    49  
    50  // Constants that identify the encoding of a value on the wire.
    51  const (
    52  	WireVarint     = 0
    53  	WireFixed64    = 1
    54  	WireBytes      = 2
    55  	WireStartGroup = 3
    56  	WireEndGroup   = 4
    57  	WireFixed32    = 5
    58  )
    59  
    60  const startSize = 10 // initial slice/string sizes
    61  
    62  // Encoders are defined in encode.go
    63  // An encoder outputs the full representation of a field, including its
    64  // tag and encoder type.
    65  type encoder func(p *Buffer, prop *Properties, base structPointer) error
    66  
    67  // A valueEncoder encodes a single integer in a particular encoding.
    68  type valueEncoder func(o *Buffer, x uint64) error
    69  
    70  // Sizers are defined in encode.go
    71  // A sizer returns the encoded size of a field, including its tag and encoder
    72  // type.
    73  type sizer func(prop *Properties, base structPointer) int
    74  
    75  // A valueSizer returns the encoded size of a single integer in a particular
    76  // encoding.
    77  type valueSizer func(x uint64) int
    78  
    79  // Decoders are defined in decode.go
    80  // A decoder creates a value from its wire representation.
    81  // Unrecognized subelements are saved in unrec.
    82  type decoder func(p *Buffer, prop *Properties, base structPointer) error
    83  
    84  // A valueDecoder decodes a single integer in a particular encoding.
    85  type valueDecoder func(o *Buffer) (x uint64, err error)
    86  
    87  // tagMap is an optimization over map[int]int for typical protocol buffer
    88  // use-cases. Encoded protocol buffers are often in tag order with small tag
    89  // numbers.
    90  type tagMap struct {
    91  	fastTags []int
    92  	slowTags map[int]int
    93  }
    94  
    95  // tagMapFastLimit is the upper bound on the tag number that will be stored in
    96  // the tagMap slice rather than its map.
    97  const tagMapFastLimit = 1024
    98  
    99  func (p *tagMap) get(t int) (int, bool) {
   100  	if t > 0 && t < tagMapFastLimit {
   101  		if t >= len(p.fastTags) {
   102  			return 0, false
   103  		}
   104  		fi := p.fastTags[t]
   105  		return fi, fi >= 0
   106  	}
   107  	fi, ok := p.slowTags[t]
   108  	return fi, ok
   109  }
   110  
   111  func (p *tagMap) put(t int, fi int) {
   112  	if t > 0 && t < tagMapFastLimit {
   113  		for len(p.fastTags) < t+1 {
   114  			p.fastTags = append(p.fastTags, -1)
   115  		}
   116  		p.fastTags[t] = fi
   117  		return
   118  	}
   119  	if p.slowTags == nil {
   120  		p.slowTags = make(map[int]int)
   121  	}
   122  	p.slowTags[t] = fi
   123  }
   124  
   125  // StructProperties represents properties for all the fields of a struct.
   126  // decoderTags and decoderOrigNames should only be used by the decoder.
   127  type StructProperties struct {
   128  	Prop             []*Properties  // properties for each field
   129  	reqCount         int            // required count
   130  	decoderTags      tagMap         // map from proto tag to struct field number
   131  	decoderOrigNames map[string]int // map from original name to struct field number
   132  	order            []int          // list of struct field numbers in tag order
   133  	unrecField       field          // field id of the XXX_unrecognized []byte field
   134  	extendable       bool           // is this an extendable proto
   135  }
   136  
   137  // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
   138  // See encode.go, (*Buffer).enc_struct.
   139  
   140  func (sp *StructProperties) Len() int { return len(sp.order) }
   141  func (sp *StructProperties) Less(i, j int) bool {
   142  	return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
   143  }
   144  func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
   145  
   146  // Properties represents the protocol-specific behavior of a single struct field.
   147  type Properties struct {
   148  	Name       string // name of the field, for error messages
   149  	OrigName   string // original name before protocol compiler (always set)
   150  	Wire       string
   151  	WireType   int
   152  	Tag        int
   153  	Required   bool
   154  	Optional   bool
   155  	Repeated   bool
   156  	Packed     bool   // relevant for repeated primitives only
   157  	Enum       string // set for enum types only
   158  	Default    string // default value
   159  	def_uint64 uint64
   160  
   161  	enc           encoder
   162  	valEnc        valueEncoder // set for bool and numeric types only
   163  	field         field
   164  	tagcode       []byte // encoding of EncodeVarint((Tag<<3)|WireType)
   165  	tagbuf        [8]byte
   166  	stype         reflect.Type      // set for struct types only
   167  	sprop         *StructProperties // set for struct types only
   168  	isMarshaler   bool
   169  	isUnmarshaler bool
   170  
   171  	size    sizer
   172  	valSize valueSizer // set for bool and numeric types only
   173  
   174  	dec    decoder
   175  	valDec valueDecoder // set for bool and numeric types only
   176  
   177  	// If this is a packable field, this will be the decoder for the packed version of the field.
   178  	packedDec decoder
   179  }
   180  
   181  // String formats the properties in the protobuf struct field tag style.
   182  func (p *Properties) String() string {
   183  	s := p.Wire
   184  	s = ","
   185  	s += strconv.Itoa(p.Tag)
   186  	if p.Required {
   187  		s += ",req"
   188  	}
   189  	if p.Optional {
   190  		s += ",opt"
   191  	}
   192  	if p.Repeated {
   193  		s += ",rep"
   194  	}
   195  	if p.Packed {
   196  		s += ",packed"
   197  	}
   198  	if p.OrigName != p.Name {
   199  		s += ",name=" + p.OrigName
   200  	}
   201  	if len(p.Enum) > 0 {
   202  		s += ",enum=" + p.Enum
   203  	}
   204  	if len(p.Default) > 0 {
   205  		s += ",def=" + p.Default
   206  	}
   207  	return s
   208  }
   209  
   210  // Parse populates p by parsing a string in the protobuf struct field tag style.
   211  func (p *Properties) Parse(s string) {
   212  	// "bytes,49,opt,name=foo,def=hello!"
   213  	fields := strings.Split(s, ",") // breaks def=, but handled below.
   214  	if len(fields) < 2 {
   215  		fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
   216  		return
   217  	}
   218  
   219  	p.Wire = fields[0]
   220  	switch p.Wire {
   221  	case "varint":
   222  		p.WireType = WireVarint
   223  		p.valEnc = (*Buffer).EncodeVarint
   224  		p.valDec = (*Buffer).DecodeVarint
   225  		p.valSize = sizeVarint
   226  	case "fixed32":
   227  		p.WireType = WireFixed32
   228  		p.valEnc = (*Buffer).EncodeFixed32
   229  		p.valDec = (*Buffer).DecodeFixed32
   230  		p.valSize = sizeFixed32
   231  	case "fixed64":
   232  		p.WireType = WireFixed64
   233  		p.valEnc = (*Buffer).EncodeFixed64
   234  		p.valDec = (*Buffer).DecodeFixed64
   235  		p.valSize = sizeFixed64
   236  	case "zigzag32":
   237  		p.WireType = WireVarint
   238  		p.valEnc = (*Buffer).EncodeZigzag32
   239  		p.valDec = (*Buffer).DecodeZigzag32
   240  		p.valSize = sizeZigzag32
   241  	case "zigzag64":
   242  		p.WireType = WireVarint
   243  		p.valEnc = (*Buffer).EncodeZigzag64
   244  		p.valDec = (*Buffer).DecodeZigzag64
   245  		p.valSize = sizeZigzag64
   246  	case "bytes", "group":
   247  		p.WireType = WireBytes
   248  		// no numeric converter for non-numeric types
   249  	default:
   250  		fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
   251  		return
   252  	}
   253  
   254  	var err error
   255  	p.Tag, err = strconv.Atoi(fields[1])
   256  	if err != nil {
   257  		return
   258  	}
   259  
   260  	for i := 2; i < len(fields); i++ {
   261  		f := fields[i]
   262  		switch {
   263  		case f == "req":
   264  			p.Required = true
   265  		case f == "opt":
   266  			p.Optional = true
   267  		case f == "rep":
   268  			p.Repeated = true
   269  		case f == "packed":
   270  			p.Packed = true
   271  		case strings.HasPrefix(f, "name="):
   272  			p.OrigName = f[5:]
   273  		case strings.HasPrefix(f, "enum="):
   274  			p.Enum = f[5:]
   275  		case strings.HasPrefix(f, "def="):
   276  			p.Default = f[4:] // rest of string
   277  			if i+1 < len(fields) {
   278  				// Commas aren't escaped, and def is always last.
   279  				p.Default += "," + strings.Join(fields[i+1:], ",")
   280  				break
   281  			}
   282  		}
   283  	}
   284  }
   285  
   286  func logNoSliceEnc(t1, t2 reflect.Type) {
   287  	fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
   288  }
   289  
   290  var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
   291  
   292  // Initialize the fields for encoding and decoding.
   293  func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) {
   294  	p.enc = nil
   295  	p.dec = nil
   296  	p.size = nil
   297  
   298  	switch t1 := typ; t1.Kind() {
   299  	default:
   300  		fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
   301  
   302  	case reflect.Ptr:
   303  		switch t2 := t1.Elem(); t2.Kind() {
   304  		default:
   305  			fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
   306  			break
   307  		case reflect.Bool:
   308  			p.enc = (*Buffer).enc_bool
   309  			p.dec = (*Buffer).dec_bool
   310  			p.size = size_bool
   311  		case reflect.Int32, reflect.Uint32:
   312  			p.enc = (*Buffer).enc_int32
   313  			p.dec = (*Buffer).dec_int32
   314  			p.size = size_int32
   315  		case reflect.Int64, reflect.Uint64:
   316  			p.enc = (*Buffer).enc_int64
   317  			p.dec = (*Buffer).dec_int64
   318  			p.size = size_int64
   319  		case reflect.Float32:
   320  			p.enc = (*Buffer).enc_int32 // can just treat them as bits
   321  			p.dec = (*Buffer).dec_int32
   322  			p.size = size_int32
   323  		case reflect.Float64:
   324  			p.enc = (*Buffer).enc_int64 // can just treat them as bits
   325  			p.dec = (*Buffer).dec_int64
   326  			p.size = size_int64
   327  		case reflect.String:
   328  			p.enc = (*Buffer).enc_string
   329  			p.dec = (*Buffer).dec_string
   330  			p.size = size_string
   331  		case reflect.Struct:
   332  			p.stype = t1.Elem()
   333  			p.isMarshaler = isMarshaler(t1)
   334  			p.isUnmarshaler = isUnmarshaler(t1)
   335  			if p.Wire == "bytes" {
   336  				p.enc = (*Buffer).enc_struct_message
   337  				p.dec = (*Buffer).dec_struct_message
   338  				p.size = size_struct_message
   339  			} else {
   340  				p.enc = (*Buffer).enc_struct_group
   341  				p.dec = (*Buffer).dec_struct_group
   342  				p.size = size_struct_group
   343  			}
   344  		}
   345  
   346  	case reflect.Slice:
   347  		switch t2 := t1.Elem(); t2.Kind() {
   348  		default:
   349  			logNoSliceEnc(t1, t2)
   350  			break
   351  		case reflect.Bool:
   352  			if p.Packed {
   353  				p.enc = (*Buffer).enc_slice_packed_bool
   354  				p.size = size_slice_packed_bool
   355  			} else {
   356  				p.enc = (*Buffer).enc_slice_bool
   357  				p.size = size_slice_bool
   358  			}
   359  			p.dec = (*Buffer).dec_slice_bool
   360  			p.packedDec = (*Buffer).dec_slice_packed_bool
   361  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   362  			switch t2.Bits() {
   363  			case 32:
   364  				if p.Packed {
   365  					p.enc = (*Buffer).enc_slice_packed_int32
   366  					p.size = size_slice_packed_int32
   367  				} else {
   368  					p.enc = (*Buffer).enc_slice_int32
   369  					p.size = size_slice_int32
   370  				}
   371  				p.dec = (*Buffer).dec_slice_int32
   372  				p.packedDec = (*Buffer).dec_slice_packed_int32
   373  			case 64:
   374  				if p.Packed {
   375  					p.enc = (*Buffer).enc_slice_packed_int64
   376  					p.size = size_slice_packed_int64
   377  				} else {
   378  					p.enc = (*Buffer).enc_slice_int64
   379  					p.size = size_slice_int64
   380  				}
   381  				p.dec = (*Buffer).dec_slice_int64
   382  				p.packedDec = (*Buffer).dec_slice_packed_int64
   383  			case 8:
   384  				if t2.Kind() == reflect.Uint8 {
   385  					p.enc = (*Buffer).enc_slice_byte
   386  					p.dec = (*Buffer).dec_slice_byte
   387  					p.size = size_slice_byte
   388  				}
   389  			default:
   390  				logNoSliceEnc(t1, t2)
   391  				break
   392  			}
   393  		case reflect.Float32, reflect.Float64:
   394  			switch t2.Bits() {
   395  			case 32:
   396  				// can just treat them as bits
   397  				if p.Packed {
   398  					p.enc = (*Buffer).enc_slice_packed_int32
   399  					p.size = size_slice_packed_int32
   400  				} else {
   401  					p.enc = (*Buffer).enc_slice_int32
   402  					p.size = size_slice_int32
   403  				}
   404  				p.dec = (*Buffer).dec_slice_int32
   405  				p.packedDec = (*Buffer).dec_slice_packed_int32
   406  			case 64:
   407  				// can just treat them as bits
   408  				if p.Packed {
   409  					p.enc = (*Buffer).enc_slice_packed_int64
   410  					p.size = size_slice_packed_int64
   411  				} else {
   412  					p.enc = (*Buffer).enc_slice_int64
   413  					p.size = size_slice_int64
   414  				}
   415  				p.dec = (*Buffer).dec_slice_int64
   416  				p.packedDec = (*Buffer).dec_slice_packed_int64
   417  			default:
   418  				logNoSliceEnc(t1, t2)
   419  				break
   420  			}
   421  		case reflect.String:
   422  			p.enc = (*Buffer).enc_slice_string
   423  			p.dec = (*Buffer).dec_slice_string
   424  			p.size = size_slice_string
   425  		case reflect.Ptr:
   426  			switch t3 := t2.Elem(); t3.Kind() {
   427  			default:
   428  				fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
   429  				break
   430  			case reflect.Struct:
   431  				p.stype = t2.Elem()
   432  				p.isMarshaler = isMarshaler(t2)
   433  				p.isUnmarshaler = isUnmarshaler(t2)
   434  				if p.Wire == "bytes" {
   435  					p.enc = (*Buffer).enc_slice_struct_message
   436  					p.dec = (*Buffer).dec_slice_struct_message
   437  					p.size = size_slice_struct_message
   438  				} else {
   439  					p.enc = (*Buffer).enc_slice_struct_group
   440  					p.dec = (*Buffer).dec_slice_struct_group
   441  					p.size = size_slice_struct_group
   442  				}
   443  			}
   444  		case reflect.Slice:
   445  			switch t2.Elem().Kind() {
   446  			default:
   447  				fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
   448  				break
   449  			case reflect.Uint8:
   450  				p.enc = (*Buffer).enc_slice_slice_byte
   451  				p.dec = (*Buffer).dec_slice_slice_byte
   452  				p.size = size_slice_slice_byte
   453  			}
   454  		}
   455  	}
   456  
   457  	// precalculate tag code
   458  	wire := p.WireType
   459  	if p.Packed {
   460  		wire = WireBytes
   461  	}
   462  	x := uint32(p.Tag)<<3 | uint32(wire)
   463  	i := 0
   464  	for i = 0; x > 127; i++ {
   465  		p.tagbuf[i] = 0x80 | uint8(x&0x7F)
   466  		x >>= 7
   467  	}
   468  	p.tagbuf[i] = uint8(x)
   469  	p.tagcode = p.tagbuf[0 : i+1]
   470  
   471  	if p.stype != nil {
   472  		if lockGetProp {
   473  			p.sprop = GetProperties(p.stype)
   474  		} else {
   475  			p.sprop = getPropertiesLocked(p.stype)
   476  		}
   477  	}
   478  }
   479  
   480  var (
   481  	marshalerType   = reflect.TypeOf((*Marshaler)(nil)).Elem()
   482  	unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
   483  )
   484  
   485  // isMarshaler reports whether type t implements Marshaler.
   486  func isMarshaler(t reflect.Type) bool {
   487  	// We're checking for (likely) pointer-receiver methods
   488  	// so if t is not a pointer, something is very wrong.
   489  	// The calls above only invoke isMarshaler on pointer types.
   490  	if t.Kind() != reflect.Ptr {
   491  		panic("proto: misuse of isMarshaler")
   492  	}
   493  	return t.Implements(marshalerType)
   494  }
   495  
   496  // isUnmarshaler reports whether type t implements Unmarshaler.
   497  func isUnmarshaler(t reflect.Type) bool {
   498  	// We're checking for (likely) pointer-receiver methods
   499  	// so if t is not a pointer, something is very wrong.
   500  	// The calls above only invoke isUnmarshaler on pointer types.
   501  	if t.Kind() != reflect.Ptr {
   502  		panic("proto: misuse of isUnmarshaler")
   503  	}
   504  	return t.Implements(unmarshalerType)
   505  }
   506  
   507  // Init populates the properties from a protocol buffer struct tag.
   508  func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
   509  	p.init(typ, name, tag, f, true)
   510  }
   511  
   512  func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
   513  	// "bytes,49,opt,def=hello!"
   514  	p.Name = name
   515  	p.OrigName = name
   516  	if f != nil {
   517  		p.field = toField(f)
   518  	}
   519  	if tag == "" {
   520  		return
   521  	}
   522  	p.Parse(tag)
   523  	p.setEncAndDec(typ, lockGetProp)
   524  }
   525  
   526  var (
   527  	mutex         sync.Mutex
   528  	propertiesMap = make(map[reflect.Type]*StructProperties)
   529  )
   530  
   531  // GetProperties returns the list of properties for the type represented by t.
   532  func GetProperties(t reflect.Type) *StructProperties {
   533  	mutex.Lock()
   534  	sprop := getPropertiesLocked(t)
   535  	mutex.Unlock()
   536  	return sprop
   537  }
   538  
   539  // getPropertiesLocked requires that mutex is held.
   540  func getPropertiesLocked(t reflect.Type) *StructProperties {
   541  	if prop, ok := propertiesMap[t]; ok {
   542  		if collectStats {
   543  			stats.Chit++
   544  		}
   545  		return prop
   546  	}
   547  	if collectStats {
   548  		stats.Cmiss++
   549  	}
   550  
   551  	prop := new(StructProperties)
   552  	// in case of recursive protos, fill this in now.
   553  	propertiesMap[t] = prop
   554  
   555  	// build properties
   556  	prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
   557  	prop.unrecField = invalidField
   558  	prop.Prop = make([]*Properties, t.NumField())
   559  	prop.order = make([]int, t.NumField())
   560  
   561  	for i := 0; i < t.NumField(); i++ {
   562  		f := t.Field(i)
   563  		p := new(Properties)
   564  		name := f.Name
   565  		p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
   566  
   567  		if f.Name == "XXX_extensions" { // special case
   568  			p.enc = (*Buffer).enc_map
   569  			p.dec = nil // not needed
   570  			p.size = size_map
   571  		}
   572  		if f.Name == "XXX_unrecognized" { // special case
   573  			prop.unrecField = toField(&f)
   574  		}
   575  		prop.Prop[i] = p
   576  		prop.order[i] = i
   577  		if debug {
   578  			print(i, " ", f.Name, " ", t.String(), " ")
   579  			if p.Tag > 0 {
   580  				print(p.String())
   581  			}
   582  			print("\n")
   583  		}
   584  		if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
   585  			fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
   586  		}
   587  	}
   588  
   589  	// Re-order prop.order.
   590  	sort.Sort(prop)
   591  
   592  	// build required counts
   593  	// build tags
   594  	reqCount := 0
   595  	prop.decoderOrigNames = make(map[string]int)
   596  	for i, p := range prop.Prop {
   597  		if strings.HasPrefix(p.Name, "XXX_") {
   598  			// Internal fields should not appear in tags/origNames maps.
   599  			// They are handled specially when encoding and decoding.
   600  			continue
   601  		}
   602  		if p.Required {
   603  			reqCount++
   604  		}
   605  		prop.decoderTags.put(p.Tag, i)
   606  		prop.decoderOrigNames[p.OrigName] = i
   607  	}
   608  	prop.reqCount = reqCount
   609  
   610  	return prop
   611  }
   612  
   613  // Return the Properties object for the x[0]'th field of the structure.
   614  func propByIndex(t reflect.Type, x []int) *Properties {
   615  	if len(x) != 1 {
   616  		fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
   617  		return nil
   618  	}
   619  	prop := GetProperties(t)
   620  	return prop.Prop[x[0]]
   621  }
   622  
   623  // Get the address and type of a pointer to a struct from an interface.
   624  func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
   625  	if pb == nil {
   626  		err = ErrNil
   627  		return
   628  	}
   629  	// get the reflect type of the pointer to the struct.
   630  	t = reflect.TypeOf(pb)
   631  	// get the address of the struct.
   632  	value := reflect.ValueOf(pb)
   633  	b = toStructPointer(value)
   634  	return
   635  }
   636  
   637  // A global registry of enum types.
   638  // The generated code will register the generated maps by calling RegisterEnum.
   639  
   640  var enumValueMaps = make(map[string]map[string]int32)
   641  
   642  // RegisterEnum is called from the generated code to install the enum descriptor
   643  // maps into the global table to aid parsing text format protocol buffers.
   644  func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
   645  	if _, ok := enumValueMaps[typeName]; ok {
   646  		panic("proto: duplicate enum registered: " + typeName)
   647  	}
   648  	enumValueMaps[typeName] = valueMap
   649  }