| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | // Copyright 2018 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. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package impl | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"sync/atomic" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"google.golang.org/protobuf/internal/genid" | 
					
						
							|  |  |  | 	"google.golang.org/protobuf/reflect/protoreflect" | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 	"google.golang.org/protobuf/reflect/protoregistry" | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MessageInfo provides protobuf related functionality for a given Go type | 
					
						
							|  |  |  | // that represents a message. A given instance of MessageInfo is tied to | 
					
						
							|  |  |  | // exactly one Go type, which must be a pointer to a struct type. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The exported fields must be populated before any methods are called | 
					
						
							|  |  |  | // and cannot be mutated after set. | 
					
						
							|  |  |  | type MessageInfo struct { | 
					
						
							|  |  |  | 	// GoReflectType is the underlying message Go type and must be populated. | 
					
						
							|  |  |  | 	GoReflectType reflect.Type // pointer to struct | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Desc is the underlying message descriptor type and must be populated. | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 	Desc protoreflect.MessageDescriptor | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Exporter must be provided in a purego environment in order to provide | 
					
						
							|  |  |  | 	// access to unexported fields. | 
					
						
							|  |  |  | 	Exporter exporter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// OneofWrappers is list of pointers to oneof wrapper struct types. | 
					
						
							|  |  |  | 	OneofWrappers []interface{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	initMu   sync.Mutex // protects all unexported fields | 
					
						
							|  |  |  | 	initDone uint32 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	reflectMessageInfo // for reflection implementation | 
					
						
							|  |  |  | 	coderMessageInfo   // for fast-path method implementations | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // exporter is a function that returns a reference to the ith field of v, | 
					
						
							|  |  |  | // where v is a pointer to a struct. It returns nil if it does not support | 
					
						
							|  |  |  | // exporting the requested field (e.g., already exported). | 
					
						
							|  |  |  | type exporter func(v interface{}, i int) interface{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // getMessageInfo returns the MessageInfo for any message type that | 
					
						
							|  |  |  | // is generated by our implementation of protoc-gen-go (for v2 and on). | 
					
						
							|  |  |  | // If it is unable to obtain a MessageInfo, it returns nil. | 
					
						
							|  |  |  | func getMessageInfo(mt reflect.Type) *MessageInfo { | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 	m, ok := reflect.Zero(mt).Interface().(protoreflect.ProtoMessage) | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mr, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *MessageInfo }) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return mr.ProtoMessageInfo() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (mi *MessageInfo) init() { | 
					
						
							|  |  |  | 	// This function is called in the hot path. Inline the sync.Once logic, | 
					
						
							|  |  |  | 	// since allocating a closure for Once.Do is expensive. | 
					
						
							|  |  |  | 	// Keep init small to ensure that it can be inlined. | 
					
						
							|  |  |  | 	if atomic.LoadUint32(&mi.initDone) == 0 { | 
					
						
							|  |  |  | 		mi.initOnce() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (mi *MessageInfo) initOnce() { | 
					
						
							|  |  |  | 	mi.initMu.Lock() | 
					
						
							|  |  |  | 	defer mi.initMu.Unlock() | 
					
						
							|  |  |  | 	if mi.initDone == 1 { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t := mi.GoReflectType | 
					
						
							|  |  |  | 	if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct { | 
					
						
							|  |  |  | 		panic(fmt.Sprintf("got %v, want *struct kind", t)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	t = t.Elem() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	si := mi.makeStructInfo(t) | 
					
						
							|  |  |  | 	mi.makeReflectFuncs(t, si) | 
					
						
							|  |  |  | 	mi.makeCoderMethods(t, si) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	atomic.StoreUint32(&mi.initDone, 1) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // getPointer returns the pointer for a message, which should be of | 
					
						
							|  |  |  | // the type of the MessageInfo. If the message is of a different type, | 
					
						
							|  |  |  | // it returns ok==false. | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | func (mi *MessageInfo) getPointer(m protoreflect.Message) (p pointer, ok bool) { | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 	switch m := m.(type) { | 
					
						
							|  |  |  | 	case *messageState: | 
					
						
							|  |  |  | 		return m.pointer(), m.messageInfo() == mi | 
					
						
							|  |  |  | 	case *messageReflectWrapper: | 
					
						
							|  |  |  | 		return m.pointer(), m.messageInfo() == mi | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return pointer{}, false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type ( | 
					
						
							|  |  |  | 	SizeCache       = int32 | 
					
						
							|  |  |  | 	WeakFields      = map[int32]protoreflect.ProtoMessage | 
					
						
							|  |  |  | 	UnknownFields   = unknownFieldsA // TODO: switch to unknownFieldsB | 
					
						
							|  |  |  | 	unknownFieldsA  = []byte | 
					
						
							|  |  |  | 	unknownFieldsB  = *[]byte | 
					
						
							|  |  |  | 	ExtensionFields = map[int32]ExtensionField | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	sizecacheType       = reflect.TypeOf(SizeCache(0)) | 
					
						
							|  |  |  | 	weakFieldsType      = reflect.TypeOf(WeakFields(nil)) | 
					
						
							|  |  |  | 	unknownFieldsAType  = reflect.TypeOf(unknownFieldsA(nil)) | 
					
						
							|  |  |  | 	unknownFieldsBType  = reflect.TypeOf(unknownFieldsB(nil)) | 
					
						
							|  |  |  | 	extensionFieldsType = reflect.TypeOf(ExtensionFields(nil)) | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type structInfo struct { | 
					
						
							|  |  |  | 	sizecacheOffset offset | 
					
						
							|  |  |  | 	sizecacheType   reflect.Type | 
					
						
							|  |  |  | 	weakOffset      offset | 
					
						
							|  |  |  | 	weakType        reflect.Type | 
					
						
							|  |  |  | 	unknownOffset   offset | 
					
						
							|  |  |  | 	unknownType     reflect.Type | 
					
						
							|  |  |  | 	extensionOffset offset | 
					
						
							|  |  |  | 	extensionType   reflect.Type | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 	fieldsByNumber        map[protoreflect.FieldNumber]reflect.StructField | 
					
						
							|  |  |  | 	oneofsByName          map[protoreflect.Name]reflect.StructField | 
					
						
							|  |  |  | 	oneofWrappersByType   map[reflect.Type]protoreflect.FieldNumber | 
					
						
							|  |  |  | 	oneofWrappersByNumber map[protoreflect.FieldNumber]reflect.Type | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo { | 
					
						
							|  |  |  | 	si := structInfo{ | 
					
						
							|  |  |  | 		sizecacheOffset: invalidOffset, | 
					
						
							|  |  |  | 		weakOffset:      invalidOffset, | 
					
						
							|  |  |  | 		unknownOffset:   invalidOffset, | 
					
						
							|  |  |  | 		extensionOffset: invalidOffset, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 		fieldsByNumber:        map[protoreflect.FieldNumber]reflect.StructField{}, | 
					
						
							|  |  |  | 		oneofsByName:          map[protoreflect.Name]reflect.StructField{}, | 
					
						
							|  |  |  | 		oneofWrappersByType:   map[reflect.Type]protoreflect.FieldNumber{}, | 
					
						
							|  |  |  | 		oneofWrappersByNumber: map[protoreflect.FieldNumber]reflect.Type{}, | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | fieldLoop: | 
					
						
							|  |  |  | 	for i := 0; i < t.NumField(); i++ { | 
					
						
							|  |  |  | 		switch f := t.Field(i); f.Name { | 
					
						
							|  |  |  | 		case genid.SizeCache_goname, genid.SizeCacheA_goname: | 
					
						
							|  |  |  | 			if f.Type == sizecacheType { | 
					
						
							|  |  |  | 				si.sizecacheOffset = offsetOf(f, mi.Exporter) | 
					
						
							|  |  |  | 				si.sizecacheType = f.Type | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case genid.WeakFields_goname, genid.WeakFieldsA_goname: | 
					
						
							|  |  |  | 			if f.Type == weakFieldsType { | 
					
						
							|  |  |  | 				si.weakOffset = offsetOf(f, mi.Exporter) | 
					
						
							|  |  |  | 				si.weakType = f.Type | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case genid.UnknownFields_goname, genid.UnknownFieldsA_goname: | 
					
						
							|  |  |  | 			if f.Type == unknownFieldsAType || f.Type == unknownFieldsBType { | 
					
						
							|  |  |  | 				si.unknownOffset = offsetOf(f, mi.Exporter) | 
					
						
							|  |  |  | 				si.unknownType = f.Type | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case genid.ExtensionFields_goname, genid.ExtensionFieldsA_goname, genid.ExtensionFieldsB_goname: | 
					
						
							|  |  |  | 			if f.Type == extensionFieldsType { | 
					
						
							|  |  |  | 				si.extensionOffset = offsetOf(f, mi.Exporter) | 
					
						
							|  |  |  | 				si.extensionType = f.Type | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") { | 
					
						
							|  |  |  | 				if len(s) > 0 && strings.Trim(s, "0123456789") == "" { | 
					
						
							|  |  |  | 					n, _ := strconv.ParseUint(s, 10, 64) | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 					si.fieldsByNumber[protoreflect.FieldNumber(n)] = f | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 					continue fieldLoop | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 { | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 				si.oneofsByName[protoreflect.Name(s)] = f | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 				continue fieldLoop | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Derive a mapping of oneof wrappers to fields. | 
					
						
							|  |  |  | 	oneofWrappers := mi.OneofWrappers | 
					
						
							| 
									
										
										
										
											2024-03-11 10:12:06 +00:00
										 |  |  | 	methods := make([]reflect.Method, 0, 2) | 
					
						
							|  |  |  | 	if m, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok { | 
					
						
							|  |  |  | 		methods = append(methods, m) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if m, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok { | 
					
						
							|  |  |  | 		methods = append(methods, m) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, fn := range methods { | 
					
						
							|  |  |  | 		for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) { | 
					
						
							|  |  |  | 			if vs, ok := v.Interface().([]interface{}); ok { | 
					
						
							|  |  |  | 				oneofWrappers = vs | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, v := range oneofWrappers { | 
					
						
							|  |  |  | 		tf := reflect.TypeOf(v).Elem() | 
					
						
							|  |  |  | 		f := tf.Field(0) | 
					
						
							|  |  |  | 		for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") { | 
					
						
							|  |  |  | 			if len(s) > 0 && strings.Trim(s, "0123456789") == "" { | 
					
						
							|  |  |  | 				n, _ := strconv.ParseUint(s, 10, 64) | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 				si.oneofWrappersByType[tf] = protoreflect.FieldNumber(n) | 
					
						
							|  |  |  | 				si.oneofWrappersByNumber[protoreflect.FieldNumber(n)] = tf | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return si | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (mi *MessageInfo) New() protoreflect.Message { | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 	m := reflect.New(mi.GoReflectType.Elem()).Interface() | 
					
						
							|  |  |  | 	if r, ok := m.(protoreflect.ProtoMessage); ok { | 
					
						
							|  |  |  | 		return r.ProtoReflect() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return mi.MessageOf(m) | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | func (mi *MessageInfo) Zero() protoreflect.Message { | 
					
						
							|  |  |  | 	return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor { | 
					
						
							|  |  |  | 	return mi.Desc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (mi *MessageInfo) Enum(i int) protoreflect.EnumType { | 
					
						
							|  |  |  | 	mi.init() | 
					
						
							|  |  |  | 	fd := mi.Desc.Fields().Get(i) | 
					
						
							|  |  |  | 	return Export{}.EnumTypeOf(mi.fieldTypes[fd.Number()]) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (mi *MessageInfo) Message(i int) protoreflect.MessageType { | 
					
						
							|  |  |  | 	mi.init() | 
					
						
							|  |  |  | 	fd := mi.Desc.Fields().Get(i) | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case fd.IsWeak(): | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | 		mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName()) | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 		return mt | 
					
						
							|  |  |  | 	case fd.IsMap(): | 
					
						
							|  |  |  | 		return mapEntryType{fd.Message(), mi.fieldTypes[fd.Number()]} | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return Export{}.MessageTypeOf(mi.fieldTypes[fd.Number()]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type mapEntryType struct { | 
					
						
							|  |  |  | 	desc    protoreflect.MessageDescriptor | 
					
						
							|  |  |  | 	valType interface{} // zero value of enum or message type | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (mt mapEntryType) New() protoreflect.Message { | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (mt mapEntryType) Zero() protoreflect.Message { | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (mt mapEntryType) Descriptor() protoreflect.MessageDescriptor { | 
					
						
							|  |  |  | 	return mt.desc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (mt mapEntryType) Enum(i int) protoreflect.EnumType { | 
					
						
							|  |  |  | 	fd := mt.desc.Fields().Get(i) | 
					
						
							|  |  |  | 	if fd.Enum() == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return Export{}.EnumTypeOf(mt.valType) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (mt mapEntryType) Message(i int) protoreflect.MessageType { | 
					
						
							|  |  |  | 	fd := mt.desc.Fields().Get(i) | 
					
						
							|  |  |  | 	if fd.Message() == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return Export{}.MessageTypeOf(mt.valType) | 
					
						
							|  |  |  | } |