1*1c12ee1eSDan Willemsen// Copyright 2018 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 "math" 10*1c12ee1eSDan Willemsen "reflect" 11*1c12ee1eSDan Willemsen "sync" 12*1c12ee1eSDan Willemsen 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/flags" 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 15*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoregistry" 16*1c12ee1eSDan Willemsen) 17*1c12ee1eSDan Willemsen 18*1c12ee1eSDan Willemsentype fieldInfo struct { 19*1c12ee1eSDan Willemsen fieldDesc protoreflect.FieldDescriptor 20*1c12ee1eSDan Willemsen 21*1c12ee1eSDan Willemsen // These fields are used for protobuf reflection support. 22*1c12ee1eSDan Willemsen has func(pointer) bool 23*1c12ee1eSDan Willemsen clear func(pointer) 24*1c12ee1eSDan Willemsen get func(pointer) protoreflect.Value 25*1c12ee1eSDan Willemsen set func(pointer, protoreflect.Value) 26*1c12ee1eSDan Willemsen mutable func(pointer) protoreflect.Value 27*1c12ee1eSDan Willemsen newMessage func() protoreflect.Message 28*1c12ee1eSDan Willemsen newField func() protoreflect.Value 29*1c12ee1eSDan Willemsen} 30*1c12ee1eSDan Willemsen 31*1c12ee1eSDan Willemsenfunc fieldInfoForMissing(fd protoreflect.FieldDescriptor) fieldInfo { 32*1c12ee1eSDan Willemsen // This never occurs for generated message types. 33*1c12ee1eSDan Willemsen // It implies that a hand-crafted type has missing Go fields 34*1c12ee1eSDan Willemsen // for specific protobuf message fields. 35*1c12ee1eSDan Willemsen return fieldInfo{ 36*1c12ee1eSDan Willemsen fieldDesc: fd, 37*1c12ee1eSDan Willemsen has: func(p pointer) bool { 38*1c12ee1eSDan Willemsen return false 39*1c12ee1eSDan Willemsen }, 40*1c12ee1eSDan Willemsen clear: func(p pointer) { 41*1c12ee1eSDan Willemsen panic("missing Go struct field for " + string(fd.FullName())) 42*1c12ee1eSDan Willemsen }, 43*1c12ee1eSDan Willemsen get: func(p pointer) protoreflect.Value { 44*1c12ee1eSDan Willemsen return fd.Default() 45*1c12ee1eSDan Willemsen }, 46*1c12ee1eSDan Willemsen set: func(p pointer, v protoreflect.Value) { 47*1c12ee1eSDan Willemsen panic("missing Go struct field for " + string(fd.FullName())) 48*1c12ee1eSDan Willemsen }, 49*1c12ee1eSDan Willemsen mutable: func(p pointer) protoreflect.Value { 50*1c12ee1eSDan Willemsen panic("missing Go struct field for " + string(fd.FullName())) 51*1c12ee1eSDan Willemsen }, 52*1c12ee1eSDan Willemsen newMessage: func() protoreflect.Message { 53*1c12ee1eSDan Willemsen panic("missing Go struct field for " + string(fd.FullName())) 54*1c12ee1eSDan Willemsen }, 55*1c12ee1eSDan Willemsen newField: func() protoreflect.Value { 56*1c12ee1eSDan Willemsen if v := fd.Default(); v.IsValid() { 57*1c12ee1eSDan Willemsen return v 58*1c12ee1eSDan Willemsen } 59*1c12ee1eSDan Willemsen panic("missing Go struct field for " + string(fd.FullName())) 60*1c12ee1eSDan Willemsen }, 61*1c12ee1eSDan Willemsen } 62*1c12ee1eSDan Willemsen} 63*1c12ee1eSDan Willemsen 64*1c12ee1eSDan Willemsenfunc fieldInfoForOneof(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter, ot reflect.Type) fieldInfo { 65*1c12ee1eSDan Willemsen ft := fs.Type 66*1c12ee1eSDan Willemsen if ft.Kind() != reflect.Interface { 67*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has invalid type: got %v, want interface kind", fd.FullName(), ft)) 68*1c12ee1eSDan Willemsen } 69*1c12ee1eSDan Willemsen if ot.Kind() != reflect.Struct { 70*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has invalid type: got %v, want struct kind", fd.FullName(), ot)) 71*1c12ee1eSDan Willemsen } 72*1c12ee1eSDan Willemsen if !reflect.PtrTo(ot).Implements(ft) { 73*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has invalid type: %v does not implement %v", fd.FullName(), ot, ft)) 74*1c12ee1eSDan Willemsen } 75*1c12ee1eSDan Willemsen conv := NewConverter(ot.Field(0).Type, fd) 76*1c12ee1eSDan Willemsen isMessage := fd.Message() != nil 77*1c12ee1eSDan Willemsen 78*1c12ee1eSDan Willemsen // TODO: Implement unsafe fast path? 79*1c12ee1eSDan Willemsen fieldOffset := offsetOf(fs, x) 80*1c12ee1eSDan Willemsen return fieldInfo{ 81*1c12ee1eSDan Willemsen // NOTE: The logic below intentionally assumes that oneof fields are 82*1c12ee1eSDan Willemsen // well-formatted. That is, the oneof interface never contains a 83*1c12ee1eSDan Willemsen // typed nil pointer to one of the wrapper structs. 84*1c12ee1eSDan Willemsen 85*1c12ee1eSDan Willemsen fieldDesc: fd, 86*1c12ee1eSDan Willemsen has: func(p pointer) bool { 87*1c12ee1eSDan Willemsen if p.IsNil() { 88*1c12ee1eSDan Willemsen return false 89*1c12ee1eSDan Willemsen } 90*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 91*1c12ee1eSDan Willemsen if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() { 92*1c12ee1eSDan Willemsen return false 93*1c12ee1eSDan Willemsen } 94*1c12ee1eSDan Willemsen return true 95*1c12ee1eSDan Willemsen }, 96*1c12ee1eSDan Willemsen clear: func(p pointer) { 97*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 98*1c12ee1eSDan Willemsen if rv.IsNil() || rv.Elem().Type().Elem() != ot { 99*1c12ee1eSDan Willemsen // NOTE: We intentionally don't check for rv.Elem().IsNil() 100*1c12ee1eSDan Willemsen // so that (*OneofWrapperType)(nil) gets cleared to nil. 101*1c12ee1eSDan Willemsen return 102*1c12ee1eSDan Willemsen } 103*1c12ee1eSDan Willemsen rv.Set(reflect.Zero(rv.Type())) 104*1c12ee1eSDan Willemsen }, 105*1c12ee1eSDan Willemsen get: func(p pointer) protoreflect.Value { 106*1c12ee1eSDan Willemsen if p.IsNil() { 107*1c12ee1eSDan Willemsen return conv.Zero() 108*1c12ee1eSDan Willemsen } 109*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 110*1c12ee1eSDan Willemsen if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() { 111*1c12ee1eSDan Willemsen return conv.Zero() 112*1c12ee1eSDan Willemsen } 113*1c12ee1eSDan Willemsen rv = rv.Elem().Elem().Field(0) 114*1c12ee1eSDan Willemsen return conv.PBValueOf(rv) 115*1c12ee1eSDan Willemsen }, 116*1c12ee1eSDan Willemsen set: func(p pointer, v protoreflect.Value) { 117*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 118*1c12ee1eSDan Willemsen if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() { 119*1c12ee1eSDan Willemsen rv.Set(reflect.New(ot)) 120*1c12ee1eSDan Willemsen } 121*1c12ee1eSDan Willemsen rv = rv.Elem().Elem().Field(0) 122*1c12ee1eSDan Willemsen rv.Set(conv.GoValueOf(v)) 123*1c12ee1eSDan Willemsen }, 124*1c12ee1eSDan Willemsen mutable: func(p pointer) protoreflect.Value { 125*1c12ee1eSDan Willemsen if !isMessage { 126*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v with invalid Mutable call on field with non-composite type", fd.FullName())) 127*1c12ee1eSDan Willemsen } 128*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 129*1c12ee1eSDan Willemsen if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() { 130*1c12ee1eSDan Willemsen rv.Set(reflect.New(ot)) 131*1c12ee1eSDan Willemsen } 132*1c12ee1eSDan Willemsen rv = rv.Elem().Elem().Field(0) 133*1c12ee1eSDan Willemsen if rv.Kind() == reflect.Ptr && rv.IsNil() { 134*1c12ee1eSDan Willemsen rv.Set(conv.GoValueOf(protoreflect.ValueOfMessage(conv.New().Message()))) 135*1c12ee1eSDan Willemsen } 136*1c12ee1eSDan Willemsen return conv.PBValueOf(rv) 137*1c12ee1eSDan Willemsen }, 138*1c12ee1eSDan Willemsen newMessage: func() protoreflect.Message { 139*1c12ee1eSDan Willemsen return conv.New().Message() 140*1c12ee1eSDan Willemsen }, 141*1c12ee1eSDan Willemsen newField: func() protoreflect.Value { 142*1c12ee1eSDan Willemsen return conv.New() 143*1c12ee1eSDan Willemsen }, 144*1c12ee1eSDan Willemsen } 145*1c12ee1eSDan Willemsen} 146*1c12ee1eSDan Willemsen 147*1c12ee1eSDan Willemsenfunc fieldInfoForMap(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo { 148*1c12ee1eSDan Willemsen ft := fs.Type 149*1c12ee1eSDan Willemsen if ft.Kind() != reflect.Map { 150*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has invalid type: got %v, want map kind", fd.FullName(), ft)) 151*1c12ee1eSDan Willemsen } 152*1c12ee1eSDan Willemsen conv := NewConverter(ft, fd) 153*1c12ee1eSDan Willemsen 154*1c12ee1eSDan Willemsen // TODO: Implement unsafe fast path? 155*1c12ee1eSDan Willemsen fieldOffset := offsetOf(fs, x) 156*1c12ee1eSDan Willemsen return fieldInfo{ 157*1c12ee1eSDan Willemsen fieldDesc: fd, 158*1c12ee1eSDan Willemsen has: func(p pointer) bool { 159*1c12ee1eSDan Willemsen if p.IsNil() { 160*1c12ee1eSDan Willemsen return false 161*1c12ee1eSDan Willemsen } 162*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 163*1c12ee1eSDan Willemsen return rv.Len() > 0 164*1c12ee1eSDan Willemsen }, 165*1c12ee1eSDan Willemsen clear: func(p pointer) { 166*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 167*1c12ee1eSDan Willemsen rv.Set(reflect.Zero(rv.Type())) 168*1c12ee1eSDan Willemsen }, 169*1c12ee1eSDan Willemsen get: func(p pointer) protoreflect.Value { 170*1c12ee1eSDan Willemsen if p.IsNil() { 171*1c12ee1eSDan Willemsen return conv.Zero() 172*1c12ee1eSDan Willemsen } 173*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 174*1c12ee1eSDan Willemsen if rv.Len() == 0 { 175*1c12ee1eSDan Willemsen return conv.Zero() 176*1c12ee1eSDan Willemsen } 177*1c12ee1eSDan Willemsen return conv.PBValueOf(rv) 178*1c12ee1eSDan Willemsen }, 179*1c12ee1eSDan Willemsen set: func(p pointer, v protoreflect.Value) { 180*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 181*1c12ee1eSDan Willemsen pv := conv.GoValueOf(v) 182*1c12ee1eSDan Willemsen if pv.IsNil() { 183*1c12ee1eSDan Willemsen panic(fmt.Sprintf("map field %v cannot be set with read-only value", fd.FullName())) 184*1c12ee1eSDan Willemsen } 185*1c12ee1eSDan Willemsen rv.Set(pv) 186*1c12ee1eSDan Willemsen }, 187*1c12ee1eSDan Willemsen mutable: func(p pointer) protoreflect.Value { 188*1c12ee1eSDan Willemsen v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 189*1c12ee1eSDan Willemsen if v.IsNil() { 190*1c12ee1eSDan Willemsen v.Set(reflect.MakeMap(fs.Type)) 191*1c12ee1eSDan Willemsen } 192*1c12ee1eSDan Willemsen return conv.PBValueOf(v) 193*1c12ee1eSDan Willemsen }, 194*1c12ee1eSDan Willemsen newField: func() protoreflect.Value { 195*1c12ee1eSDan Willemsen return conv.New() 196*1c12ee1eSDan Willemsen }, 197*1c12ee1eSDan Willemsen } 198*1c12ee1eSDan Willemsen} 199*1c12ee1eSDan Willemsen 200*1c12ee1eSDan Willemsenfunc fieldInfoForList(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo { 201*1c12ee1eSDan Willemsen ft := fs.Type 202*1c12ee1eSDan Willemsen if ft.Kind() != reflect.Slice { 203*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has invalid type: got %v, want slice kind", fd.FullName(), ft)) 204*1c12ee1eSDan Willemsen } 205*1c12ee1eSDan Willemsen conv := NewConverter(reflect.PtrTo(ft), fd) 206*1c12ee1eSDan Willemsen 207*1c12ee1eSDan Willemsen // TODO: Implement unsafe fast path? 208*1c12ee1eSDan Willemsen fieldOffset := offsetOf(fs, x) 209*1c12ee1eSDan Willemsen return fieldInfo{ 210*1c12ee1eSDan Willemsen fieldDesc: fd, 211*1c12ee1eSDan Willemsen has: func(p pointer) bool { 212*1c12ee1eSDan Willemsen if p.IsNil() { 213*1c12ee1eSDan Willemsen return false 214*1c12ee1eSDan Willemsen } 215*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 216*1c12ee1eSDan Willemsen return rv.Len() > 0 217*1c12ee1eSDan Willemsen }, 218*1c12ee1eSDan Willemsen clear: func(p pointer) { 219*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 220*1c12ee1eSDan Willemsen rv.Set(reflect.Zero(rv.Type())) 221*1c12ee1eSDan Willemsen }, 222*1c12ee1eSDan Willemsen get: func(p pointer) protoreflect.Value { 223*1c12ee1eSDan Willemsen if p.IsNil() { 224*1c12ee1eSDan Willemsen return conv.Zero() 225*1c12ee1eSDan Willemsen } 226*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type) 227*1c12ee1eSDan Willemsen if rv.Elem().Len() == 0 { 228*1c12ee1eSDan Willemsen return conv.Zero() 229*1c12ee1eSDan Willemsen } 230*1c12ee1eSDan Willemsen return conv.PBValueOf(rv) 231*1c12ee1eSDan Willemsen }, 232*1c12ee1eSDan Willemsen set: func(p pointer, v protoreflect.Value) { 233*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 234*1c12ee1eSDan Willemsen pv := conv.GoValueOf(v) 235*1c12ee1eSDan Willemsen if pv.IsNil() { 236*1c12ee1eSDan Willemsen panic(fmt.Sprintf("list field %v cannot be set with read-only value", fd.FullName())) 237*1c12ee1eSDan Willemsen } 238*1c12ee1eSDan Willemsen rv.Set(pv.Elem()) 239*1c12ee1eSDan Willemsen }, 240*1c12ee1eSDan Willemsen mutable: func(p pointer) protoreflect.Value { 241*1c12ee1eSDan Willemsen v := p.Apply(fieldOffset).AsValueOf(fs.Type) 242*1c12ee1eSDan Willemsen return conv.PBValueOf(v) 243*1c12ee1eSDan Willemsen }, 244*1c12ee1eSDan Willemsen newField: func() protoreflect.Value { 245*1c12ee1eSDan Willemsen return conv.New() 246*1c12ee1eSDan Willemsen }, 247*1c12ee1eSDan Willemsen } 248*1c12ee1eSDan Willemsen} 249*1c12ee1eSDan Willemsen 250*1c12ee1eSDan Willemsenvar ( 251*1c12ee1eSDan Willemsen nilBytes = reflect.ValueOf([]byte(nil)) 252*1c12ee1eSDan Willemsen emptyBytes = reflect.ValueOf([]byte{}) 253*1c12ee1eSDan Willemsen) 254*1c12ee1eSDan Willemsen 255*1c12ee1eSDan Willemsenfunc fieldInfoForScalar(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo { 256*1c12ee1eSDan Willemsen ft := fs.Type 257*1c12ee1eSDan Willemsen nullable := fd.HasPresence() 258*1c12ee1eSDan Willemsen isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 259*1c12ee1eSDan Willemsen if nullable { 260*1c12ee1eSDan Willemsen if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice { 261*1c12ee1eSDan Willemsen // This never occurs for generated message types. 262*1c12ee1eSDan Willemsen // Despite the protobuf type system specifying presence, 263*1c12ee1eSDan Willemsen // the Go field type cannot represent it. 264*1c12ee1eSDan Willemsen nullable = false 265*1c12ee1eSDan Willemsen } 266*1c12ee1eSDan Willemsen if ft.Kind() == reflect.Ptr { 267*1c12ee1eSDan Willemsen ft = ft.Elem() 268*1c12ee1eSDan Willemsen } 269*1c12ee1eSDan Willemsen } 270*1c12ee1eSDan Willemsen conv := NewConverter(ft, fd) 271*1c12ee1eSDan Willemsen 272*1c12ee1eSDan Willemsen // TODO: Implement unsafe fast path? 273*1c12ee1eSDan Willemsen fieldOffset := offsetOf(fs, x) 274*1c12ee1eSDan Willemsen return fieldInfo{ 275*1c12ee1eSDan Willemsen fieldDesc: fd, 276*1c12ee1eSDan Willemsen has: func(p pointer) bool { 277*1c12ee1eSDan Willemsen if p.IsNil() { 278*1c12ee1eSDan Willemsen return false 279*1c12ee1eSDan Willemsen } 280*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 281*1c12ee1eSDan Willemsen if nullable { 282*1c12ee1eSDan Willemsen return !rv.IsNil() 283*1c12ee1eSDan Willemsen } 284*1c12ee1eSDan Willemsen switch rv.Kind() { 285*1c12ee1eSDan Willemsen case reflect.Bool: 286*1c12ee1eSDan Willemsen return rv.Bool() 287*1c12ee1eSDan Willemsen case reflect.Int32, reflect.Int64: 288*1c12ee1eSDan Willemsen return rv.Int() != 0 289*1c12ee1eSDan Willemsen case reflect.Uint32, reflect.Uint64: 290*1c12ee1eSDan Willemsen return rv.Uint() != 0 291*1c12ee1eSDan Willemsen case reflect.Float32, reflect.Float64: 292*1c12ee1eSDan Willemsen return rv.Float() != 0 || math.Signbit(rv.Float()) 293*1c12ee1eSDan Willemsen case reflect.String, reflect.Slice: 294*1c12ee1eSDan Willemsen return rv.Len() > 0 295*1c12ee1eSDan Willemsen default: 296*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has invalid type: %v", fd.FullName(), rv.Type())) // should never happen 297*1c12ee1eSDan Willemsen } 298*1c12ee1eSDan Willemsen }, 299*1c12ee1eSDan Willemsen clear: func(p pointer) { 300*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 301*1c12ee1eSDan Willemsen rv.Set(reflect.Zero(rv.Type())) 302*1c12ee1eSDan Willemsen }, 303*1c12ee1eSDan Willemsen get: func(p pointer) protoreflect.Value { 304*1c12ee1eSDan Willemsen if p.IsNil() { 305*1c12ee1eSDan Willemsen return conv.Zero() 306*1c12ee1eSDan Willemsen } 307*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 308*1c12ee1eSDan Willemsen if nullable { 309*1c12ee1eSDan Willemsen if rv.IsNil() { 310*1c12ee1eSDan Willemsen return conv.Zero() 311*1c12ee1eSDan Willemsen } 312*1c12ee1eSDan Willemsen if rv.Kind() == reflect.Ptr { 313*1c12ee1eSDan Willemsen rv = rv.Elem() 314*1c12ee1eSDan Willemsen } 315*1c12ee1eSDan Willemsen } 316*1c12ee1eSDan Willemsen return conv.PBValueOf(rv) 317*1c12ee1eSDan Willemsen }, 318*1c12ee1eSDan Willemsen set: func(p pointer, v protoreflect.Value) { 319*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 320*1c12ee1eSDan Willemsen if nullable && rv.Kind() == reflect.Ptr { 321*1c12ee1eSDan Willemsen if rv.IsNil() { 322*1c12ee1eSDan Willemsen rv.Set(reflect.New(ft)) 323*1c12ee1eSDan Willemsen } 324*1c12ee1eSDan Willemsen rv = rv.Elem() 325*1c12ee1eSDan Willemsen } 326*1c12ee1eSDan Willemsen rv.Set(conv.GoValueOf(v)) 327*1c12ee1eSDan Willemsen if isBytes && rv.Len() == 0 { 328*1c12ee1eSDan Willemsen if nullable { 329*1c12ee1eSDan Willemsen rv.Set(emptyBytes) // preserve presence 330*1c12ee1eSDan Willemsen } else { 331*1c12ee1eSDan Willemsen rv.Set(nilBytes) // do not preserve presence 332*1c12ee1eSDan Willemsen } 333*1c12ee1eSDan Willemsen } 334*1c12ee1eSDan Willemsen }, 335*1c12ee1eSDan Willemsen newField: func() protoreflect.Value { 336*1c12ee1eSDan Willemsen return conv.New() 337*1c12ee1eSDan Willemsen }, 338*1c12ee1eSDan Willemsen } 339*1c12ee1eSDan Willemsen} 340*1c12ee1eSDan Willemsen 341*1c12ee1eSDan Willemsenfunc fieldInfoForWeakMessage(fd protoreflect.FieldDescriptor, weakOffset offset) fieldInfo { 342*1c12ee1eSDan Willemsen if !flags.ProtoLegacy { 343*1c12ee1eSDan Willemsen panic("no support for proto1 weak fields") 344*1c12ee1eSDan Willemsen } 345*1c12ee1eSDan Willemsen 346*1c12ee1eSDan Willemsen var once sync.Once 347*1c12ee1eSDan Willemsen var messageType protoreflect.MessageType 348*1c12ee1eSDan Willemsen lazyInit := func() { 349*1c12ee1eSDan Willemsen once.Do(func() { 350*1c12ee1eSDan Willemsen messageName := fd.Message().FullName() 351*1c12ee1eSDan Willemsen messageType, _ = protoregistry.GlobalTypes.FindMessageByName(messageName) 352*1c12ee1eSDan Willemsen if messageType == nil { 353*1c12ee1eSDan Willemsen panic(fmt.Sprintf("weak message %v for field %v is not linked in", messageName, fd.FullName())) 354*1c12ee1eSDan Willemsen } 355*1c12ee1eSDan Willemsen }) 356*1c12ee1eSDan Willemsen } 357*1c12ee1eSDan Willemsen 358*1c12ee1eSDan Willemsen num := fd.Number() 359*1c12ee1eSDan Willemsen return fieldInfo{ 360*1c12ee1eSDan Willemsen fieldDesc: fd, 361*1c12ee1eSDan Willemsen has: func(p pointer) bool { 362*1c12ee1eSDan Willemsen if p.IsNil() { 363*1c12ee1eSDan Willemsen return false 364*1c12ee1eSDan Willemsen } 365*1c12ee1eSDan Willemsen _, ok := p.Apply(weakOffset).WeakFields().get(num) 366*1c12ee1eSDan Willemsen return ok 367*1c12ee1eSDan Willemsen }, 368*1c12ee1eSDan Willemsen clear: func(p pointer) { 369*1c12ee1eSDan Willemsen p.Apply(weakOffset).WeakFields().clear(num) 370*1c12ee1eSDan Willemsen }, 371*1c12ee1eSDan Willemsen get: func(p pointer) protoreflect.Value { 372*1c12ee1eSDan Willemsen lazyInit() 373*1c12ee1eSDan Willemsen if p.IsNil() { 374*1c12ee1eSDan Willemsen return protoreflect.ValueOfMessage(messageType.Zero()) 375*1c12ee1eSDan Willemsen } 376*1c12ee1eSDan Willemsen m, ok := p.Apply(weakOffset).WeakFields().get(num) 377*1c12ee1eSDan Willemsen if !ok { 378*1c12ee1eSDan Willemsen return protoreflect.ValueOfMessage(messageType.Zero()) 379*1c12ee1eSDan Willemsen } 380*1c12ee1eSDan Willemsen return protoreflect.ValueOfMessage(m.ProtoReflect()) 381*1c12ee1eSDan Willemsen }, 382*1c12ee1eSDan Willemsen set: func(p pointer, v protoreflect.Value) { 383*1c12ee1eSDan Willemsen lazyInit() 384*1c12ee1eSDan Willemsen m := v.Message() 385*1c12ee1eSDan Willemsen if m.Descriptor() != messageType.Descriptor() { 386*1c12ee1eSDan Willemsen if got, want := m.Descriptor().FullName(), messageType.Descriptor().FullName(); got != want { 387*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has mismatching message descriptor: got %v, want %v", fd.FullName(), got, want)) 388*1c12ee1eSDan Willemsen } 389*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has mismatching message descriptor: %v", fd.FullName(), m.Descriptor().FullName())) 390*1c12ee1eSDan Willemsen } 391*1c12ee1eSDan Willemsen p.Apply(weakOffset).WeakFields().set(num, m.Interface()) 392*1c12ee1eSDan Willemsen }, 393*1c12ee1eSDan Willemsen mutable: func(p pointer) protoreflect.Value { 394*1c12ee1eSDan Willemsen lazyInit() 395*1c12ee1eSDan Willemsen fs := p.Apply(weakOffset).WeakFields() 396*1c12ee1eSDan Willemsen m, ok := fs.get(num) 397*1c12ee1eSDan Willemsen if !ok { 398*1c12ee1eSDan Willemsen m = messageType.New().Interface() 399*1c12ee1eSDan Willemsen fs.set(num, m) 400*1c12ee1eSDan Willemsen } 401*1c12ee1eSDan Willemsen return protoreflect.ValueOfMessage(m.ProtoReflect()) 402*1c12ee1eSDan Willemsen }, 403*1c12ee1eSDan Willemsen newMessage: func() protoreflect.Message { 404*1c12ee1eSDan Willemsen lazyInit() 405*1c12ee1eSDan Willemsen return messageType.New() 406*1c12ee1eSDan Willemsen }, 407*1c12ee1eSDan Willemsen newField: func() protoreflect.Value { 408*1c12ee1eSDan Willemsen lazyInit() 409*1c12ee1eSDan Willemsen return protoreflect.ValueOfMessage(messageType.New()) 410*1c12ee1eSDan Willemsen }, 411*1c12ee1eSDan Willemsen } 412*1c12ee1eSDan Willemsen} 413*1c12ee1eSDan Willemsen 414*1c12ee1eSDan Willemsenfunc fieldInfoForMessage(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo { 415*1c12ee1eSDan Willemsen ft := fs.Type 416*1c12ee1eSDan Willemsen conv := NewConverter(ft, fd) 417*1c12ee1eSDan Willemsen 418*1c12ee1eSDan Willemsen // TODO: Implement unsafe fast path? 419*1c12ee1eSDan Willemsen fieldOffset := offsetOf(fs, x) 420*1c12ee1eSDan Willemsen return fieldInfo{ 421*1c12ee1eSDan Willemsen fieldDesc: fd, 422*1c12ee1eSDan Willemsen has: func(p pointer) bool { 423*1c12ee1eSDan Willemsen if p.IsNil() { 424*1c12ee1eSDan Willemsen return false 425*1c12ee1eSDan Willemsen } 426*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 427*1c12ee1eSDan Willemsen if fs.Type.Kind() != reflect.Ptr { 428*1c12ee1eSDan Willemsen return !isZero(rv) 429*1c12ee1eSDan Willemsen } 430*1c12ee1eSDan Willemsen return !rv.IsNil() 431*1c12ee1eSDan Willemsen }, 432*1c12ee1eSDan Willemsen clear: func(p pointer) { 433*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 434*1c12ee1eSDan Willemsen rv.Set(reflect.Zero(rv.Type())) 435*1c12ee1eSDan Willemsen }, 436*1c12ee1eSDan Willemsen get: func(p pointer) protoreflect.Value { 437*1c12ee1eSDan Willemsen if p.IsNil() { 438*1c12ee1eSDan Willemsen return conv.Zero() 439*1c12ee1eSDan Willemsen } 440*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 441*1c12ee1eSDan Willemsen return conv.PBValueOf(rv) 442*1c12ee1eSDan Willemsen }, 443*1c12ee1eSDan Willemsen set: func(p pointer, v protoreflect.Value) { 444*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 445*1c12ee1eSDan Willemsen rv.Set(conv.GoValueOf(v)) 446*1c12ee1eSDan Willemsen if fs.Type.Kind() == reflect.Ptr && rv.IsNil() { 447*1c12ee1eSDan Willemsen panic(fmt.Sprintf("field %v has invalid nil pointer", fd.FullName())) 448*1c12ee1eSDan Willemsen } 449*1c12ee1eSDan Willemsen }, 450*1c12ee1eSDan Willemsen mutable: func(p pointer) protoreflect.Value { 451*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 452*1c12ee1eSDan Willemsen if fs.Type.Kind() == reflect.Ptr && rv.IsNil() { 453*1c12ee1eSDan Willemsen rv.Set(conv.GoValueOf(conv.New())) 454*1c12ee1eSDan Willemsen } 455*1c12ee1eSDan Willemsen return conv.PBValueOf(rv) 456*1c12ee1eSDan Willemsen }, 457*1c12ee1eSDan Willemsen newMessage: func() protoreflect.Message { 458*1c12ee1eSDan Willemsen return conv.New().Message() 459*1c12ee1eSDan Willemsen }, 460*1c12ee1eSDan Willemsen newField: func() protoreflect.Value { 461*1c12ee1eSDan Willemsen return conv.New() 462*1c12ee1eSDan Willemsen }, 463*1c12ee1eSDan Willemsen } 464*1c12ee1eSDan Willemsen} 465*1c12ee1eSDan Willemsen 466*1c12ee1eSDan Willemsentype oneofInfo struct { 467*1c12ee1eSDan Willemsen oneofDesc protoreflect.OneofDescriptor 468*1c12ee1eSDan Willemsen which func(pointer) protoreflect.FieldNumber 469*1c12ee1eSDan Willemsen} 470*1c12ee1eSDan Willemsen 471*1c12ee1eSDan Willemsenfunc makeOneofInfo(od protoreflect.OneofDescriptor, si structInfo, x exporter) *oneofInfo { 472*1c12ee1eSDan Willemsen oi := &oneofInfo{oneofDesc: od} 473*1c12ee1eSDan Willemsen if od.IsSynthetic() { 474*1c12ee1eSDan Willemsen fs := si.fieldsByNumber[od.Fields().Get(0).Number()] 475*1c12ee1eSDan Willemsen fieldOffset := offsetOf(fs, x) 476*1c12ee1eSDan Willemsen oi.which = func(p pointer) protoreflect.FieldNumber { 477*1c12ee1eSDan Willemsen if p.IsNil() { 478*1c12ee1eSDan Willemsen return 0 479*1c12ee1eSDan Willemsen } 480*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 481*1c12ee1eSDan Willemsen if rv.IsNil() { // valid on either *T or []byte 482*1c12ee1eSDan Willemsen return 0 483*1c12ee1eSDan Willemsen } 484*1c12ee1eSDan Willemsen return od.Fields().Get(0).Number() 485*1c12ee1eSDan Willemsen } 486*1c12ee1eSDan Willemsen } else { 487*1c12ee1eSDan Willemsen fs := si.oneofsByName[od.Name()] 488*1c12ee1eSDan Willemsen fieldOffset := offsetOf(fs, x) 489*1c12ee1eSDan Willemsen oi.which = func(p pointer) protoreflect.FieldNumber { 490*1c12ee1eSDan Willemsen if p.IsNil() { 491*1c12ee1eSDan Willemsen return 0 492*1c12ee1eSDan Willemsen } 493*1c12ee1eSDan Willemsen rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem() 494*1c12ee1eSDan Willemsen if rv.IsNil() { 495*1c12ee1eSDan Willemsen return 0 496*1c12ee1eSDan Willemsen } 497*1c12ee1eSDan Willemsen rv = rv.Elem() 498*1c12ee1eSDan Willemsen if rv.IsNil() { 499*1c12ee1eSDan Willemsen return 0 500*1c12ee1eSDan Willemsen } 501*1c12ee1eSDan Willemsen return si.oneofWrappersByType[rv.Type().Elem()] 502*1c12ee1eSDan Willemsen } 503*1c12ee1eSDan Willemsen } 504*1c12ee1eSDan Willemsen return oi 505*1c12ee1eSDan Willemsen} 506*1c12ee1eSDan Willemsen 507*1c12ee1eSDan Willemsen// isZero is identical to reflect.Value.IsZero. 508*1c12ee1eSDan Willemsen// TODO: Remove this when Go1.13 is the minimally supported Go version. 509*1c12ee1eSDan Willemsenfunc isZero(v reflect.Value) bool { 510*1c12ee1eSDan Willemsen switch v.Kind() { 511*1c12ee1eSDan Willemsen case reflect.Bool: 512*1c12ee1eSDan Willemsen return !v.Bool() 513*1c12ee1eSDan Willemsen case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 514*1c12ee1eSDan Willemsen return v.Int() == 0 515*1c12ee1eSDan Willemsen case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 516*1c12ee1eSDan Willemsen return v.Uint() == 0 517*1c12ee1eSDan Willemsen case reflect.Float32, reflect.Float64: 518*1c12ee1eSDan Willemsen return math.Float64bits(v.Float()) == 0 519*1c12ee1eSDan Willemsen case reflect.Complex64, reflect.Complex128: 520*1c12ee1eSDan Willemsen c := v.Complex() 521*1c12ee1eSDan Willemsen return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0 522*1c12ee1eSDan Willemsen case reflect.Array: 523*1c12ee1eSDan Willemsen for i := 0; i < v.Len(); i++ { 524*1c12ee1eSDan Willemsen if !isZero(v.Index(i)) { 525*1c12ee1eSDan Willemsen return false 526*1c12ee1eSDan Willemsen } 527*1c12ee1eSDan Willemsen } 528*1c12ee1eSDan Willemsen return true 529*1c12ee1eSDan Willemsen case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: 530*1c12ee1eSDan Willemsen return v.IsNil() 531*1c12ee1eSDan Willemsen case reflect.String: 532*1c12ee1eSDan Willemsen return v.Len() == 0 533*1c12ee1eSDan Willemsen case reflect.Struct: 534*1c12ee1eSDan Willemsen for i := 0; i < v.NumField(); i++ { 535*1c12ee1eSDan Willemsen if !isZero(v.Field(i)) { 536*1c12ee1eSDan Willemsen return false 537*1c12ee1eSDan Willemsen } 538*1c12ee1eSDan Willemsen } 539*1c12ee1eSDan Willemsen return true 540*1c12ee1eSDan Willemsen default: 541*1c12ee1eSDan Willemsen panic(&reflect.ValueError{"reflect.Value.IsZero", v.Kind()}) 542*1c12ee1eSDan Willemsen } 543*1c12ee1eSDan Willemsen} 544