123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- // Copyright 2010 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // +build use_golang_protobuf_v1
- package proto
- import (
- "reflect"
- "strconv"
- "strings"
- "sync"
- )
- // Constants that identify the encoding of a value on the wire.
- const (
- WireVarint = 0
- WireFixed32 = 5
- WireFixed64 = 1
- WireBytes = 2
- WireStartGroup = 3
- WireEndGroup = 4
- )
- // StructProperties represents properties for all the fields of a struct.
- type StructProperties struct {
- Prop []*Properties // properties for each field
- // OneofTypes contains information about the oneof fields in this message.
- // It is keyed by the original name of a field.
- OneofTypes map[string]*OneofProperties
- }
- // OneofProperties represents information about a specific field in a oneof.
- type OneofProperties struct {
- Type reflect.Type // pointer to generated struct type for this oneof field
- Field int // struct field number of the containing oneof in the message
- Prop *Properties
- }
- func (sp *StructProperties) Len() int { return len(sp.Prop) }
- func (sp *StructProperties) Less(i, j int) bool { return false }
- func (sp *StructProperties) Swap(i, j int) { return }
- // Properties represents the protocol-specific behavior of a single struct field.
- type Properties struct {
- Name string // name of the field, for error messages
- OrigName string // original name before protocol compiler (always set)
- JSONName string // name to use for JSON; determined by protoc
- Wire string
- WireType int
- Tag int
- Required bool
- Optional bool
- Repeated bool
- Packed bool // relevant for repeated primitives only
- Enum string // set for enum types only
- Proto3 bool // whether this is known to be a proto3 field
- Oneof bool // whether this is a oneof field
- Default string // default value
- HasDefault bool // whether an explicit default was provided
- MapKeyProp *Properties // set for map types only
- MapValProp *Properties // set for map types only
- }
- // String formats the properties in the protobuf struct field tag style.
- func (p *Properties) String() string {
- s := p.Wire
- s += "," + strconv.Itoa(p.Tag)
- if p.Required {
- s += ",req"
- }
- if p.Optional {
- s += ",opt"
- }
- if p.Repeated {
- s += ",rep"
- }
- if p.Packed {
- s += ",packed"
- }
- s += ",name=" + p.OrigName
- if p.JSONName != "" {
- s += ",json=" + p.JSONName
- }
- if p.Proto3 {
- s += ",proto3"
- }
- if p.Oneof {
- s += ",oneof"
- }
- if len(p.Enum) > 0 {
- s += ",enum=" + p.Enum
- }
- if p.HasDefault {
- s += ",def=" + p.Default
- }
- return s
- }
- // Parse populates p by parsing a string in the protobuf struct field tag style.
- func (p *Properties) Parse(tag string) {
- // For example: "bytes,49,opt,name=foo,def=hello!"
- for len(tag) > 0 {
- i := strings.IndexByte(tag, ',')
- if i < 0 {
- i = len(tag)
- }
- switch s := tag[:i]; {
- case strings.HasPrefix(s, "name="):
- p.OrigName = s[len("name="):]
- case strings.HasPrefix(s, "json="):
- p.JSONName = s[len("json="):]
- case strings.HasPrefix(s, "enum="):
- p.Enum = s[len("enum="):]
- case strings.Trim(s, "0123456789") == "":
- n, _ := strconv.ParseUint(s, 10, 32)
- p.Tag = int(n)
- case s == "opt":
- p.Optional = true
- case s == "req":
- p.Required = true
- case s == "rep":
- p.Repeated = true
- case s == "varint" || s == "zigzag32" || s == "zigzag64":
- p.Wire = s
- p.WireType = WireVarint
- case s == "fixed32":
- p.Wire = s
- p.WireType = WireFixed32
- case s == "fixed64":
- p.Wire = s
- p.WireType = WireFixed64
- case s == "bytes":
- p.Wire = s
- p.WireType = WireBytes
- case s == "group":
- p.Wire = s
- p.WireType = WireStartGroup
- case s == "packed":
- p.Packed = true
- case s == "proto3":
- p.Proto3 = true
- case s == "oneof":
- p.Oneof = true
- case strings.HasPrefix(s, "def="):
- // The default tag is special in that everything afterwards is the
- // default regardless of the presence of commas.
- p.HasDefault = true
- p.Default, i = tag[len("def="):], len(tag)
- }
- tag = strings.TrimPrefix(tag[i:], ",")
- }
- }
- // Init populates the properties from a protocol buffer struct tag.
- func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
- p.init(typ, name, tag, f)
- }
- func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField) {
- p.Name = name
- p.OrigName = name
- if tag == "" {
- return
- }
- p.Parse(tag)
- if typ != nil && typ.Kind() == reflect.Map {
- p.MapKeyProp = new(Properties)
- p.MapKeyProp.init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
- p.MapValProp = new(Properties)
- p.MapValProp.init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
- }
- }
- var propertiesCache sync.Map // map[reflect.Type]*StructProperties
- // GetProperties returns the list of properties for the type represented by t.
- // t must represent a generated struct type of a protocol message.
- func GetProperties(t reflect.Type) *StructProperties {
- if p, ok := propertiesCache.Load(t); ok {
- return p.(*StructProperties)
- }
- p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
- return p.(*StructProperties)
- }
- func newProperties(t reflect.Type) *StructProperties {
- if t.Kind() != reflect.Struct {
- panic("proto: type must have kind struct")
- }
- prop := new(StructProperties)
- // Construct a list of properties for each field in the struct.
- for i := 0; i < t.NumField(); i++ {
- p := new(Properties)
- f := t.Field(i)
- p.init(f.Type, f.Name, f.Tag.Get("protobuf"), &f)
- if name := f.Tag.Get("protobuf_oneof"); name != "" {
- p.OrigName = name
- }
- prop.Prop = append(prop.Prop, p)
- }
- // Construct a mapping of oneof field names to properties.
- if oneofImplementors := oneofWrappers(t); len(oneofImplementors) > 0 {
- prop.OneofTypes = make(map[string]*OneofProperties)
- for _, wrapper := range oneofImplementors {
- p := &OneofProperties{
- Type: reflect.ValueOf(wrapper).Type(), // *T
- Prop: new(Properties),
- }
- f := p.Type.Elem().Field(0)
- p.Prop.Name = f.Name
- p.Prop.Parse(f.Tag.Get("protobuf"))
- // Determine the struct field that contains this oneof.
- // Each wrapper is assignable to exactly one parent field.
- for i := 0; i < t.NumField(); i++ {
- if p.Type.AssignableTo(t.Field(i).Type) {
- p.Field = i
- break
- }
- }
- prop.OneofTypes[p.Prop.OrigName] = p
- }
- }
- return prop
- }
|