gtsocial-umbx

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

message.go (8571B)


      1 // Copyright 2018 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 impl
      6 
      7 import (
      8 	"fmt"
      9 	"reflect"
     10 	"strconv"
     11 	"strings"
     12 	"sync"
     13 	"sync/atomic"
     14 
     15 	"google.golang.org/protobuf/internal/genid"
     16 	"google.golang.org/protobuf/reflect/protoreflect"
     17 	"google.golang.org/protobuf/reflect/protoregistry"
     18 )
     19 
     20 // MessageInfo provides protobuf related functionality for a given Go type
     21 // that represents a message. A given instance of MessageInfo is tied to
     22 // exactly one Go type, which must be a pointer to a struct type.
     23 //
     24 // The exported fields must be populated before any methods are called
     25 // and cannot be mutated after set.
     26 type MessageInfo struct {
     27 	// GoReflectType is the underlying message Go type and must be populated.
     28 	GoReflectType reflect.Type // pointer to struct
     29 
     30 	// Desc is the underlying message descriptor type and must be populated.
     31 	Desc protoreflect.MessageDescriptor
     32 
     33 	// Exporter must be provided in a purego environment in order to provide
     34 	// access to unexported fields.
     35 	Exporter exporter
     36 
     37 	// OneofWrappers is list of pointers to oneof wrapper struct types.
     38 	OneofWrappers []interface{}
     39 
     40 	initMu   sync.Mutex // protects all unexported fields
     41 	initDone uint32
     42 
     43 	reflectMessageInfo // for reflection implementation
     44 	coderMessageInfo   // for fast-path method implementations
     45 }
     46 
     47 // exporter is a function that returns a reference to the ith field of v,
     48 // where v is a pointer to a struct. It returns nil if it does not support
     49 // exporting the requested field (e.g., already exported).
     50 type exporter func(v interface{}, i int) interface{}
     51 
     52 // getMessageInfo returns the MessageInfo for any message type that
     53 // is generated by our implementation of protoc-gen-go (for v2 and on).
     54 // If it is unable to obtain a MessageInfo, it returns nil.
     55 func getMessageInfo(mt reflect.Type) *MessageInfo {
     56 	m, ok := reflect.Zero(mt).Interface().(protoreflect.ProtoMessage)
     57 	if !ok {
     58 		return nil
     59 	}
     60 	mr, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *MessageInfo })
     61 	if !ok {
     62 		return nil
     63 	}
     64 	return mr.ProtoMessageInfo()
     65 }
     66 
     67 func (mi *MessageInfo) init() {
     68 	// This function is called in the hot path. Inline the sync.Once logic,
     69 	// since allocating a closure for Once.Do is expensive.
     70 	// Keep init small to ensure that it can be inlined.
     71 	if atomic.LoadUint32(&mi.initDone) == 0 {
     72 		mi.initOnce()
     73 	}
     74 }
     75 
     76 func (mi *MessageInfo) initOnce() {
     77 	mi.initMu.Lock()
     78 	defer mi.initMu.Unlock()
     79 	if mi.initDone == 1 {
     80 		return
     81 	}
     82 
     83 	t := mi.GoReflectType
     84 	if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
     85 		panic(fmt.Sprintf("got %v, want *struct kind", t))
     86 	}
     87 	t = t.Elem()
     88 
     89 	si := mi.makeStructInfo(t)
     90 	mi.makeReflectFuncs(t, si)
     91 	mi.makeCoderMethods(t, si)
     92 
     93 	atomic.StoreUint32(&mi.initDone, 1)
     94 }
     95 
     96 // getPointer returns the pointer for a message, which should be of
     97 // the type of the MessageInfo. If the message is of a different type,
     98 // it returns ok==false.
     99 func (mi *MessageInfo) getPointer(m protoreflect.Message) (p pointer, ok bool) {
    100 	switch m := m.(type) {
    101 	case *messageState:
    102 		return m.pointer(), m.messageInfo() == mi
    103 	case *messageReflectWrapper:
    104 		return m.pointer(), m.messageInfo() == mi
    105 	}
    106 	return pointer{}, false
    107 }
    108 
    109 type (
    110 	SizeCache       = int32
    111 	WeakFields      = map[int32]protoreflect.ProtoMessage
    112 	UnknownFields   = unknownFieldsA // TODO: switch to unknownFieldsB
    113 	unknownFieldsA  = []byte
    114 	unknownFieldsB  = *[]byte
    115 	ExtensionFields = map[int32]ExtensionField
    116 )
    117 
    118 var (
    119 	sizecacheType       = reflect.TypeOf(SizeCache(0))
    120 	weakFieldsType      = reflect.TypeOf(WeakFields(nil))
    121 	unknownFieldsAType  = reflect.TypeOf(unknownFieldsA(nil))
    122 	unknownFieldsBType  = reflect.TypeOf(unknownFieldsB(nil))
    123 	extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
    124 )
    125 
    126 type structInfo struct {
    127 	sizecacheOffset offset
    128 	sizecacheType   reflect.Type
    129 	weakOffset      offset
    130 	weakType        reflect.Type
    131 	unknownOffset   offset
    132 	unknownType     reflect.Type
    133 	extensionOffset offset
    134 	extensionType   reflect.Type
    135 
    136 	fieldsByNumber        map[protoreflect.FieldNumber]reflect.StructField
    137 	oneofsByName          map[protoreflect.Name]reflect.StructField
    138 	oneofWrappersByType   map[reflect.Type]protoreflect.FieldNumber
    139 	oneofWrappersByNumber map[protoreflect.FieldNumber]reflect.Type
    140 }
    141 
    142 func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo {
    143 	si := structInfo{
    144 		sizecacheOffset: invalidOffset,
    145 		weakOffset:      invalidOffset,
    146 		unknownOffset:   invalidOffset,
    147 		extensionOffset: invalidOffset,
    148 
    149 		fieldsByNumber:        map[protoreflect.FieldNumber]reflect.StructField{},
    150 		oneofsByName:          map[protoreflect.Name]reflect.StructField{},
    151 		oneofWrappersByType:   map[reflect.Type]protoreflect.FieldNumber{},
    152 		oneofWrappersByNumber: map[protoreflect.FieldNumber]reflect.Type{},
    153 	}
    154 
    155 fieldLoop:
    156 	for i := 0; i < t.NumField(); i++ {
    157 		switch f := t.Field(i); f.Name {
    158 		case genid.SizeCache_goname, genid.SizeCacheA_goname:
    159 			if f.Type == sizecacheType {
    160 				si.sizecacheOffset = offsetOf(f, mi.Exporter)
    161 				si.sizecacheType = f.Type
    162 			}
    163 		case genid.WeakFields_goname, genid.WeakFieldsA_goname:
    164 			if f.Type == weakFieldsType {
    165 				si.weakOffset = offsetOf(f, mi.Exporter)
    166 				si.weakType = f.Type
    167 			}
    168 		case genid.UnknownFields_goname, genid.UnknownFieldsA_goname:
    169 			if f.Type == unknownFieldsAType || f.Type == unknownFieldsBType {
    170 				si.unknownOffset = offsetOf(f, mi.Exporter)
    171 				si.unknownType = f.Type
    172 			}
    173 		case genid.ExtensionFields_goname, genid.ExtensionFieldsA_goname, genid.ExtensionFieldsB_goname:
    174 			if f.Type == extensionFieldsType {
    175 				si.extensionOffset = offsetOf(f, mi.Exporter)
    176 				si.extensionType = f.Type
    177 			}
    178 		default:
    179 			for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
    180 				if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
    181 					n, _ := strconv.ParseUint(s, 10, 64)
    182 					si.fieldsByNumber[protoreflect.FieldNumber(n)] = f
    183 					continue fieldLoop
    184 				}
    185 			}
    186 			if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
    187 				si.oneofsByName[protoreflect.Name(s)] = f
    188 				continue fieldLoop
    189 			}
    190 		}
    191 	}
    192 
    193 	// Derive a mapping of oneof wrappers to fields.
    194 	oneofWrappers := mi.OneofWrappers
    195 	for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} {
    196 		if fn, ok := reflect.PtrTo(t).MethodByName(method); ok {
    197 			for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) {
    198 				if vs, ok := v.Interface().([]interface{}); ok {
    199 					oneofWrappers = vs
    200 				}
    201 			}
    202 		}
    203 	}
    204 	for _, v := range oneofWrappers {
    205 		tf := reflect.TypeOf(v).Elem()
    206 		f := tf.Field(0)
    207 		for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
    208 			if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
    209 				n, _ := strconv.ParseUint(s, 10, 64)
    210 				si.oneofWrappersByType[tf] = protoreflect.FieldNumber(n)
    211 				si.oneofWrappersByNumber[protoreflect.FieldNumber(n)] = tf
    212 				break
    213 			}
    214 		}
    215 	}
    216 
    217 	return si
    218 }
    219 
    220 func (mi *MessageInfo) New() protoreflect.Message {
    221 	m := reflect.New(mi.GoReflectType.Elem()).Interface()
    222 	if r, ok := m.(protoreflect.ProtoMessage); ok {
    223 		return r.ProtoReflect()
    224 	}
    225 	return mi.MessageOf(m)
    226 }
    227 func (mi *MessageInfo) Zero() protoreflect.Message {
    228 	return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface())
    229 }
    230 func (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor {
    231 	return mi.Desc
    232 }
    233 func (mi *MessageInfo) Enum(i int) protoreflect.EnumType {
    234 	mi.init()
    235 	fd := mi.Desc.Fields().Get(i)
    236 	return Export{}.EnumTypeOf(mi.fieldTypes[fd.Number()])
    237 }
    238 func (mi *MessageInfo) Message(i int) protoreflect.MessageType {
    239 	mi.init()
    240 	fd := mi.Desc.Fields().Get(i)
    241 	switch {
    242 	case fd.IsWeak():
    243 		mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName())
    244 		return mt
    245 	case fd.IsMap():
    246 		return mapEntryType{fd.Message(), mi.fieldTypes[fd.Number()]}
    247 	default:
    248 		return Export{}.MessageTypeOf(mi.fieldTypes[fd.Number()])
    249 	}
    250 }
    251 
    252 type mapEntryType struct {
    253 	desc    protoreflect.MessageDescriptor
    254 	valType interface{} // zero value of enum or message type
    255 }
    256 
    257 func (mt mapEntryType) New() protoreflect.Message {
    258 	return nil
    259 }
    260 func (mt mapEntryType) Zero() protoreflect.Message {
    261 	return nil
    262 }
    263 func (mt mapEntryType) Descriptor() protoreflect.MessageDescriptor {
    264 	return mt.desc
    265 }
    266 func (mt mapEntryType) Enum(i int) protoreflect.EnumType {
    267 	fd := mt.desc.Fields().Get(i)
    268 	if fd.Enum() == nil {
    269 		return nil
    270 	}
    271 	return Export{}.EnumTypeOf(mt.valType)
    272 }
    273 func (mt mapEntryType) Message(i int) protoreflect.MessageType {
    274 	fd := mt.desc.Fields().Get(i)
    275 	if fd.Message() == nil {
    276 		return nil
    277 	}
    278 	return Export{}.MessageTypeOf(mt.valType)
    279 }