...

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

Documentation: github.com/golang/protobuf/proto

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package proto
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"strconv"
    11  	"strings"
    12  	"sync"
    13  
    14  	"google.golang.org/protobuf/reflect/protoreflect"
    15  	"google.golang.org/protobuf/runtime/protoimpl"
    16  )
    17  
    18  // StructProperties represents protocol buffer type information for a
    19  // generated protobuf message in the open-struct API.
    20  //
    21  // Deprecated: Do not use.
    22  type StructProperties struct {
    23  	// Prop are the properties for each field.
    24  	//
    25  	// Fields belonging to a oneof are stored in OneofTypes instead, with a
    26  	// single Properties representing the parent oneof held here.
    27  	//
    28  	// The order of Prop matches the order of fields in the Go struct.
    29  	// Struct fields that are not related to protobufs have a "XXX_" prefix
    30  	// in the Properties.Name and must be ignored by the user.
    31  	Prop []*Properties
    32  
    33  	// OneofTypes contains information about the oneof fields in this message.
    34  	// It is keyed by the protobuf field name.
    35  	OneofTypes map[string]*OneofProperties
    36  }
    37  
    38  // Properties represents the type information for a protobuf message field.
    39  //
    40  // Deprecated: Do not use.
    41  type Properties struct {
    42  	// Name is a placeholder name with little meaningful semantic value.
    43  	// If the name has an "XXX_" prefix, the entire Properties must be ignored.
    44  	Name string
    45  	// OrigName is the protobuf field name or oneof name.
    46  	OrigName string
    47  	// JSONName is the JSON name for the protobuf field.
    48  	JSONName string
    49  	// Enum is a placeholder name for enums.
    50  	// For historical reasons, this is neither the Go name for the enum,
    51  	// nor the protobuf name for the enum.
    52  	Enum string // Deprecated: Do not use.
    53  	// Weak contains the full name of the weakly referenced message.
    54  	Weak string
    55  	// Wire is a string representation of the wire type.
    56  	Wire string
    57  	// WireType is the protobuf wire type for the field.
    58  	WireType int
    59  	// Tag is the protobuf field number.
    60  	Tag int
    61  	// Required reports whether this is a required field.
    62  	Required bool
    63  	// Optional reports whether this is a optional field.
    64  	Optional bool
    65  	// Repeated reports whether this is a repeated field.
    66  	Repeated bool
    67  	// Packed reports whether this is a packed repeated field of scalars.
    68  	Packed bool
    69  	// Proto3 reports whether this field operates under the proto3 syntax.
    70  	Proto3 bool
    71  	// Oneof reports whether this field belongs within a oneof.
    72  	Oneof bool
    73  
    74  	// Default is the default value in string form.
    75  	Default string
    76  	// HasDefault reports whether the field has a default value.
    77  	HasDefault bool
    78  
    79  	// MapKeyProp is the properties for the key field for a map field.
    80  	MapKeyProp *Properties
    81  	// MapValProp is the properties for the value field for a map field.
    82  	MapValProp *Properties
    83  }
    84  
    85  // OneofProperties represents the type information for a protobuf oneof.
    86  //
    87  // Deprecated: Do not use.
    88  type OneofProperties struct {
    89  	// Type is a pointer to the generated wrapper type for the field value.
    90  	// This is nil for messages that are not in the open-struct API.
    91  	Type reflect.Type
    92  	// Field is the index into StructProperties.Prop for the containing oneof.
    93  	Field int
    94  	// Prop is the properties for the field.
    95  	Prop *Properties
    96  }
    97  
    98  // String formats the properties in the protobuf struct field tag style.
    99  func (p *Properties) String() string {
   100  	s := p.Wire
   101  	s += "," + strconv.Itoa(p.Tag)
   102  	if p.Required {
   103  		s += ",req"
   104  	}
   105  	if p.Optional {
   106  		s += ",opt"
   107  	}
   108  	if p.Repeated {
   109  		s += ",rep"
   110  	}
   111  	if p.Packed {
   112  		s += ",packed"
   113  	}
   114  	s += ",name=" + p.OrigName
   115  	if p.JSONName != "" {
   116  		s += ",json=" + p.JSONName
   117  	}
   118  	if len(p.Enum) > 0 {
   119  		s += ",enum=" + p.Enum
   120  	}
   121  	if len(p.Weak) > 0 {
   122  		s += ",weak=" + p.Weak
   123  	}
   124  	if p.Proto3 {
   125  		s += ",proto3"
   126  	}
   127  	if p.Oneof {
   128  		s += ",oneof"
   129  	}
   130  	if p.HasDefault {
   131  		s += ",def=" + p.Default
   132  	}
   133  	return s
   134  }
   135  
   136  // Parse populates p by parsing a string in the protobuf struct field tag style.
   137  func (p *Properties) Parse(tag string) {
   138  	// For example: "bytes,49,opt,name=foo,def=hello!"
   139  	for len(tag) > 0 {
   140  		i := strings.IndexByte(tag, ',')
   141  		if i < 0 {
   142  			i = len(tag)
   143  		}
   144  		switch s := tag[:i]; {
   145  		case strings.HasPrefix(s, "name="):
   146  			p.OrigName = s[len("name="):]
   147  		case strings.HasPrefix(s, "json="):
   148  			p.JSONName = s[len("json="):]
   149  		case strings.HasPrefix(s, "enum="):
   150  			p.Enum = s[len("enum="):]
   151  		case strings.HasPrefix(s, "weak="):
   152  			p.Weak = s[len("weak="):]
   153  		case strings.Trim(s, "0123456789") == "":
   154  			n, _ := strconv.ParseUint(s, 10, 32)
   155  			p.Tag = int(n)
   156  		case s == "opt":
   157  			p.Optional = true
   158  		case s == "req":
   159  			p.Required = true
   160  		case s == "rep":
   161  			p.Repeated = true
   162  		case s == "varint" || s == "zigzag32" || s == "zigzag64":
   163  			p.Wire = s
   164  			p.WireType = WireVarint
   165  		case s == "fixed32":
   166  			p.Wire = s
   167  			p.WireType = WireFixed32
   168  		case s == "fixed64":
   169  			p.Wire = s
   170  			p.WireType = WireFixed64
   171  		case s == "bytes":
   172  			p.Wire = s
   173  			p.WireType = WireBytes
   174  		case s == "group":
   175  			p.Wire = s
   176  			p.WireType = WireStartGroup
   177  		case s == "packed":
   178  			p.Packed = true
   179  		case s == "proto3":
   180  			p.Proto3 = true
   181  		case s == "oneof":
   182  			p.Oneof = true
   183  		case strings.HasPrefix(s, "def="):
   184  			// The default tag is special in that everything afterwards is the
   185  			// default regardless of the presence of commas.
   186  			p.HasDefault = true
   187  			p.Default, i = tag[len("def="):], len(tag)
   188  		}
   189  		tag = strings.TrimPrefix(tag[i:], ",")
   190  	}
   191  }
   192  
   193  // Init populates the properties from a protocol buffer struct tag.
   194  //
   195  // Deprecated: Do not use.
   196  func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
   197  	p.Name = name
   198  	p.OrigName = name
   199  	if tag == "" {
   200  		return
   201  	}
   202  	p.Parse(tag)
   203  
   204  	if typ != nil && typ.Kind() == reflect.Map {
   205  		p.MapKeyProp = new(Properties)
   206  		p.MapKeyProp.Init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
   207  		p.MapValProp = new(Properties)
   208  		p.MapValProp.Init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
   209  	}
   210  }
   211  
   212  var propertiesCache sync.Map // map[reflect.Type]*StructProperties
   213  
   214  // GetProperties returns the list of properties for the type represented by t,
   215  // which must be a generated protocol buffer message in the open-struct API,
   216  // where protobuf message fields are represented by exported Go struct fields.
   217  //
   218  // Deprecated: Use protobuf reflection instead.
   219  func GetProperties(t reflect.Type) *StructProperties {
   220  	if p, ok := propertiesCache.Load(t); ok {
   221  		return p.(*StructProperties)
   222  	}
   223  	p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
   224  	return p.(*StructProperties)
   225  }
   226  
   227  func newProperties(t reflect.Type) *StructProperties {
   228  	if t.Kind() != reflect.Struct {
   229  		panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
   230  	}
   231  
   232  	var hasOneof bool
   233  	prop := new(StructProperties)
   234  
   235  	// Construct a list of properties for each field in the struct.
   236  	for i := 0; i < t.NumField(); i++ {
   237  		p := new(Properties)
   238  		f := t.Field(i)
   239  		tagField := f.Tag.Get("protobuf")
   240  		p.Init(f.Type, f.Name, tagField, &f)
   241  
   242  		tagOneof := f.Tag.Get("protobuf_oneof")
   243  		if tagOneof != "" {
   244  			hasOneof = true
   245  			p.OrigName = tagOneof
   246  		}
   247  
   248  		// Rename unrelated struct fields with the "XXX_" prefix since so much
   249  		// user code simply checks for this to exclude special fields.
   250  		if tagField == "" && tagOneof == "" && !strings.HasPrefix(p.Name, "XXX_") {
   251  			p.Name = "XXX_" + p.Name
   252  			p.OrigName = "XXX_" + p.OrigName
   253  		} else if p.Weak != "" {
   254  			p.Name = p.OrigName // avoid possible "XXX_" prefix on weak field
   255  		}
   256  
   257  		prop.Prop = append(prop.Prop, p)
   258  	}
   259  
   260  	// Construct a mapping of oneof field names to properties.
   261  	if hasOneof {
   262  		var oneofWrappers []interface{}
   263  		if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
   264  			oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
   265  		}
   266  		if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
   267  			oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
   268  		}
   269  		if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoreflect.ProtoMessage); ok {
   270  			if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok {
   271  				oneofWrappers = m.ProtoMessageInfo().OneofWrappers
   272  			}
   273  		}
   274  
   275  		prop.OneofTypes = make(map[string]*OneofProperties)
   276  		for _, wrapper := range oneofWrappers {
   277  			p := &OneofProperties{
   278  				Type: reflect.ValueOf(wrapper).Type(), // *T
   279  				Prop: new(Properties),
   280  			}
   281  			f := p.Type.Elem().Field(0)
   282  			p.Prop.Name = f.Name
   283  			p.Prop.Parse(f.Tag.Get("protobuf"))
   284  
   285  			// Determine the struct field that contains this oneof.
   286  			// Each wrapper is assignable to exactly one parent field.
   287  			var foundOneof bool
   288  			for i := 0; i < t.NumField() && !foundOneof; i++ {
   289  				if p.Type.AssignableTo(t.Field(i).Type) {
   290  					p.Field = i
   291  					foundOneof = true
   292  				}
   293  			}
   294  			if !foundOneof {
   295  				panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
   296  			}
   297  			prop.OneofTypes[p.Prop.OrigName] = p
   298  		}
   299  	}
   300  
   301  	return prop
   302  }
   303  
   304  func (sp *StructProperties) Len() int           { return len(sp.Prop) }
   305  func (sp *StructProperties) Less(i, j int) bool { return false }
   306  func (sp *StructProperties) Swap(i, j int)      { return }
   307  

View as plain text