1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage impl 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "fmt" 9*1c12ee1eSDan Willemsen "reflect" 10*1c12ee1eSDan Willemsen 11*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/detrand" 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/pragma" 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 14*1c12ee1eSDan Willemsen) 15*1c12ee1eSDan Willemsen 16*1c12ee1eSDan Willemsentype reflectMessageInfo struct { 17*1c12ee1eSDan Willemsen fields map[protoreflect.FieldNumber]*fieldInfo 18*1c12ee1eSDan Willemsen oneofs map[protoreflect.Name]*oneofInfo 19*1c12ee1eSDan Willemsen 20*1c12ee1eSDan Willemsen // fieldTypes contains the zero value of an enum or message field. 21*1c12ee1eSDan Willemsen // For lists, it contains the element type. 22*1c12ee1eSDan Willemsen // For maps, it contains the entry value type. 23*1c12ee1eSDan Willemsen fieldTypes map[protoreflect.FieldNumber]interface{} 24*1c12ee1eSDan Willemsen 25*1c12ee1eSDan Willemsen // denseFields is a subset of fields where: 26*1c12ee1eSDan Willemsen // 0 < fieldDesc.Number() < len(denseFields) 27*1c12ee1eSDan Willemsen // It provides faster access to the fieldInfo, but may be incomplete. 28*1c12ee1eSDan Willemsen denseFields []*fieldInfo 29*1c12ee1eSDan Willemsen 30*1c12ee1eSDan Willemsen // rangeInfos is a list of all fields (not belonging to a oneof) and oneofs. 31*1c12ee1eSDan Willemsen rangeInfos []interface{} // either *fieldInfo or *oneofInfo 32*1c12ee1eSDan Willemsen 33*1c12ee1eSDan Willemsen getUnknown func(pointer) protoreflect.RawFields 34*1c12ee1eSDan Willemsen setUnknown func(pointer, protoreflect.RawFields) 35*1c12ee1eSDan Willemsen extensionMap func(pointer) *extensionMap 36*1c12ee1eSDan Willemsen 37*1c12ee1eSDan Willemsen nilMessage atomicNilMessage 38*1c12ee1eSDan Willemsen} 39*1c12ee1eSDan Willemsen 40*1c12ee1eSDan Willemsen// makeReflectFuncs generates the set of functions to support reflection. 41*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeReflectFuncs(t reflect.Type, si structInfo) { 42*1c12ee1eSDan Willemsen mi.makeKnownFieldsFunc(si) 43*1c12ee1eSDan Willemsen mi.makeUnknownFieldsFunc(t, si) 44*1c12ee1eSDan Willemsen mi.makeExtensionFieldsFunc(t, si) 45*1c12ee1eSDan Willemsen mi.makeFieldTypes(si) 46*1c12ee1eSDan Willemsen} 47*1c12ee1eSDan Willemsen 48*1c12ee1eSDan Willemsen// makeKnownFieldsFunc generates functions for operations that can be performed 49*1c12ee1eSDan Willemsen// on each protobuf message field. It takes in a reflect.Type representing the 50*1c12ee1eSDan Willemsen// Go struct and matches message fields with struct fields. 51*1c12ee1eSDan Willemsen// 52*1c12ee1eSDan Willemsen// This code assumes that the struct is well-formed and panics if there are 53*1c12ee1eSDan Willemsen// any discrepancies. 54*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) { 55*1c12ee1eSDan Willemsen mi.fields = map[protoreflect.FieldNumber]*fieldInfo{} 56*1c12ee1eSDan Willemsen md := mi.Desc 57*1c12ee1eSDan Willemsen fds := md.Fields() 58*1c12ee1eSDan Willemsen for i := 0; i < fds.Len(); i++ { 59*1c12ee1eSDan Willemsen fd := fds.Get(i) 60*1c12ee1eSDan Willemsen fs := si.fieldsByNumber[fd.Number()] 61*1c12ee1eSDan Willemsen isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic() 62*1c12ee1eSDan Willemsen if isOneof { 63*1c12ee1eSDan Willemsen fs = si.oneofsByName[fd.ContainingOneof().Name()] 64*1c12ee1eSDan Willemsen } 65*1c12ee1eSDan Willemsen var fi fieldInfo 66*1c12ee1eSDan Willemsen switch { 67*1c12ee1eSDan Willemsen case fs.Type == nil: 68*1c12ee1eSDan Willemsen fi = fieldInfoForMissing(fd) // never occurs for officially generated message types 69*1c12ee1eSDan Willemsen case isOneof: 70*1c12ee1eSDan Willemsen fi = fieldInfoForOneof(fd, fs, mi.Exporter, si.oneofWrappersByNumber[fd.Number()]) 71*1c12ee1eSDan Willemsen case fd.IsMap(): 72*1c12ee1eSDan Willemsen fi = fieldInfoForMap(fd, fs, mi.Exporter) 73*1c12ee1eSDan Willemsen case fd.IsList(): 74*1c12ee1eSDan Willemsen fi = fieldInfoForList(fd, fs, mi.Exporter) 75*1c12ee1eSDan Willemsen case fd.IsWeak(): 76*1c12ee1eSDan Willemsen fi = fieldInfoForWeakMessage(fd, si.weakOffset) 77*1c12ee1eSDan Willemsen case fd.Message() != nil: 78*1c12ee1eSDan Willemsen fi = fieldInfoForMessage(fd, fs, mi.Exporter) 79*1c12ee1eSDan Willemsen default: 80*1c12ee1eSDan Willemsen fi = fieldInfoForScalar(fd, fs, mi.Exporter) 81*1c12ee1eSDan Willemsen } 82*1c12ee1eSDan Willemsen mi.fields[fd.Number()] = &fi 83*1c12ee1eSDan Willemsen } 84*1c12ee1eSDan Willemsen 85*1c12ee1eSDan Willemsen mi.oneofs = map[protoreflect.Name]*oneofInfo{} 86*1c12ee1eSDan Willemsen for i := 0; i < md.Oneofs().Len(); i++ { 87*1c12ee1eSDan Willemsen od := md.Oneofs().Get(i) 88*1c12ee1eSDan Willemsen mi.oneofs[od.Name()] = makeOneofInfo(od, si, mi.Exporter) 89*1c12ee1eSDan Willemsen } 90*1c12ee1eSDan Willemsen 91*1c12ee1eSDan Willemsen mi.denseFields = make([]*fieldInfo, fds.Len()*2) 92*1c12ee1eSDan Willemsen for i := 0; i < fds.Len(); i++ { 93*1c12ee1eSDan Willemsen if fd := fds.Get(i); int(fd.Number()) < len(mi.denseFields) { 94*1c12ee1eSDan Willemsen mi.denseFields[fd.Number()] = mi.fields[fd.Number()] 95*1c12ee1eSDan Willemsen } 96*1c12ee1eSDan Willemsen } 97*1c12ee1eSDan Willemsen 98*1c12ee1eSDan Willemsen for i := 0; i < fds.Len(); { 99*1c12ee1eSDan Willemsen fd := fds.Get(i) 100*1c12ee1eSDan Willemsen if od := fd.ContainingOneof(); od != nil && !od.IsSynthetic() { 101*1c12ee1eSDan Willemsen mi.rangeInfos = append(mi.rangeInfos, mi.oneofs[od.Name()]) 102*1c12ee1eSDan Willemsen i += od.Fields().Len() 103*1c12ee1eSDan Willemsen } else { 104*1c12ee1eSDan Willemsen mi.rangeInfos = append(mi.rangeInfos, mi.fields[fd.Number()]) 105*1c12ee1eSDan Willemsen i++ 106*1c12ee1eSDan Willemsen } 107*1c12ee1eSDan Willemsen } 108*1c12ee1eSDan Willemsen 109*1c12ee1eSDan Willemsen // Introduce instability to iteration order, but keep it deterministic. 110*1c12ee1eSDan Willemsen if len(mi.rangeInfos) > 1 && detrand.Bool() { 111*1c12ee1eSDan Willemsen i := detrand.Intn(len(mi.rangeInfos) - 1) 112*1c12ee1eSDan Willemsen mi.rangeInfos[i], mi.rangeInfos[i+1] = mi.rangeInfos[i+1], mi.rangeInfos[i] 113*1c12ee1eSDan Willemsen } 114*1c12ee1eSDan Willemsen} 115*1c12ee1eSDan Willemsen 116*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeUnknownFieldsFunc(t reflect.Type, si structInfo) { 117*1c12ee1eSDan Willemsen switch { 118*1c12ee1eSDan Willemsen case si.unknownOffset.IsValid() && si.unknownType == unknownFieldsAType: 119*1c12ee1eSDan Willemsen // Handle as []byte. 120*1c12ee1eSDan Willemsen mi.getUnknown = func(p pointer) protoreflect.RawFields { 121*1c12ee1eSDan Willemsen if p.IsNil() { 122*1c12ee1eSDan Willemsen return nil 123*1c12ee1eSDan Willemsen } 124*1c12ee1eSDan Willemsen return *p.Apply(mi.unknownOffset).Bytes() 125*1c12ee1eSDan Willemsen } 126*1c12ee1eSDan Willemsen mi.setUnknown = func(p pointer, b protoreflect.RawFields) { 127*1c12ee1eSDan Willemsen if p.IsNil() { 128*1c12ee1eSDan Willemsen panic("invalid SetUnknown on nil Message") 129*1c12ee1eSDan Willemsen } 130*1c12ee1eSDan Willemsen *p.Apply(mi.unknownOffset).Bytes() = b 131*1c12ee1eSDan Willemsen } 132*1c12ee1eSDan Willemsen case si.unknownOffset.IsValid() && si.unknownType == unknownFieldsBType: 133*1c12ee1eSDan Willemsen // Handle as *[]byte. 134*1c12ee1eSDan Willemsen mi.getUnknown = func(p pointer) protoreflect.RawFields { 135*1c12ee1eSDan Willemsen if p.IsNil() { 136*1c12ee1eSDan Willemsen return nil 137*1c12ee1eSDan Willemsen } 138*1c12ee1eSDan Willemsen bp := p.Apply(mi.unknownOffset).BytesPtr() 139*1c12ee1eSDan Willemsen if *bp == nil { 140*1c12ee1eSDan Willemsen return nil 141*1c12ee1eSDan Willemsen } 142*1c12ee1eSDan Willemsen return **bp 143*1c12ee1eSDan Willemsen } 144*1c12ee1eSDan Willemsen mi.setUnknown = func(p pointer, b protoreflect.RawFields) { 145*1c12ee1eSDan Willemsen if p.IsNil() { 146*1c12ee1eSDan Willemsen panic("invalid SetUnknown on nil Message") 147*1c12ee1eSDan Willemsen } 148*1c12ee1eSDan Willemsen bp := p.Apply(mi.unknownOffset).BytesPtr() 149*1c12ee1eSDan Willemsen if *bp == nil { 150*1c12ee1eSDan Willemsen *bp = new([]byte) 151*1c12ee1eSDan Willemsen } 152*1c12ee1eSDan Willemsen **bp = b 153*1c12ee1eSDan Willemsen } 154*1c12ee1eSDan Willemsen default: 155*1c12ee1eSDan Willemsen mi.getUnknown = func(pointer) protoreflect.RawFields { 156*1c12ee1eSDan Willemsen return nil 157*1c12ee1eSDan Willemsen } 158*1c12ee1eSDan Willemsen mi.setUnknown = func(p pointer, _ protoreflect.RawFields) { 159*1c12ee1eSDan Willemsen if p.IsNil() { 160*1c12ee1eSDan Willemsen panic("invalid SetUnknown on nil Message") 161*1c12ee1eSDan Willemsen } 162*1c12ee1eSDan Willemsen } 163*1c12ee1eSDan Willemsen } 164*1c12ee1eSDan Willemsen} 165*1c12ee1eSDan Willemsen 166*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeExtensionFieldsFunc(t reflect.Type, si structInfo) { 167*1c12ee1eSDan Willemsen if si.extensionOffset.IsValid() { 168*1c12ee1eSDan Willemsen mi.extensionMap = func(p pointer) *extensionMap { 169*1c12ee1eSDan Willemsen if p.IsNil() { 170*1c12ee1eSDan Willemsen return (*extensionMap)(nil) 171*1c12ee1eSDan Willemsen } 172*1c12ee1eSDan Willemsen v := p.Apply(si.extensionOffset).AsValueOf(extensionFieldsType) 173*1c12ee1eSDan Willemsen return (*extensionMap)(v.Interface().(*map[int32]ExtensionField)) 174*1c12ee1eSDan Willemsen } 175*1c12ee1eSDan Willemsen } else { 176*1c12ee1eSDan Willemsen mi.extensionMap = func(pointer) *extensionMap { 177*1c12ee1eSDan Willemsen return (*extensionMap)(nil) 178*1c12ee1eSDan Willemsen } 179*1c12ee1eSDan Willemsen } 180*1c12ee1eSDan Willemsen} 181*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeFieldTypes(si structInfo) { 182*1c12ee1eSDan Willemsen md := mi.Desc 183*1c12ee1eSDan Willemsen fds := md.Fields() 184*1c12ee1eSDan Willemsen for i := 0; i < fds.Len(); i++ { 185*1c12ee1eSDan Willemsen var ft reflect.Type 186*1c12ee1eSDan Willemsen fd := fds.Get(i) 187*1c12ee1eSDan Willemsen fs := si.fieldsByNumber[fd.Number()] 188*1c12ee1eSDan Willemsen isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic() 189*1c12ee1eSDan Willemsen if isOneof { 190*1c12ee1eSDan Willemsen fs = si.oneofsByName[fd.ContainingOneof().Name()] 191*1c12ee1eSDan Willemsen } 192*1c12ee1eSDan Willemsen var isMessage bool 193*1c12ee1eSDan Willemsen switch { 194*1c12ee1eSDan Willemsen case fs.Type == nil: 195*1c12ee1eSDan Willemsen continue // never occurs for officially generated message types 196*1c12ee1eSDan Willemsen case isOneof: 197*1c12ee1eSDan Willemsen if fd.Enum() != nil || fd.Message() != nil { 198*1c12ee1eSDan Willemsen ft = si.oneofWrappersByNumber[fd.Number()].Field(0).Type 199*1c12ee1eSDan Willemsen } 200*1c12ee1eSDan Willemsen case fd.IsMap(): 201*1c12ee1eSDan Willemsen if fd.MapValue().Enum() != nil || fd.MapValue().Message() != nil { 202*1c12ee1eSDan Willemsen ft = fs.Type.Elem() 203*1c12ee1eSDan Willemsen } 204*1c12ee1eSDan Willemsen isMessage = fd.MapValue().Message() != nil 205*1c12ee1eSDan Willemsen case fd.IsList(): 206*1c12ee1eSDan Willemsen if fd.Enum() != nil || fd.Message() != nil { 207*1c12ee1eSDan Willemsen ft = fs.Type.Elem() 208*1c12ee1eSDan Willemsen } 209*1c12ee1eSDan Willemsen isMessage = fd.Message() != nil 210*1c12ee1eSDan Willemsen case fd.Enum() != nil: 211*1c12ee1eSDan Willemsen ft = fs.Type 212*1c12ee1eSDan Willemsen if fd.HasPresence() && ft.Kind() == reflect.Ptr { 213*1c12ee1eSDan Willemsen ft = ft.Elem() 214*1c12ee1eSDan Willemsen } 215*1c12ee1eSDan Willemsen case fd.Message() != nil: 216*1c12ee1eSDan Willemsen ft = fs.Type 217*1c12ee1eSDan Willemsen if fd.IsWeak() { 218*1c12ee1eSDan Willemsen ft = nil 219*1c12ee1eSDan Willemsen } 220*1c12ee1eSDan Willemsen isMessage = true 221*1c12ee1eSDan Willemsen } 222*1c12ee1eSDan Willemsen if isMessage && ft != nil && ft.Kind() != reflect.Ptr { 223*1c12ee1eSDan Willemsen ft = reflect.PtrTo(ft) // never occurs for officially generated message types 224*1c12ee1eSDan Willemsen } 225*1c12ee1eSDan Willemsen if ft != nil { 226*1c12ee1eSDan Willemsen if mi.fieldTypes == nil { 227*1c12ee1eSDan Willemsen mi.fieldTypes = make(map[protoreflect.FieldNumber]interface{}) 228*1c12ee1eSDan Willemsen } 229*1c12ee1eSDan Willemsen mi.fieldTypes[fd.Number()] = reflect.Zero(ft).Interface() 230*1c12ee1eSDan Willemsen } 231*1c12ee1eSDan Willemsen } 232*1c12ee1eSDan Willemsen} 233*1c12ee1eSDan Willemsen 234*1c12ee1eSDan Willemsentype extensionMap map[int32]ExtensionField 235*1c12ee1eSDan Willemsen 236*1c12ee1eSDan Willemsenfunc (m *extensionMap) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { 237*1c12ee1eSDan Willemsen if m != nil { 238*1c12ee1eSDan Willemsen for _, x := range *m { 239*1c12ee1eSDan Willemsen xd := x.Type().TypeDescriptor() 240*1c12ee1eSDan Willemsen v := x.Value() 241*1c12ee1eSDan Willemsen if xd.IsList() && v.List().Len() == 0 { 242*1c12ee1eSDan Willemsen continue 243*1c12ee1eSDan Willemsen } 244*1c12ee1eSDan Willemsen if !f(xd, v) { 245*1c12ee1eSDan Willemsen return 246*1c12ee1eSDan Willemsen } 247*1c12ee1eSDan Willemsen } 248*1c12ee1eSDan Willemsen } 249*1c12ee1eSDan Willemsen} 250*1c12ee1eSDan Willemsenfunc (m *extensionMap) Has(xt protoreflect.ExtensionType) (ok bool) { 251*1c12ee1eSDan Willemsen if m == nil { 252*1c12ee1eSDan Willemsen return false 253*1c12ee1eSDan Willemsen } 254*1c12ee1eSDan Willemsen xd := xt.TypeDescriptor() 255*1c12ee1eSDan Willemsen x, ok := (*m)[int32(xd.Number())] 256*1c12ee1eSDan Willemsen if !ok { 257*1c12ee1eSDan Willemsen return false 258*1c12ee1eSDan Willemsen } 259*1c12ee1eSDan Willemsen switch { 260*1c12ee1eSDan Willemsen case xd.IsList(): 261*1c12ee1eSDan Willemsen return x.Value().List().Len() > 0 262*1c12ee1eSDan Willemsen case xd.IsMap(): 263*1c12ee1eSDan Willemsen return x.Value().Map().Len() > 0 264*1c12ee1eSDan Willemsen case xd.Message() != nil: 265*1c12ee1eSDan Willemsen return x.Value().Message().IsValid() 266*1c12ee1eSDan Willemsen } 267*1c12ee1eSDan Willemsen return true 268*1c12ee1eSDan Willemsen} 269*1c12ee1eSDan Willemsenfunc (m *extensionMap) Clear(xt protoreflect.ExtensionType) { 270*1c12ee1eSDan Willemsen delete(*m, int32(xt.TypeDescriptor().Number())) 271*1c12ee1eSDan Willemsen} 272*1c12ee1eSDan Willemsenfunc (m *extensionMap) Get(xt protoreflect.ExtensionType) protoreflect.Value { 273*1c12ee1eSDan Willemsen xd := xt.TypeDescriptor() 274*1c12ee1eSDan Willemsen if m != nil { 275*1c12ee1eSDan Willemsen if x, ok := (*m)[int32(xd.Number())]; ok { 276*1c12ee1eSDan Willemsen return x.Value() 277*1c12ee1eSDan Willemsen } 278*1c12ee1eSDan Willemsen } 279*1c12ee1eSDan Willemsen return xt.Zero() 280*1c12ee1eSDan Willemsen} 281*1c12ee1eSDan Willemsenfunc (m *extensionMap) Set(xt protoreflect.ExtensionType, v protoreflect.Value) { 282*1c12ee1eSDan Willemsen xd := xt.TypeDescriptor() 283*1c12ee1eSDan Willemsen isValid := true 284*1c12ee1eSDan Willemsen switch { 285*1c12ee1eSDan Willemsen case !xt.IsValidValue(v): 286*1c12ee1eSDan Willemsen isValid = false 287*1c12ee1eSDan Willemsen case xd.IsList(): 288*1c12ee1eSDan Willemsen isValid = v.List().IsValid() 289*1c12ee1eSDan Willemsen case xd.IsMap(): 290*1c12ee1eSDan Willemsen isValid = v.Map().IsValid() 291*1c12ee1eSDan Willemsen case xd.Message() != nil: 292*1c12ee1eSDan Willemsen isValid = v.Message().IsValid() 293*1c12ee1eSDan Willemsen } 294*1c12ee1eSDan Willemsen if !isValid { 295*1c12ee1eSDan Willemsen panic(fmt.Sprintf("%v: assigning invalid value", xt.TypeDescriptor().FullName())) 296*1c12ee1eSDan Willemsen } 297*1c12ee1eSDan Willemsen 298*1c12ee1eSDan Willemsen if *m == nil { 299*1c12ee1eSDan Willemsen *m = make(map[int32]ExtensionField) 300*1c12ee1eSDan Willemsen } 301*1c12ee1eSDan Willemsen var x ExtensionField 302*1c12ee1eSDan Willemsen x.Set(xt, v) 303*1c12ee1eSDan Willemsen (*m)[int32(xd.Number())] = x 304*1c12ee1eSDan Willemsen} 305*1c12ee1eSDan Willemsenfunc (m *extensionMap) Mutable(xt protoreflect.ExtensionType) protoreflect.Value { 306*1c12ee1eSDan Willemsen xd := xt.TypeDescriptor() 307*1c12ee1eSDan Willemsen if xd.Kind() != protoreflect.MessageKind && xd.Kind() != protoreflect.GroupKind && !xd.IsList() && !xd.IsMap() { 308*1c12ee1eSDan Willemsen panic("invalid Mutable on field with non-composite type") 309*1c12ee1eSDan Willemsen } 310*1c12ee1eSDan Willemsen if x, ok := (*m)[int32(xd.Number())]; ok { 311*1c12ee1eSDan Willemsen return x.Value() 312*1c12ee1eSDan Willemsen } 313*1c12ee1eSDan Willemsen v := xt.New() 314*1c12ee1eSDan Willemsen m.Set(xt, v) 315*1c12ee1eSDan Willemsen return v 316*1c12ee1eSDan Willemsen} 317*1c12ee1eSDan Willemsen 318*1c12ee1eSDan Willemsen// MessageState is a data structure that is nested as the first field in a 319*1c12ee1eSDan Willemsen// concrete message. It provides a way to implement the ProtoReflect method 320*1c12ee1eSDan Willemsen// in an allocation-free way without needing to have a shadow Go type generated 321*1c12ee1eSDan Willemsen// for every message type. This technique only works using unsafe. 322*1c12ee1eSDan Willemsen// 323*1c12ee1eSDan Willemsen// Example generated code: 324*1c12ee1eSDan Willemsen// 325*1c12ee1eSDan Willemsen// type M struct { 326*1c12ee1eSDan Willemsen// state protoimpl.MessageState 327*1c12ee1eSDan Willemsen// 328*1c12ee1eSDan Willemsen// Field1 int32 329*1c12ee1eSDan Willemsen// Field2 string 330*1c12ee1eSDan Willemsen// Field3 *BarMessage 331*1c12ee1eSDan Willemsen// ... 332*1c12ee1eSDan Willemsen// } 333*1c12ee1eSDan Willemsen// 334*1c12ee1eSDan Willemsen// func (m *M) ProtoReflect() protoreflect.Message { 335*1c12ee1eSDan Willemsen// mi := &file_fizz_buzz_proto_msgInfos[5] 336*1c12ee1eSDan Willemsen// if protoimpl.UnsafeEnabled && m != nil { 337*1c12ee1eSDan Willemsen// ms := protoimpl.X.MessageStateOf(Pointer(m)) 338*1c12ee1eSDan Willemsen// if ms.LoadMessageInfo() == nil { 339*1c12ee1eSDan Willemsen// ms.StoreMessageInfo(mi) 340*1c12ee1eSDan Willemsen// } 341*1c12ee1eSDan Willemsen// return ms 342*1c12ee1eSDan Willemsen// } 343*1c12ee1eSDan Willemsen// return mi.MessageOf(m) 344*1c12ee1eSDan Willemsen// } 345*1c12ee1eSDan Willemsen// 346*1c12ee1eSDan Willemsen// The MessageState type holds a *MessageInfo, which must be atomically set to 347*1c12ee1eSDan Willemsen// the message info associated with a given message instance. 348*1c12ee1eSDan Willemsen// By unsafely converting a *M into a *MessageState, the MessageState object 349*1c12ee1eSDan Willemsen// has access to all the information needed to implement protobuf reflection. 350*1c12ee1eSDan Willemsen// It has access to the message info as its first field, and a pointer to the 351*1c12ee1eSDan Willemsen// MessageState is identical to a pointer to the concrete message value. 352*1c12ee1eSDan Willemsen// 353*1c12ee1eSDan Willemsen// Requirements: 354*1c12ee1eSDan Willemsen// - The type M must implement protoreflect.ProtoMessage. 355*1c12ee1eSDan Willemsen// - The address of m must not be nil. 356*1c12ee1eSDan Willemsen// - The address of m and the address of m.state must be equal, 357*1c12ee1eSDan Willemsen// even though they are different Go types. 358*1c12ee1eSDan Willemsentype MessageState struct { 359*1c12ee1eSDan Willemsen pragma.NoUnkeyedLiterals 360*1c12ee1eSDan Willemsen pragma.DoNotCompare 361*1c12ee1eSDan Willemsen pragma.DoNotCopy 362*1c12ee1eSDan Willemsen 363*1c12ee1eSDan Willemsen atomicMessageInfo *MessageInfo 364*1c12ee1eSDan Willemsen} 365*1c12ee1eSDan Willemsen 366*1c12ee1eSDan Willemsentype messageState MessageState 367*1c12ee1eSDan Willemsen 368*1c12ee1eSDan Willemsenvar ( 369*1c12ee1eSDan Willemsen _ protoreflect.Message = (*messageState)(nil) 370*1c12ee1eSDan Willemsen _ unwrapper = (*messageState)(nil) 371*1c12ee1eSDan Willemsen) 372*1c12ee1eSDan Willemsen 373*1c12ee1eSDan Willemsen// messageDataType is a tuple of a pointer to the message data and 374*1c12ee1eSDan Willemsen// a pointer to the message type. It is a generalized way of providing a 375*1c12ee1eSDan Willemsen// reflective view over a message instance. The disadvantage of this approach 376*1c12ee1eSDan Willemsen// is the need to allocate this tuple of 16B. 377*1c12ee1eSDan Willemsentype messageDataType struct { 378*1c12ee1eSDan Willemsen p pointer 379*1c12ee1eSDan Willemsen mi *MessageInfo 380*1c12ee1eSDan Willemsen} 381*1c12ee1eSDan Willemsen 382*1c12ee1eSDan Willemsentype ( 383*1c12ee1eSDan Willemsen messageReflectWrapper messageDataType 384*1c12ee1eSDan Willemsen messageIfaceWrapper messageDataType 385*1c12ee1eSDan Willemsen) 386*1c12ee1eSDan Willemsen 387*1c12ee1eSDan Willemsenvar ( 388*1c12ee1eSDan Willemsen _ protoreflect.Message = (*messageReflectWrapper)(nil) 389*1c12ee1eSDan Willemsen _ unwrapper = (*messageReflectWrapper)(nil) 390*1c12ee1eSDan Willemsen _ protoreflect.ProtoMessage = (*messageIfaceWrapper)(nil) 391*1c12ee1eSDan Willemsen _ unwrapper = (*messageIfaceWrapper)(nil) 392*1c12ee1eSDan Willemsen) 393*1c12ee1eSDan Willemsen 394*1c12ee1eSDan Willemsen// MessageOf returns a reflective view over a message. The input must be a 395*1c12ee1eSDan Willemsen// pointer to a named Go struct. If the provided type has a ProtoReflect method, 396*1c12ee1eSDan Willemsen// it must be implemented by calling this method. 397*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) MessageOf(m interface{}) protoreflect.Message { 398*1c12ee1eSDan Willemsen if reflect.TypeOf(m) != mi.GoReflectType { 399*1c12ee1eSDan Willemsen panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoReflectType)) 400*1c12ee1eSDan Willemsen } 401*1c12ee1eSDan Willemsen p := pointerOfIface(m) 402*1c12ee1eSDan Willemsen if p.IsNil() { 403*1c12ee1eSDan Willemsen return mi.nilMessage.Init(mi) 404*1c12ee1eSDan Willemsen } 405*1c12ee1eSDan Willemsen return &messageReflectWrapper{p, mi} 406*1c12ee1eSDan Willemsen} 407*1c12ee1eSDan Willemsen 408*1c12ee1eSDan Willemsenfunc (m *messageReflectWrapper) pointer() pointer { return m.p } 409*1c12ee1eSDan Willemsenfunc (m *messageReflectWrapper) messageInfo() *MessageInfo { return m.mi } 410*1c12ee1eSDan Willemsen 411*1c12ee1eSDan Willemsen// Reset implements the v1 proto.Message.Reset method. 412*1c12ee1eSDan Willemsenfunc (m *messageIfaceWrapper) Reset() { 413*1c12ee1eSDan Willemsen if mr, ok := m.protoUnwrap().(interface{ Reset() }); ok { 414*1c12ee1eSDan Willemsen mr.Reset() 415*1c12ee1eSDan Willemsen return 416*1c12ee1eSDan Willemsen } 417*1c12ee1eSDan Willemsen rv := reflect.ValueOf(m.protoUnwrap()) 418*1c12ee1eSDan Willemsen if rv.Kind() == reflect.Ptr && !rv.IsNil() { 419*1c12ee1eSDan Willemsen rv.Elem().Set(reflect.Zero(rv.Type().Elem())) 420*1c12ee1eSDan Willemsen } 421*1c12ee1eSDan Willemsen} 422*1c12ee1eSDan Willemsenfunc (m *messageIfaceWrapper) ProtoReflect() protoreflect.Message { 423*1c12ee1eSDan Willemsen return (*messageReflectWrapper)(m) 424*1c12ee1eSDan Willemsen} 425*1c12ee1eSDan Willemsenfunc (m *messageIfaceWrapper) protoUnwrap() interface{} { 426*1c12ee1eSDan Willemsen return m.p.AsIfaceOf(m.mi.GoReflectType.Elem()) 427*1c12ee1eSDan Willemsen} 428*1c12ee1eSDan Willemsen 429*1c12ee1eSDan Willemsen// checkField verifies that the provided field descriptor is valid. 430*1c12ee1eSDan Willemsen// Exactly one of the returned values is populated. 431*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) checkField(fd protoreflect.FieldDescriptor) (*fieldInfo, protoreflect.ExtensionType) { 432*1c12ee1eSDan Willemsen var fi *fieldInfo 433*1c12ee1eSDan Willemsen if n := fd.Number(); 0 < n && int(n) < len(mi.denseFields) { 434*1c12ee1eSDan Willemsen fi = mi.denseFields[n] 435*1c12ee1eSDan Willemsen } else { 436*1c12ee1eSDan Willemsen fi = mi.fields[n] 437*1c12ee1eSDan Willemsen } 438*1c12ee1eSDan Willemsen if fi != nil { 439*1c12ee1eSDan Willemsen if fi.fieldDesc != fd { 440*1c12ee1eSDan Willemsen if got, want := fd.FullName(), fi.fieldDesc.FullName(); got != want { 441*1c12ee1eSDan Willemsen panic(fmt.Sprintf("mismatching field: got %v, want %v", got, want)) 442*1c12ee1eSDan Willemsen } 443*1c12ee1eSDan Willemsen panic(fmt.Sprintf("mismatching field: %v", fd.FullName())) 444*1c12ee1eSDan Willemsen } 445*1c12ee1eSDan Willemsen return fi, nil 446*1c12ee1eSDan Willemsen } 447*1c12ee1eSDan Willemsen 448*1c12ee1eSDan Willemsen if fd.IsExtension() { 449*1c12ee1eSDan Willemsen if got, want := fd.ContainingMessage().FullName(), mi.Desc.FullName(); got != want { 450*1c12ee1eSDan Willemsen // TODO: Should this be exact containing message descriptor match? 451*1c12ee1eSDan Willemsen panic(fmt.Sprintf("extension %v has mismatching containing message: got %v, want %v", fd.FullName(), got, want)) 452*1c12ee1eSDan Willemsen } 453*1c12ee1eSDan Willemsen if !mi.Desc.ExtensionRanges().Has(fd.Number()) { 454*1c12ee1eSDan Willemsen panic(fmt.Sprintf("extension %v extends %v outside the extension range", fd.FullName(), mi.Desc.FullName())) 455*1c12ee1eSDan Willemsen } 456*1c12ee1eSDan Willemsen xtd, ok := fd.(protoreflect.ExtensionTypeDescriptor) 457*1c12ee1eSDan Willemsen if !ok { 458*1c12ee1eSDan Willemsen panic(fmt.Sprintf("extension %v does not implement protoreflect.ExtensionTypeDescriptor", fd.FullName())) 459*1c12ee1eSDan Willemsen } 460*1c12ee1eSDan Willemsen return nil, xtd.Type() 461*1c12ee1eSDan Willemsen } 462*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v is invalid", fd.FullName())) 463*1c12ee1eSDan Willemsen} 464