2018-09-12 16:20:37 -07: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"
|
2019-04-22 11:44:49 -07:00
|
|
|
"math"
|
2018-09-12 16:20:37 -07:00
|
|
|
"reflect"
|
2019-08-05 13:20:14 -07:00
|
|
|
"sync"
|
2018-09-12 16:20:37 -07:00
|
|
|
|
2019-04-08 13:52:14 -07:00
|
|
|
"google.golang.org/protobuf/internal/flags"
|
2019-05-13 23:55:40 -07:00
|
|
|
pref "google.golang.org/protobuf/reflect/protoreflect"
|
2019-04-08 13:52:14 -07:00
|
|
|
preg "google.golang.org/protobuf/reflect/protoregistry"
|
2018-09-12 16:20:37 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type fieldInfo struct {
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldDesc pref.FieldDescriptor
|
|
|
|
|
2019-04-01 13:49:56 -07:00
|
|
|
// These fields are used for protobuf reflection support.
|
2018-12-07 14:28:33 -08:00
|
|
|
has func(pointer) bool
|
2019-04-25 23:48:08 -07:00
|
|
|
clear func(pointer)
|
2018-12-07 14:28:33 -08:00
|
|
|
get func(pointer) pref.Value
|
|
|
|
set func(pointer, pref.Value)
|
2019-04-25 23:48:08 -07:00
|
|
|
mutable func(pointer) pref.Value
|
2018-12-07 14:28:33 -08:00
|
|
|
newMessage func() pref.Message
|
all: add NewField, NewElement, NewValue
Add methods to protoreflect.{Message,List,Map} to constrict values
assignable to a message field, list element, or map value. These
methods return the default value for scalar fields, the zero value for
scalar list elements and map values, and an empty, mutable value for
messages, lists, and maps.
Deprecate the NewMessage methods on these types, which are superseded.
Updates golang/protobuf#879
Change-Id: I0f064f60c89a239330ccea81523f559f14fd2c4f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-05 10:48:38 -07:00
|
|
|
newField func() pref.Value
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
|
2019-07-06 13:05:11 -07:00
|
|
|
func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, x exporter, ot reflect.Type) fieldInfo {
|
2018-10-17 11:46:52 -07:00
|
|
|
ft := fs.Type
|
|
|
|
if ft.Kind() != reflect.Interface {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v has invalid type: got %v, want interface kind", fd.FullName(), ft))
|
2018-10-17 11:46:52 -07:00
|
|
|
}
|
|
|
|
if ot.Kind() != reflect.Struct {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v has invalid type: got %v, want struct kind", fd.FullName(), ot))
|
2018-10-17 11:46:52 -07:00
|
|
|
}
|
|
|
|
if !reflect.PtrTo(ot).Implements(ft) {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v has invalid type: %v does not implement %v", fd.FullName(), ot, ft))
|
2018-10-17 11:46:52 -07:00
|
|
|
}
|
2019-07-17 16:52:10 -07:00
|
|
|
conv := NewConverter(ot.Field(0).Type, fd)
|
|
|
|
isMessage := fd.Message() != nil
|
2019-04-25 23:48:08 -07:00
|
|
|
|
2018-10-17 11:46:52 -07:00
|
|
|
// TODO: Implement unsafe fast path?
|
2019-07-06 13:05:11 -07:00
|
|
|
fieldOffset := offsetOf(fs, x)
|
2018-10-17 11:46:52 -07:00
|
|
|
return fieldInfo{
|
|
|
|
// NOTE: The logic below intentionally assumes that oneof fields are
|
|
|
|
// well-formatted. That is, the oneof interface never contains a
|
|
|
|
// typed nil pointer to one of the wrapper structs.
|
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldDesc: fd,
|
2018-10-17 11:46:52 -07:00
|
|
|
has: func(p pointer) bool {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2019-08-08 19:23:32 -07:00
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
|
2018-10-17 11:46:52 -07:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
clear: func(p pointer) {
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot {
|
2019-08-08 19:23:32 -07:00
|
|
|
// NOTE: We intentionally don't check for rv.Elem().IsNil()
|
|
|
|
// so that (*OneofWrapperType)(nil) gets cleared to nil.
|
2019-04-25 23:48:08 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
rv.Set(reflect.Zero(rv.Type()))
|
|
|
|
},
|
2018-10-17 11:46:52 -07:00
|
|
|
get: func(p pointer) pref.Value {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
all: make handling of zero-value composites more consistent
We occasionally need to work with immutable, empty lists, maps, and
messages. Notably, Message.Get on an empty repeated field will return a
"frozen" empty value.
Move handling of these immutable, zero-length composites into Converter,
to unify the behavior of regular and extension fields.
Add a Zero method to Converter, MessageType, and ExtensionType, to
provide a consistent way to get an empty, frozen value of a composite
type. Adding this method to the public {Message,Extension}Type
interfaces does increase our API surface, but lets us (for example)
cleanly represent an empty map as a nil map rather than a non-nil
one wrapped in a frozenMap type.
Drop the frozen{List,Map,Message} types as no longer necessary.
(These types did have support for creating a read-only view of a
non-empty value, but we are not currently using that feature.)
Change-Id: Ia76f149d591da07b40ce75b7404a7ab8a60cb9d8
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189339
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-07 12:21:41 -07:00
|
|
|
return conv.Zero()
|
2018-12-01 04:57:09 -08:00
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2019-08-08 19:23:32 -07:00
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
|
all: make handling of zero-value composites more consistent
We occasionally need to work with immutable, empty lists, maps, and
messages. Notably, Message.Get on an empty repeated field will return a
"frozen" empty value.
Move handling of these immutable, zero-length composites into Converter,
to unify the behavior of regular and extension fields.
Add a Zero method to Converter, MessageType, and ExtensionType, to
provide a consistent way to get an empty, frozen value of a composite
type. Adding this method to the public {Message,Extension}Type
interfaces does increase our API surface, but lets us (for example)
cleanly represent an empty map as a nil map rather than a non-nil
one wrapped in a frozenMap type.
Drop the frozen{List,Map,Message} types as no longer necessary.
(These types did have support for creating a read-only view of a
non-empty value, but we are not currently using that feature.)
Change-Id: Ia76f149d591da07b40ce75b7404a7ab8a60cb9d8
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189339
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-07 12:21:41 -07:00
|
|
|
return conv.Zero()
|
2018-10-17 11:46:52 -07:00
|
|
|
}
|
|
|
|
rv = rv.Elem().Elem().Field(0)
|
2018-11-05 11:42:22 -08:00
|
|
|
return conv.PBValueOf(rv)
|
2018-10-17 11:46:52 -07:00
|
|
|
},
|
|
|
|
set: func(p pointer, v pref.Value) {
|
2018-12-01 04:57:09 -08:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2019-08-08 19:23:32 -07:00
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
|
2018-10-17 11:46:52 -07:00
|
|
|
rv.Set(reflect.New(ot))
|
|
|
|
}
|
|
|
|
rv = rv.Elem().Elem().Field(0)
|
2018-11-05 11:42:22 -08:00
|
|
|
rv.Set(conv.GoValueOf(v))
|
2018-10-17 11:46:52 -07:00
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
mutable: func(p pointer) pref.Value {
|
2019-07-17 16:52:10 -07:00
|
|
|
if !isMessage {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v with invalid Mutable call on field with non-composite type", fd.FullName()))
|
2019-04-25 23:48:08 -07:00
|
|
|
}
|
2018-12-01 04:57:09 -08:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2019-08-08 19:23:32 -07:00
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
|
2019-04-25 23:48:08 -07:00
|
|
|
rv.Set(reflect.New(ot))
|
2018-10-17 11:46:52 -07:00
|
|
|
}
|
2019-04-25 23:48:08 -07:00
|
|
|
rv = rv.Elem().Elem().Field(0)
|
|
|
|
if rv.IsNil() {
|
2019-09-17 13:38:48 -07:00
|
|
|
rv.Set(conv.GoValueOf(pref.ValueOfMessage(conv.New().Message())))
|
2019-04-25 23:48:08 -07:00
|
|
|
}
|
|
|
|
return conv.PBValueOf(rv)
|
2018-10-17 11:46:52 -07:00
|
|
|
},
|
2019-07-17 16:52:10 -07:00
|
|
|
newMessage: func() pref.Message {
|
|
|
|
return conv.New().Message()
|
|
|
|
},
|
all: add NewField, NewElement, NewValue
Add methods to protoreflect.{Message,List,Map} to constrict values
assignable to a message field, list element, or map value. These
methods return the default value for scalar fields, the zero value for
scalar list elements and map values, and an empty, mutable value for
messages, lists, and maps.
Deprecate the NewMessage methods on these types, which are superseded.
Updates golang/protobuf#879
Change-Id: I0f064f60c89a239330ccea81523f559f14fd2c4f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-05 10:48:38 -07:00
|
|
|
newField: func() pref.Value {
|
|
|
|
return conv.New()
|
|
|
|
},
|
2018-10-17 11:46:52 -07:00
|
|
|
}
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
|
2019-07-06 13:05:11 -07:00
|
|
|
func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
|
2018-10-17 00:27:21 +00:00
|
|
|
ft := fs.Type
|
|
|
|
if ft.Kind() != reflect.Map {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v has invalid type: got %v, want map kind", fd.FullName(), ft))
|
2018-10-17 00:27:21 +00:00
|
|
|
}
|
2019-07-17 16:52:10 -07:00
|
|
|
conv := NewConverter(ft, fd)
|
2019-04-25 23:48:08 -07:00
|
|
|
|
2018-10-17 00:27:21 +00:00
|
|
|
// TODO: Implement unsafe fast path?
|
2019-07-06 13:05:11 -07:00
|
|
|
fieldOffset := offsetOf(fs, x)
|
2018-10-17 00:27:21 +00:00
|
|
|
return fieldInfo{
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldDesc: fd,
|
2018-10-17 00:27:21 +00:00
|
|
|
has: func(p pointer) bool {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-10-17 00:27:21 +00:00
|
|
|
return rv.Len() > 0
|
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
clear: func(p pointer) {
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
rv.Set(reflect.Zero(rv.Type()))
|
|
|
|
},
|
2018-10-17 00:27:21 +00:00
|
|
|
get: func(p pointer) pref.Value {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
all: make handling of zero-value composites more consistent
We occasionally need to work with immutable, empty lists, maps, and
messages. Notably, Message.Get on an empty repeated field will return a
"frozen" empty value.
Move handling of these immutable, zero-length composites into Converter,
to unify the behavior of regular and extension fields.
Add a Zero method to Converter, MessageType, and ExtensionType, to
provide a consistent way to get an empty, frozen value of a composite
type. Adding this method to the public {Message,Extension}Type
interfaces does increase our API surface, but lets us (for example)
cleanly represent an empty map as a nil map rather than a non-nil
one wrapped in a frozenMap type.
Drop the frozen{List,Map,Message} types as no longer necessary.
(These types did have support for creating a read-only view of a
non-empty value, but we are not currently using that feature.)
Change-Id: Ia76f149d591da07b40ce75b7404a7ab8a60cb9d8
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189339
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-07 12:21:41 -07:00
|
|
|
return conv.Zero()
|
2018-12-01 04:57:09 -08:00
|
|
|
}
|
2019-04-25 23:48:08 -07:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2019-11-26 13:31:38 -08:00
|
|
|
if rv.Len() == 0 {
|
|
|
|
return conv.Zero()
|
|
|
|
}
|
2019-07-17 16:52:10 -07:00
|
|
|
return conv.PBValueOf(rv)
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
|
|
|
set: func(p pointer, v pref.Value) {
|
2018-12-01 04:57:09 -08:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2019-11-26 13:31:38 -08:00
|
|
|
pv := conv.GoValueOf(v)
|
|
|
|
if pv.IsNil() {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("map field %v cannot be set with read-only value", fd.FullName()))
|
2019-11-26 13:31:38 -08:00
|
|
|
}
|
|
|
|
rv.Set(pv)
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
mutable: func(p pointer) pref.Value {
|
2019-07-17 16:52:10 -07:00
|
|
|
v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
if v.IsNil() {
|
|
|
|
v.Set(reflect.MakeMap(fs.Type))
|
|
|
|
}
|
|
|
|
return conv.PBValueOf(v)
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
all: add NewField, NewElement, NewValue
Add methods to protoreflect.{Message,List,Map} to constrict values
assignable to a message field, list element, or map value. These
methods return the default value for scalar fields, the zero value for
scalar list elements and map values, and an empty, mutable value for
messages, lists, and maps.
Deprecate the NewMessage methods on these types, which are superseded.
Updates golang/protobuf#879
Change-Id: I0f064f60c89a239330ccea81523f559f14fd2c4f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-05 10:48:38 -07:00
|
|
|
newField: func() pref.Value {
|
|
|
|
return conv.New()
|
|
|
|
},
|
2018-10-17 00:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-06 13:05:11 -07:00
|
|
|
func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
|
2018-09-13 13:24:35 -07:00
|
|
|
ft := fs.Type
|
|
|
|
if ft.Kind() != reflect.Slice {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v has invalid type: got %v, want slice kind", fd.FullName(), ft))
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
2019-07-17 16:52:10 -07:00
|
|
|
conv := NewConverter(reflect.PtrTo(ft), fd)
|
2019-04-25 23:48:08 -07:00
|
|
|
|
2018-09-13 13:24:35 -07:00
|
|
|
// TODO: Implement unsafe fast path?
|
2019-07-06 13:05:11 -07:00
|
|
|
fieldOffset := offsetOf(fs, x)
|
2018-09-13 13:24:35 -07:00
|
|
|
return fieldInfo{
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldDesc: fd,
|
2018-09-13 13:24:35 -07:00
|
|
|
has: func(p pointer) bool {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-09-13 13:24:35 -07:00
|
|
|
return rv.Len() > 0
|
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
clear: func(p pointer) {
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
rv.Set(reflect.Zero(rv.Type()))
|
|
|
|
},
|
2018-09-13 13:24:35 -07:00
|
|
|
get: func(p pointer) pref.Value {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
all: make handling of zero-value composites more consistent
We occasionally need to work with immutable, empty lists, maps, and
messages. Notably, Message.Get on an empty repeated field will return a
"frozen" empty value.
Move handling of these immutable, zero-length composites into Converter,
to unify the behavior of regular and extension fields.
Add a Zero method to Converter, MessageType, and ExtensionType, to
provide a consistent way to get an empty, frozen value of a composite
type. Adding this method to the public {Message,Extension}Type
interfaces does increase our API surface, but lets us (for example)
cleanly represent an empty map as a nil map rather than a non-nil
one wrapped in a frozenMap type.
Drop the frozen{List,Map,Message} types as no longer necessary.
(These types did have support for creating a read-only view of a
non-empty value, but we are not currently using that feature.)
Change-Id: Ia76f149d591da07b40ce75b7404a7ab8a60cb9d8
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189339
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-07 12:21:41 -07:00
|
|
|
return conv.Zero()
|
2018-12-01 04:57:09 -08:00
|
|
|
}
|
2019-07-17 16:52:10 -07:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
|
2019-11-26 13:31:38 -08:00
|
|
|
if rv.Elem().Len() == 0 {
|
|
|
|
return conv.Zero()
|
|
|
|
}
|
2019-07-17 16:52:10 -07:00
|
|
|
return conv.PBValueOf(rv)
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
set: func(p pointer, v pref.Value) {
|
2018-12-01 04:57:09 -08:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2019-11-26 13:31:38 -08:00
|
|
|
pv := conv.GoValueOf(v)
|
|
|
|
if pv.IsNil() {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("list field %v cannot be set with read-only value", fd.FullName()))
|
2019-11-26 13:31:38 -08:00
|
|
|
}
|
|
|
|
rv.Set(pv.Elem())
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
mutable: func(p pointer) pref.Value {
|
2019-07-17 16:52:10 -07:00
|
|
|
v := p.Apply(fieldOffset).AsValueOf(fs.Type)
|
|
|
|
return conv.PBValueOf(v)
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
all: add NewField, NewElement, NewValue
Add methods to protoreflect.{Message,List,Map} to constrict values
assignable to a message field, list element, or map value. These
methods return the default value for scalar fields, the zero value for
scalar list elements and map values, and an empty, mutable value for
messages, lists, and maps.
Deprecate the NewMessage methods on these types, which are superseded.
Updates golang/protobuf#879
Change-Id: I0f064f60c89a239330ccea81523f559f14fd2c4f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-05 10:48:38 -07:00
|
|
|
newField: func() pref.Value {
|
|
|
|
return conv.New()
|
|
|
|
},
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-10 10:21:12 -07:00
|
|
|
var (
|
|
|
|
nilBytes = reflect.ValueOf([]byte(nil))
|
|
|
|
emptyBytes = reflect.ValueOf([]byte{})
|
|
|
|
)
|
2018-09-12 16:20:37 -07:00
|
|
|
|
2019-07-06 13:05:11 -07:00
|
|
|
func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
|
2018-09-12 16:20:37 -07:00
|
|
|
ft := fs.Type
|
2020-04-28 14:44:38 -07:00
|
|
|
nullable := fd.HasPresence()
|
2019-07-10 10:21:12 -07:00
|
|
|
isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8
|
2018-09-12 16:20:37 -07:00
|
|
|
if nullable {
|
|
|
|
if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v has invalid type: got %v, want pointer", fd.FullName(), ft))
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
if ft.Kind() == reflect.Ptr {
|
|
|
|
ft = ft.Elem()
|
|
|
|
}
|
|
|
|
}
|
2019-07-17 16:52:10 -07:00
|
|
|
conv := NewConverter(ft, fd)
|
2019-04-25 23:48:08 -07:00
|
|
|
|
2018-09-12 16:20:37 -07:00
|
|
|
// TODO: Implement unsafe fast path?
|
2019-07-06 13:05:11 -07:00
|
|
|
fieldOffset := offsetOf(fs, x)
|
2018-09-12 16:20:37 -07:00
|
|
|
return fieldInfo{
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldDesc: fd,
|
2018-09-12 16:20:37 -07:00
|
|
|
has: func(p pointer) bool {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-09-12 16:20:37 -07:00
|
|
|
if nullable {
|
|
|
|
return !rv.IsNil()
|
|
|
|
}
|
|
|
|
switch rv.Kind() {
|
|
|
|
case reflect.Bool:
|
|
|
|
return rv.Bool()
|
|
|
|
case reflect.Int32, reflect.Int64:
|
2018-11-19 15:27:09 -08:00
|
|
|
return rv.Int() != 0
|
2018-09-12 16:20:37 -07:00
|
|
|
case reflect.Uint32, reflect.Uint64:
|
2018-11-19 15:27:09 -08:00
|
|
|
return rv.Uint() != 0
|
2018-09-12 16:20:37 -07:00
|
|
|
case reflect.Float32, reflect.Float64:
|
2019-04-22 11:44:49 -07:00
|
|
|
return rv.Float() != 0 || math.Signbit(rv.Float())
|
2018-09-12 16:20:37 -07:00
|
|
|
case reflect.String, reflect.Slice:
|
|
|
|
return rv.Len() > 0
|
|
|
|
default:
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v has invalid type: %v", fd.FullName(), rv.Type())) // should never happen
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
clear: func(p pointer) {
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
rv.Set(reflect.Zero(rv.Type()))
|
|
|
|
},
|
2018-09-12 16:20:37 -07:00
|
|
|
get: func(p pointer) pref.Value {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
all: make handling of zero-value composites more consistent
We occasionally need to work with immutable, empty lists, maps, and
messages. Notably, Message.Get on an empty repeated field will return a
"frozen" empty value.
Move handling of these immutable, zero-length composites into Converter,
to unify the behavior of regular and extension fields.
Add a Zero method to Converter, MessageType, and ExtensionType, to
provide a consistent way to get an empty, frozen value of a composite
type. Adding this method to the public {Message,Extension}Type
interfaces does increase our API surface, but lets us (for example)
cleanly represent an empty map as a nil map rather than a non-nil
one wrapped in a frozenMap type.
Drop the frozen{List,Map,Message} types as no longer necessary.
(These types did have support for creating a read-only view of a
non-empty value, but we are not currently using that feature.)
Change-Id: Ia76f149d591da07b40ce75b7404a7ab8a60cb9d8
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189339
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-07 12:21:41 -07:00
|
|
|
return conv.Zero()
|
2018-12-01 04:57:09 -08:00
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-09-12 16:20:37 -07:00
|
|
|
if nullable {
|
|
|
|
if rv.IsNil() {
|
all: make handling of zero-value composites more consistent
We occasionally need to work with immutable, empty lists, maps, and
messages. Notably, Message.Get on an empty repeated field will return a
"frozen" empty value.
Move handling of these immutable, zero-length composites into Converter,
to unify the behavior of regular and extension fields.
Add a Zero method to Converter, MessageType, and ExtensionType, to
provide a consistent way to get an empty, frozen value of a composite
type. Adding this method to the public {Message,Extension}Type
interfaces does increase our API surface, but lets us (for example)
cleanly represent an empty map as a nil map rather than a non-nil
one wrapped in a frozenMap type.
Drop the frozen{List,Map,Message} types as no longer necessary.
(These types did have support for creating a read-only view of a
non-empty value, but we are not currently using that feature.)
Change-Id: Ia76f149d591da07b40ce75b7404a7ab8a60cb9d8
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189339
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-07 12:21:41 -07:00
|
|
|
return conv.Zero()
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
if rv.Kind() == reflect.Ptr {
|
|
|
|
rv = rv.Elem()
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 11:42:22 -08:00
|
|
|
return conv.PBValueOf(rv)
|
2018-09-12 16:20:37 -07:00
|
|
|
},
|
|
|
|
set: func(p pointer, v pref.Value) {
|
2018-12-01 04:57:09 -08:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-09-12 16:20:37 -07:00
|
|
|
if nullable && rv.Kind() == reflect.Ptr {
|
|
|
|
if rv.IsNil() {
|
|
|
|
rv.Set(reflect.New(ft))
|
|
|
|
}
|
|
|
|
rv = rv.Elem()
|
|
|
|
}
|
2018-11-05 11:42:22 -08:00
|
|
|
rv.Set(conv.GoValueOf(v))
|
2019-07-10 10:21:12 -07:00
|
|
|
if isBytes && rv.Len() == 0 {
|
|
|
|
if nullable {
|
2020-04-28 14:44:38 -07:00
|
|
|
rv.Set(emptyBytes) // preserve presence
|
2019-07-10 10:21:12 -07:00
|
|
|
} else {
|
2020-04-28 14:44:38 -07:00
|
|
|
rv.Set(nilBytes) // do not preserve presence
|
2019-07-10 10:21:12 -07:00
|
|
|
}
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
},
|
all: add NewField, NewElement, NewValue
Add methods to protoreflect.{Message,List,Map} to constrict values
assignable to a message field, list element, or map value. These
methods return the default value for scalar fields, the zero value for
scalar list elements and map values, and an empty, mutable value for
messages, lists, and maps.
Deprecate the NewMessage methods on these types, which are superseded.
Updates golang/protobuf#879
Change-Id: I0f064f60c89a239330ccea81523f559f14fd2c4f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-05 10:48:38 -07:00
|
|
|
newField: func() pref.Value {
|
|
|
|
return conv.New()
|
|
|
|
},
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-08 13:52:14 -07:00
|
|
|
func fieldInfoForWeakMessage(fd pref.FieldDescriptor, weakOffset offset) fieldInfo {
|
2019-08-08 13:31:59 -07:00
|
|
|
if !flags.ProtoLegacy {
|
2019-04-08 13:52:14 -07:00
|
|
|
panic("no support for proto1 weak fields")
|
|
|
|
}
|
|
|
|
|
2019-08-05 13:20:14 -07:00
|
|
|
var once sync.Once
|
|
|
|
var messageType pref.MessageType
|
|
|
|
lazyInit := func() {
|
|
|
|
once.Do(func() {
|
|
|
|
messageName := fd.Message().FullName()
|
|
|
|
messageType, _ = preg.GlobalTypes.FindMessageByName(messageName)
|
|
|
|
if messageType == nil {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("weak message %v for field %v is not linked in", messageName, fd.FullName()))
|
2019-08-05 13:20:14 -07:00
|
|
|
}
|
|
|
|
})
|
2019-04-08 13:52:14 -07:00
|
|
|
}
|
|
|
|
|
2019-10-01 13:05:16 -07:00
|
|
|
num := fd.Number()
|
2019-04-08 13:52:14 -07:00
|
|
|
return fieldInfo{
|
|
|
|
fieldDesc: fd,
|
|
|
|
has: func(p pointer) bool {
|
|
|
|
if p.IsNil() {
|
|
|
|
return false
|
|
|
|
}
|
2019-10-01 13:05:16 -07:00
|
|
|
_, ok := p.Apply(weakOffset).WeakFields().get(num)
|
2019-04-08 13:52:14 -07:00
|
|
|
return ok
|
|
|
|
},
|
|
|
|
clear: func(p pointer) {
|
2019-10-01 13:05:16 -07:00
|
|
|
p.Apply(weakOffset).WeakFields().clear(num)
|
2019-04-08 13:52:14 -07:00
|
|
|
},
|
|
|
|
get: func(p pointer) pref.Value {
|
2019-08-05 13:20:14 -07:00
|
|
|
lazyInit()
|
2019-04-08 13:52:14 -07:00
|
|
|
if p.IsNil() {
|
2019-09-17 13:38:48 -07:00
|
|
|
return pref.ValueOfMessage(messageType.Zero())
|
2019-04-08 13:52:14 -07:00
|
|
|
}
|
2019-10-01 13:05:16 -07:00
|
|
|
m, ok := p.Apply(weakOffset).WeakFields().get(num)
|
2019-04-08 13:52:14 -07:00
|
|
|
if !ok {
|
2019-09-17 13:38:48 -07:00
|
|
|
return pref.ValueOfMessage(messageType.Zero())
|
2019-04-08 13:52:14 -07:00
|
|
|
}
|
2019-10-01 13:05:16 -07:00
|
|
|
return pref.ValueOfMessage(m.ProtoReflect())
|
2019-04-08 13:52:14 -07:00
|
|
|
},
|
|
|
|
set: func(p pointer, v pref.Value) {
|
2019-08-05 13:20:14 -07:00
|
|
|
lazyInit()
|
2019-04-08 13:52:14 -07:00
|
|
|
m := v.Message()
|
|
|
|
if m.Descriptor() != messageType.Descriptor() {
|
2020-04-22 21:58:56 -07:00
|
|
|
if got, want := m.Descriptor().FullName(), messageType.Descriptor().FullName(); got != want {
|
|
|
|
panic(fmt.Sprintf("field %v has mismatching message descriptor: got %v, want %v", fd.FullName(), got, want))
|
|
|
|
}
|
|
|
|
panic(fmt.Sprintf("field %v has mismatching message descriptor: %v", fd.FullName(), m.Descriptor().FullName()))
|
2019-04-08 13:52:14 -07:00
|
|
|
}
|
2019-10-01 13:05:16 -07:00
|
|
|
p.Apply(weakOffset).WeakFields().set(num, m.Interface())
|
2019-04-08 13:52:14 -07:00
|
|
|
},
|
|
|
|
mutable: func(p pointer) pref.Value {
|
2019-08-05 13:20:14 -07:00
|
|
|
lazyInit()
|
2019-04-08 13:52:14 -07:00
|
|
|
fs := p.Apply(weakOffset).WeakFields()
|
2019-10-01 13:05:16 -07:00
|
|
|
m, ok := fs.get(num)
|
2019-04-08 13:52:14 -07:00
|
|
|
if !ok {
|
2019-10-01 13:05:16 -07:00
|
|
|
m = messageType.New().Interface()
|
|
|
|
fs.set(num, m)
|
2019-04-08 13:52:14 -07:00
|
|
|
}
|
2019-10-01 13:05:16 -07:00
|
|
|
return pref.ValueOfMessage(m.ProtoReflect())
|
2019-04-08 13:52:14 -07:00
|
|
|
},
|
|
|
|
newMessage: func() pref.Message {
|
2019-08-05 13:20:14 -07:00
|
|
|
lazyInit()
|
2019-04-08 13:52:14 -07:00
|
|
|
return messageType.New()
|
|
|
|
},
|
all: add NewField, NewElement, NewValue
Add methods to protoreflect.{Message,List,Map} to constrict values
assignable to a message field, list element, or map value. These
methods return the default value for scalar fields, the zero value for
scalar list elements and map values, and an empty, mutable value for
messages, lists, and maps.
Deprecate the NewMessage methods on these types, which are superseded.
Updates golang/protobuf#879
Change-Id: I0f064f60c89a239330ccea81523f559f14fd2c4f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-05 10:48:38 -07:00
|
|
|
newField: func() pref.Value {
|
|
|
|
lazyInit()
|
2019-09-17 13:38:48 -07:00
|
|
|
return pref.ValueOfMessage(messageType.New())
|
all: add NewField, NewElement, NewValue
Add methods to protoreflect.{Message,List,Map} to constrict values
assignable to a message field, list element, or map value. These
methods return the default value for scalar fields, the zero value for
scalar list elements and map values, and an empty, mutable value for
messages, lists, and maps.
Deprecate the NewMessage methods on these types, which are superseded.
Updates golang/protobuf#879
Change-Id: I0f064f60c89a239330ccea81523f559f14fd2c4f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-05 10:48:38 -07:00
|
|
|
},
|
2019-04-08 13:52:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-06 13:05:11 -07:00
|
|
|
func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
|
2018-10-19 16:27:46 -07:00
|
|
|
ft := fs.Type
|
2019-07-17 16:52:10 -07:00
|
|
|
conv := NewConverter(ft, fd)
|
2019-04-25 23:48:08 -07:00
|
|
|
|
|
|
|
// TODO: Implement unsafe fast path?
|
2019-07-06 13:05:11 -07:00
|
|
|
fieldOffset := offsetOf(fs, x)
|
2018-10-19 16:27:46 -07:00
|
|
|
return fieldInfo{
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldDesc: fd,
|
2018-10-19 16:27:46 -07:00
|
|
|
has: func(p pointer) bool {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-10-19 16:27:46 -07:00
|
|
|
return !rv.IsNil()
|
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
clear: func(p pointer) {
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
rv.Set(reflect.Zero(rv.Type()))
|
|
|
|
},
|
2018-10-19 16:27:46 -07:00
|
|
|
get: func(p pointer) pref.Value {
|
2018-12-01 04:57:09 -08:00
|
|
|
if p.IsNil() {
|
all: make handling of zero-value composites more consistent
We occasionally need to work with immutable, empty lists, maps, and
messages. Notably, Message.Get on an empty repeated field will return a
"frozen" empty value.
Move handling of these immutable, zero-length composites into Converter,
to unify the behavior of regular and extension fields.
Add a Zero method to Converter, MessageType, and ExtensionType, to
provide a consistent way to get an empty, frozen value of a composite
type. Adding this method to the public {Message,Extension}Type
interfaces does increase our API surface, but lets us (for example)
cleanly represent an empty map as a nil map rather than a non-nil
one wrapped in a frozenMap type.
Drop the frozen{List,Map,Message} types as no longer necessary.
(These types did have support for creating a read-only view of a
non-empty value, but we are not currently using that feature.)
Change-Id: Ia76f149d591da07b40ce75b7404a7ab8a60cb9d8
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189339
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-07 12:21:41 -07:00
|
|
|
return conv.Zero()
|
2018-12-01 04:57:09 -08:00
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-11-05 11:42:22 -08:00
|
|
|
return conv.PBValueOf(rv)
|
2018-10-19 16:27:46 -07:00
|
|
|
},
|
|
|
|
set: func(p pointer, v pref.Value) {
|
2018-12-01 04:57:09 -08:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-11-05 11:42:22 -08:00
|
|
|
rv.Set(conv.GoValueOf(v))
|
reflect/protoreflect: clarify Get semantics on unpopulated fields
Clearly specify that Get on an unpopulated field:
* returns the default value for scalars
* returns a mutable (but empty) List for repeated fields
* returns a mutable (but empty) Map for map fields
* returns an invalid value for message fields
The difference in semantics between List+Maps and Messages is because
protobuf semantics provide no distinction between an unpopulated and empty list
or map. On the other hand, there is a semantic difference between an unpopulated
message and an empty message.
Default values for scalars is trivial to implement with FieldDescriptor.Default.
A mutable, but empty List and Map is easy to implement for known fields since
known fields are generated as a slice or map field in a struct.
Since struct fields are addressable, the implementation can just return a
reference to the slice or map.
Repeated, extension fields are a little more tricky since extension fields
are implemented under the hood as a map[FieldNumber]Extension.
Rather than allocating an empty list in KnownFields.Get upon first retrieval
(which presents a race), delegate the work to ExtensionFieldTypes.Register,
which must occur before any Get operation. Register is not a concurrent-safe
operation, so that is an excellent time to initilize empty lists.
The implementation of extensions will need to be careful that Clear on a repeated
field simply truncates it zero instead of deleting the object.
For unpopulated messages, we return an invalid value, instead of the prior
behavior of returning a typed nil-pointer to the Go type for the message.
The approach is problematic because it assumes that
1) all messages are always implemented on a pointer reciever
2) a typed nil-pointer is an appropriate "read-only, but empty" message
These assumptions are not true of all message types (e.g., dynamic messages).
Change-Id: Ie96e6744c890308d9de738b6cf01d3b19e7e7c6a
Reviewed-on: https://go-review.googlesource.com/c/150319
Reviewed-by: Damien Neil <dneil@google.com>
2018-11-19 14:26:06 -08:00
|
|
|
if rv.IsNil() {
|
2020-04-22 21:58:56 -07:00
|
|
|
panic(fmt.Sprintf("field %v has invalid nil pointer", fd.FullName()))
|
reflect/protoreflect: clarify Get semantics on unpopulated fields
Clearly specify that Get on an unpopulated field:
* returns the default value for scalars
* returns a mutable (but empty) List for repeated fields
* returns a mutable (but empty) Map for map fields
* returns an invalid value for message fields
The difference in semantics between List+Maps and Messages is because
protobuf semantics provide no distinction between an unpopulated and empty list
or map. On the other hand, there is a semantic difference between an unpopulated
message and an empty message.
Default values for scalars is trivial to implement with FieldDescriptor.Default.
A mutable, but empty List and Map is easy to implement for known fields since
known fields are generated as a slice or map field in a struct.
Since struct fields are addressable, the implementation can just return a
reference to the slice or map.
Repeated, extension fields are a little more tricky since extension fields
are implemented under the hood as a map[FieldNumber]Extension.
Rather than allocating an empty list in KnownFields.Get upon first retrieval
(which presents a race), delegate the work to ExtensionFieldTypes.Register,
which must occur before any Get operation. Register is not a concurrent-safe
operation, so that is an excellent time to initilize empty lists.
The implementation of extensions will need to be careful that Clear on a repeated
field simply truncates it zero instead of deleting the object.
For unpopulated messages, we return an invalid value, instead of the prior
behavior of returning a typed nil-pointer to the Go type for the message.
The approach is problematic because it assumes that
1) all messages are always implemented on a pointer reciever
2) a typed nil-pointer is an appropriate "read-only, but empty" message
These assumptions are not true of all message types (e.g., dynamic messages).
Change-Id: Ie96e6744c890308d9de738b6cf01d3b19e7e7c6a
Reviewed-on: https://go-review.googlesource.com/c/150319
Reviewed-by: Damien Neil <dneil@google.com>
2018-11-19 14:26:06 -08:00
|
|
|
}
|
2018-10-19 16:27:46 -07:00
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
mutable: func(p pointer) pref.Value {
|
2018-12-01 04:57:09 -08:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2019-04-25 23:48:08 -07:00
|
|
|
if rv.IsNil() {
|
2019-07-17 16:52:10 -07:00
|
|
|
rv.Set(conv.GoValueOf(conv.New()))
|
2019-04-25 23:48:08 -07:00
|
|
|
}
|
|
|
|
return conv.PBValueOf(rv)
|
2018-10-19 16:27:46 -07:00
|
|
|
},
|
2019-07-17 16:52:10 -07:00
|
|
|
newMessage: func() pref.Message {
|
|
|
|
return conv.New().Message()
|
|
|
|
},
|
all: add NewField, NewElement, NewValue
Add methods to protoreflect.{Message,List,Map} to constrict values
assignable to a message field, list element, or map value. These
methods return the default value for scalar fields, the zero value for
scalar list elements and map values, and an empty, mutable value for
messages, lists, and maps.
Deprecate the NewMessage methods on these types, which are superseded.
Updates golang/protobuf#879
Change-Id: I0f064f60c89a239330ccea81523f559f14fd2c4f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-05 10:48:38 -07:00
|
|
|
newField: func() pref.Value {
|
|
|
|
return conv.New()
|
|
|
|
},
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
}
|
2018-12-01 04:57:09 -08:00
|
|
|
|
2019-04-03 13:40:53 -07:00
|
|
|
type oneofInfo struct {
|
2019-04-25 23:48:08 -07:00
|
|
|
oneofDesc pref.OneofDescriptor
|
|
|
|
which func(pointer) pref.FieldNumber
|
2019-04-03 13:40:53 -07:00
|
|
|
}
|
|
|
|
|
2020-04-28 14:44:38 -07:00
|
|
|
func makeOneofInfo(od pref.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
|
|
|
|
oi := &oneofInfo{oneofDesc: od}
|
|
|
|
if od.IsSynthetic() {
|
|
|
|
fs := si.fieldsByNumber[od.Fields().Get(0).Number()]
|
|
|
|
fieldOffset := offsetOf(fs, x)
|
|
|
|
oi.which = func(p pointer) pref.FieldNumber {
|
|
|
|
if p.IsNil() {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
if rv.IsNil() { // valid on either *T or []byte
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return od.Fields().Get(0).Number()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fs := si.oneofsByName[od.Name()]
|
|
|
|
fieldOffset := offsetOf(fs, x)
|
|
|
|
oi.which = func(p pointer) pref.FieldNumber {
|
2019-04-03 13:40:53 -07:00
|
|
|
if p.IsNil() {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
if rv.IsNil() {
|
|
|
|
return 0
|
|
|
|
}
|
2019-09-18 18:08:52 -07:00
|
|
|
rv = rv.Elem()
|
|
|
|
if rv.IsNil() {
|
|
|
|
return 0
|
|
|
|
}
|
2020-04-28 14:44:38 -07:00
|
|
|
return si.oneofWrappersByType[rv.Type().Elem()]
|
|
|
|
}
|
2019-04-03 13:40:53 -07:00
|
|
|
}
|
2020-04-28 14:44:38 -07:00
|
|
|
return oi
|
2019-04-03 13:40:53 -07:00
|
|
|
}
|