package impl
import (
"fmt"
"reflect"
"google.golang.org/protobuf/internal/detrand"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/reflect/protoreflect"
)
type reflectMessageInfo struct {
fields map [protoreflect .FieldNumber ]*fieldInfo
oneofs map [protoreflect .Name ]*oneofInfo
fieldTypes map [protoreflect .FieldNumber ]any
denseFields []*fieldInfo
rangeInfos []any
getUnknown func (pointer ) protoreflect .RawFields
setUnknown func (pointer , protoreflect .RawFields )
extensionMap func (pointer ) *extensionMap
nilMessage atomicNilMessage
}
func (mi *MessageInfo ) makeReflectFuncs (t reflect .Type , si structInfo ) {
mi .makeKnownFieldsFunc (si )
mi .makeUnknownFieldsFunc (t , si )
mi .makeExtensionFieldsFunc (t , si )
mi .makeFieldTypes (si )
}
func (mi *MessageInfo ) makeKnownFieldsFunc (si structInfo ) {
mi .fields = map [protoreflect .FieldNumber ]*fieldInfo {}
md := mi .Desc
fds := md .Fields ()
for i := 0 ; i < fds .Len (); i ++ {
fd := fds .Get (i )
fs := si .fieldsByNumber [fd .Number ()]
isOneof := fd .ContainingOneof () != nil && !fd .ContainingOneof ().IsSynthetic ()
if isOneof {
fs = si .oneofsByName [fd .ContainingOneof ().Name ()]
}
var fi fieldInfo
switch {
case fs .Type == nil :
fi = fieldInfoForMissing (fd )
case isOneof :
fi = fieldInfoForOneof (fd , fs , mi .Exporter , si .oneofWrappersByNumber [fd .Number ()])
case fd .IsMap ():
fi = fieldInfoForMap (fd , fs , mi .Exporter )
case fd .IsList ():
fi = fieldInfoForList (fd , fs , mi .Exporter )
case fd .Message () != nil :
fi = fieldInfoForMessage (fd , fs , mi .Exporter )
default :
fi = fieldInfoForScalar (fd , fs , mi .Exporter )
}
mi .fields [fd .Number ()] = &fi
}
mi .oneofs = map [protoreflect .Name ]*oneofInfo {}
for i := 0 ; i < md .Oneofs ().Len (); i ++ {
od := md .Oneofs ().Get (i )
mi .oneofs [od .Name ()] = makeOneofInfo (od , si , mi .Exporter )
}
mi .denseFields = make ([]*fieldInfo , fds .Len ()*2 )
for i := 0 ; i < fds .Len (); i ++ {
if fd := fds .Get (i ); int (fd .Number ()) < len (mi .denseFields ) {
mi .denseFields [fd .Number ()] = mi .fields [fd .Number ()]
}
}
for i := 0 ; i < fds .Len (); {
fd := fds .Get (i )
if od := fd .ContainingOneof (); od != nil && !od .IsSynthetic () {
mi .rangeInfos = append (mi .rangeInfos , mi .oneofs [od .Name ()])
i += od .Fields ().Len ()
} else {
mi .rangeInfos = append (mi .rangeInfos , mi .fields [fd .Number ()])
i ++
}
}
if len (mi .rangeInfos ) > 1 && detrand .Bool () {
i := detrand .Intn (len (mi .rangeInfos ) - 1 )
mi .rangeInfos [i ], mi .rangeInfos [i +1 ] = mi .rangeInfos [i +1 ], mi .rangeInfos [i ]
}
}
func (mi *MessageInfo ) makeUnknownFieldsFunc (t reflect .Type , si structInfo ) {
switch {
case si .unknownOffset .IsValid () && si .unknownType == unknownFieldsAType :
mi .getUnknown = func (p pointer ) protoreflect .RawFields {
if p .IsNil () {
return nil
}
return *p .Apply (mi .unknownOffset ).Bytes ()
}
mi .setUnknown = func (p pointer , b protoreflect .RawFields ) {
if p .IsNil () {
panic ("invalid SetUnknown on nil Message" )
}
*p .Apply (mi .unknownOffset ).Bytes () = b
}
case si .unknownOffset .IsValid () && si .unknownType == unknownFieldsBType :
mi .getUnknown = func (p pointer ) protoreflect .RawFields {
if p .IsNil () {
return nil
}
bp := p .Apply (mi .unknownOffset ).BytesPtr ()
if *bp == nil {
return nil
}
return **bp
}
mi .setUnknown = func (p pointer , b protoreflect .RawFields ) {
if p .IsNil () {
panic ("invalid SetUnknown on nil Message" )
}
bp := p .Apply (mi .unknownOffset ).BytesPtr ()
if *bp == nil {
*bp = new ([]byte )
}
**bp = b
}
default :
mi .getUnknown = func (pointer ) protoreflect .RawFields {
return nil
}
mi .setUnknown = func (p pointer , _ protoreflect .RawFields ) {
if p .IsNil () {
panic ("invalid SetUnknown on nil Message" )
}
}
}
}
func (mi *MessageInfo ) makeExtensionFieldsFunc (t reflect .Type , si structInfo ) {
if si .extensionOffset .IsValid () {
mi .extensionMap = func (p pointer ) *extensionMap {
if p .IsNil () {
return (*extensionMap )(nil )
}
v := p .Apply (si .extensionOffset ).AsValueOf (extensionFieldsType )
return (*extensionMap )(v .Interface ().(*map [int32 ]ExtensionField ))
}
} else {
mi .extensionMap = func (pointer ) *extensionMap {
return (*extensionMap )(nil )
}
}
}
func (mi *MessageInfo ) makeFieldTypes (si structInfo ) {
md := mi .Desc
fds := md .Fields ()
for i := 0 ; i < fds .Len (); i ++ {
var ft reflect .Type
fd := fds .Get (i )
fs := si .fieldsByNumber [fd .Number ()]
isOneof := fd .ContainingOneof () != nil && !fd .ContainingOneof ().IsSynthetic ()
if isOneof {
fs = si .oneofsByName [fd .ContainingOneof ().Name ()]
}
var isMessage bool
switch {
case fs .Type == nil :
continue
case isOneof :
if fd .Enum () != nil || fd .Message () != nil {
ft = si .oneofWrappersByNumber [fd .Number ()].Field (0 ).Type
}
case fd .IsMap ():
if fd .MapValue ().Enum () != nil || fd .MapValue ().Message () != nil {
ft = fs .Type .Elem ()
}
isMessage = fd .MapValue ().Message () != nil
case fd .IsList ():
if fd .Enum () != nil || fd .Message () != nil {
ft = fs .Type .Elem ()
if ft .Kind () == reflect .Slice {
ft = ft .Elem ()
}
}
isMessage = fd .Message () != nil
case fd .Enum () != nil :
ft = fs .Type
if fd .HasPresence () && ft .Kind () == reflect .Ptr {
ft = ft .Elem ()
}
case fd .Message () != nil :
ft = fs .Type
isMessage = true
}
if isMessage && ft != nil && ft .Kind () != reflect .Ptr {
ft = reflect .PtrTo (ft )
}
if ft != nil {
if mi .fieldTypes == nil {
mi .fieldTypes = make (map [protoreflect .FieldNumber ]any )
}
mi .fieldTypes [fd .Number ()] = reflect .Zero (ft ).Interface ()
}
}
}
type extensionMap map [int32 ]ExtensionField
func (m *extensionMap ) Range (f func (protoreflect .FieldDescriptor , protoreflect .Value ) bool ) {
if m != nil {
for _ , x := range *m {
xd := x .Type ().TypeDescriptor ()
v := x .Value ()
if xd .IsList () && v .List ().Len () == 0 {
continue
}
if !f (xd , v ) {
return
}
}
}
}
func (m *extensionMap ) Has (xd protoreflect .ExtensionTypeDescriptor ) (ok bool ) {
if m == nil {
return false
}
x , ok := (*m )[int32 (xd .Number ())]
if !ok {
return false
}
if x .isUnexpandedLazy () {
return true
}
switch {
case xd .IsList ():
return x .Value ().List ().Len () > 0
case xd .IsMap ():
return x .Value ().Map ().Len () > 0
}
return true
}
func (m *extensionMap ) Clear (xd protoreflect .ExtensionTypeDescriptor ) {
delete (*m , int32 (xd .Number ()))
}
func (m *extensionMap ) Get (xd protoreflect .ExtensionTypeDescriptor ) protoreflect .Value {
if m != nil {
if x , ok := (*m )[int32 (xd .Number ())]; ok {
return x .Value ()
}
}
return xd .Type ().Zero ()
}
func (m *extensionMap ) Set (xd protoreflect .ExtensionTypeDescriptor , v protoreflect .Value ) {
xt := xd .Type ()
isValid := true
switch {
case !xt .IsValidValue (v ):
isValid = false
case xd .IsList ():
isValid = v .List ().IsValid ()
case xd .IsMap ():
isValid = v .Map ().IsValid ()
case xd .Message () != nil :
isValid = v .Message ().IsValid ()
}
if !isValid {
panic (fmt .Sprintf ("%v: assigning invalid value" , xd .FullName ()))
}
if *m == nil {
*m = make (map [int32 ]ExtensionField )
}
var x ExtensionField
x .Set (xt , v )
(*m )[int32 (xd .Number ())] = x
}
func (m *extensionMap ) Mutable (xd protoreflect .ExtensionTypeDescriptor ) protoreflect .Value {
if xd .Kind () != protoreflect .MessageKind && xd .Kind () != protoreflect .GroupKind && !xd .IsList () && !xd .IsMap () {
panic ("invalid Mutable on field with non-composite type" )
}
if x , ok := (*m )[int32 (xd .Number ())]; ok {
return x .Value ()
}
v := xd .Type ().New ()
m .Set (xd , v )
return v
}
type MessageState struct {
pragma .NoUnkeyedLiterals
pragma .DoNotCompare
pragma .DoNotCopy
atomicMessageInfo *MessageInfo
}
type messageState MessageState
var (
_ protoreflect .Message = (*messageState )(nil )
_ unwrapper = (*messageState )(nil )
)
type messageDataType struct {
p pointer
mi *MessageInfo
}
type (
messageReflectWrapper messageDataType
messageIfaceWrapper messageDataType
)
var (
_ protoreflect .Message = (*messageReflectWrapper )(nil )
_ unwrapper = (*messageReflectWrapper )(nil )
_ protoreflect .ProtoMessage = (*messageIfaceWrapper )(nil )
_ unwrapper = (*messageIfaceWrapper )(nil )
)
func (mi *MessageInfo ) MessageOf (m any ) protoreflect .Message {
if reflect .TypeOf (m ) != mi .GoReflectType {
panic (fmt .Sprintf ("type mismatch: got %T, want %v" , m , mi .GoReflectType ))
}
p := pointerOfIface (m )
if p .IsNil () {
return mi .nilMessage .Init (mi )
}
return &messageReflectWrapper {p , mi }
}
func (m *messageReflectWrapper ) pointer () pointer { return m .p }
func (m *messageReflectWrapper ) messageInfo () *MessageInfo { return m .mi }
func (m *messageIfaceWrapper ) Reset () {
if mr , ok := m .protoUnwrap ().(interface { Reset () }); ok {
mr .Reset ()
return
}
rv := reflect .ValueOf (m .protoUnwrap ())
if rv .Kind () == reflect .Ptr && !rv .IsNil () {
rv .Elem ().Set (reflect .Zero (rv .Type ().Elem ()))
}
}
func (m *messageIfaceWrapper ) ProtoReflect () protoreflect .Message {
return (*messageReflectWrapper )(m )
}
func (m *messageIfaceWrapper ) protoUnwrap () any {
return m .p .AsIfaceOf (m .mi .GoReflectType .Elem ())
}
func (mi *MessageInfo ) checkField (fd protoreflect .FieldDescriptor ) (*fieldInfo , protoreflect .ExtensionTypeDescriptor ) {
var fi *fieldInfo
if n := fd .Number (); 0 < n && int (n ) < len (mi .denseFields ) {
fi = mi .denseFields [n ]
} else {
fi = mi .fields [n ]
}
if fi != nil {
if fi .fieldDesc != fd {
if got , want := fd .FullName (), fi .fieldDesc .FullName (); got != want {
panic (fmt .Sprintf ("mismatching field: got %v, want %v" , got , want ))
}
panic (fmt .Sprintf ("mismatching field: %v" , fd .FullName ()))
}
return fi , nil
}
if fd .IsExtension () {
if got , want := fd .ContainingMessage ().FullName (), mi .Desc .FullName (); got != want {
panic (fmt .Sprintf ("extension %v has mismatching containing message: got %v, want %v" , fd .FullName (), got , want ))
}
if !mi .Desc .ExtensionRanges ().Has (fd .Number ()) {
panic (fmt .Sprintf ("extension %v extends %v outside the extension range" , fd .FullName (), mi .Desc .FullName ()))
}
xtd , ok := fd .(protoreflect .ExtensionTypeDescriptor )
if !ok {
panic (fmt .Sprintf ("extension %v does not implement protoreflect.ExtensionTypeDescriptor" , fd .FullName ()))
}
return nil , xtd
}
panic (fmt .Sprintf ("field %v is invalid" , fd .FullName ()))
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .