blob: 28da1475fb3973dc2b2a65d2ba71368016d8724d [file] [log] [blame]
William Kurkianea869482019-04-09 15:16:11 -04001// 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
37package proto
38
39/*
40 * Routines for encoding data into the wire format for protocol buffers.
41 */
42
43import (
44 "fmt"
45 "log"
William Kurkianea869482019-04-09 15:16:11 -040046 "reflect"
47 "sort"
48 "strconv"
49 "strings"
50 "sync"
51)
52
53const debug bool = false
54
55// Constants that identify the encoding of a value on the wire.
56const (
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.
68type 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.
75const tagMapFastLimit = 1024
76
77func (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
89func (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.
105type 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.
118type 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
127func (sp *StructProperties) Len() int { return len(sp.order) }
128func (sp *StructProperties) Less(i, j int) bool {
129 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
130}
131func (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.
134type 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.
167func (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.
203func (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 {
Devmalya Pauldd23a992019-11-14 07:06:31 +0000207 log.Printf("proto: tag has too few fields: %q", s)
William Kurkianea869482019-04-09 15:16:11 -0400208 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:
Devmalya Pauldd23a992019-11-14 07:06:31 +0000227 log.Printf("proto: tag has unknown wire type: %q", s)
William Kurkianea869482019-04-09 15:16:11 -0400228 return
229 }
230
231 var err error
232 p.Tag, err = strconv.Atoi(fields[1])
233 if err != nil {
234 return
235 }
236
237outer:
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
283var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
284
285// setFieldProps initializes the field properties for submessages and maps.
286func (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
345func (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
355var (
356 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
357)
358
359// Init populates the properties from a protocol buffer struct tag.
360func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
361 p.init(typ, name, tag, f, true)
362}
363
364func (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
375var (
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.
382func 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
David Bainbridge788e5202019-10-21 18:49:40 +0000402type (
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
William Kurkianea869482019-04-09 15:16:11 -0400411// getPropertiesLocked requires that propertiesMu is held.
412func 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
David Bainbridge788e5202019-10-21 18:49:40 +0000452 if isOneofMessage {
William Kurkianea869482019-04-09 15:16:11 -0400453 var oots []interface{}
David Bainbridge788e5202019-10-21 18:49:40 +0000454 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),
William Kurkianea869482019-04-09 15:16:11 -0400467 }
David Bainbridge788e5202019-10-21 18:49:40 +0000468 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
William Kurkianea869482019-04-09 15:16:11 -0400483 }
David Bainbridge788e5202019-10-21 18:49:40 +0000484 prop.OneofTypes[oop.Prop.OrigName] = oop
William Kurkianea869482019-04-09 15:16:11 -0400485 }
William Kurkianea869482019-04-09 15:16:11 -0400486 }
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
513var enumValueMaps = make(map[string]map[string]int32)
514var 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.
518func 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.
531func 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").
537var (
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.
545func 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.
564func 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.
578func 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.
591func 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.
599var (
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.
605func RegisterFile(filename string, fileDescriptor []byte) {
606 protoFiles[filename] = fileDescriptor
607}
608
609// FileDescriptor returns the compressed FileDescriptorProto for a .proto file.
610func FileDescriptor(filename string) []byte { return protoFiles[filename] }