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