gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

properties.go (9108B)


      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 }