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-05-13 23:55:40 -07:00
|
|
|
pvalue "google.golang.org/protobuf/internal/value"
|
|
|
|
pref "google.golang.org/protobuf/reflect/protoreflect"
|
2019-05-22 13:42:54 -04:00
|
|
|
piface "google.golang.org/protobuf/runtime/protoiface"
|
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
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, ot reflect.Type) fieldInfo {
|
2018-10-17 11:46:52 -07:00
|
|
|
ft := fs.Type
|
|
|
|
if ft.Kind() != reflect.Interface {
|
|
|
|
panic(fmt.Sprintf("invalid type: got %v, want interface kind", ft))
|
|
|
|
}
|
|
|
|
if ot.Kind() != reflect.Struct {
|
|
|
|
panic(fmt.Sprintf("invalid type: got %v, want struct kind", ot))
|
|
|
|
}
|
|
|
|
if !reflect.PtrTo(ot).Implements(ft) {
|
|
|
|
panic(fmt.Sprintf("invalid type: %v does not implement %v", ot, ft))
|
|
|
|
}
|
2019-05-22 13:42:54 -04:00
|
|
|
conv, _ := newConverter(ot.Field(0).Type, fd.Kind())
|
2019-04-25 23:48:08 -07:00
|
|
|
var frozenEmpty pref.Value
|
|
|
|
if conv.NewMessage != nil {
|
|
|
|
frozenEmpty = pref.ValueOf(frozenMessage{conv.NewMessage()})
|
|
|
|
}
|
|
|
|
|
2018-10-17 11:46:52 -07:00
|
|
|
// TODO: Implement unsafe fast path?
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldOffset := offsetOf(fs)
|
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()
|
2018-10-17 11:46:52 -07:00
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot {
|
|
|
|
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 {
|
|
|
|
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() {
|
2019-04-25 23:48:08 -07:00
|
|
|
if frozenEmpty.IsValid() {
|
|
|
|
return frozenEmpty
|
|
|
|
}
|
2018-12-01 04:57:09 -08:00
|
|
|
return defaultValueOf(fd)
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-10-17 11:46:52 -07:00
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot {
|
2019-04-25 23:48:08 -07:00
|
|
|
if frozenEmpty.IsValid() {
|
|
|
|
return frozenEmpty
|
|
|
|
}
|
2018-12-01 04:57:09 -08:00
|
|
|
return defaultValueOf(fd)
|
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()
|
2018-10-17 11:46:52 -07:00
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot {
|
|
|
|
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 {
|
|
|
|
if conv.NewMessage == nil {
|
|
|
|
panic("invalid Mutable on field with non-composite type")
|
|
|
|
}
|
2018-12-01 04:57:09 -08:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-10-17 11:46:52 -07:00
|
|
|
if rv.IsNil() || rv.Elem().Type().Elem() != ot {
|
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() {
|
|
|
|
rv.Set(conv.GoValueOf(pref.ValueOf(conv.NewMessage())))
|
|
|
|
}
|
|
|
|
return conv.PBValueOf(rv)
|
2018-10-17 11:46:52 -07:00
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
newMessage: conv.NewMessage,
|
2018-10-17 11:46:52 -07:00
|
|
|
}
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
|
2018-10-17 00:27:21 +00:00
|
|
|
ft := fs.Type
|
|
|
|
if ft.Kind() != reflect.Map {
|
|
|
|
panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
|
|
|
|
}
|
2019-05-22 13:42:54 -04:00
|
|
|
keyConv, _ := newConverter(ft.Key(), fd.MapKey().Kind())
|
|
|
|
valConv, _ := newConverter(ft.Elem(), fd.MapValue().Kind())
|
2019-04-25 23:48:08 -07:00
|
|
|
frozenEmpty := pref.ValueOf(frozenMap{
|
|
|
|
pvalue.MapOf(reflect.Zero(reflect.PtrTo(fs.Type)).Interface(), keyConv, valConv),
|
|
|
|
})
|
|
|
|
|
2018-10-17 00:27:21 +00:00
|
|
|
// TODO: Implement unsafe fast path?
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldOffset := offsetOf(fs)
|
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() {
|
2019-04-25 23:48:08 -07:00
|
|
|
return frozenEmpty
|
2018-12-01 04:57:09 -08:00
|
|
|
}
|
2019-04-25 23:48:08 -07:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
if rv.IsNil() {
|
|
|
|
return frozenEmpty
|
|
|
|
}
|
|
|
|
return pref.ValueOf(pvalue.MapOf(rv.Addr().Interface(), keyConv, valConv))
|
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()
|
2018-11-29 14:54:05 -08:00
|
|
|
rv.Set(reflect.ValueOf(v.Map().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
mutable: func(p pointer) pref.Value {
|
|
|
|
v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
|
|
|
|
return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
all: rename Vector as List
The terminology Vector does not occur in protobuf documentation at all,
so we should rename the Go use of the term to something more recognizable.
As such, all instances that match the regexp "[Vv]ect(or)?" were replaced.
The C++ documentation uses the term "Repeated", which is a reasonable name.
However, the term became overloaded in 2014, when maps were added as a feature
and implementated under the hood as repeated fields. This is confusing as it
means "repeated" could either refer to repeated fields proper (i.e., explicitly
marked with the "repeated" label in the proto file) or map fields. In the case
of the C++ reflective API, this is not a problem since repeated fields proper
and map fields are interacted with through the same RepeatedField type.
In Go, we do not use a single type to handle both types of repeated fields:
1) We are coming up with the Go protobuf reflection API for the first time
and so do not need to piggy-back on the repeated fields API to remain backwards
compatible since no former usages of Go protobuf reflection exists.
2) Map fields are commonly represented in Go as the Go map type, which do not
preserve ordering information. As such it is fundamentally impossible to present
an unordered map as a consistently ordered list. Thus, Go needs two different
interfaces for lists and maps.
Given the above situation, "Repeated" is not a great term to use since it
refers to two different things (when we only want one of the meanings).
To distinguish between the two, we'll use the terms "List" and "Map" instead.
There is some precedence for the term "List" in the protobuf codebase
(e.g., "getRepeatedInt32List").
Change-Id: Iddcdb6b78e1e60c14fa4ca213c15f45e214b967b
Reviewed-on: https://go-review.googlesource.com/c/149657
Reviewed-by: Damien Neil <dneil@google.com>
2018-11-14 14:05:19 -08:00
|
|
|
func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
|
2018-09-13 13:24:35 -07:00
|
|
|
ft := fs.Type
|
|
|
|
if ft.Kind() != reflect.Slice {
|
|
|
|
panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
|
|
|
|
}
|
2019-05-22 13:42:54 -04:00
|
|
|
conv, _ := newConverter(ft.Elem(), fd.Kind())
|
2019-04-25 23:48:08 -07:00
|
|
|
frozenEmpty := pref.ValueOf(frozenList{
|
|
|
|
pvalue.ListOf(reflect.Zero(reflect.PtrTo(fs.Type)).Interface(), conv),
|
|
|
|
})
|
|
|
|
|
2018-09-13 13:24:35 -07:00
|
|
|
// TODO: Implement unsafe fast path?
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldOffset := offsetOf(fs)
|
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() {
|
2019-04-25 23:48:08 -07:00
|
|
|
return frozenEmpty
|
2018-12-01 04:57:09 -08:00
|
|
|
}
|
2019-04-25 23:48:08 -07:00
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
if rv.Len() == 0 {
|
|
|
|
return frozenEmpty
|
|
|
|
}
|
|
|
|
return pref.ValueOf(pvalue.ListOf(rv.Addr().Interface(), conv))
|
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()
|
2018-11-29 14:54:05 -08:00
|
|
|
rv.Set(reflect.ValueOf(v.List().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
mutable: func(p pointer) pref.Value {
|
|
|
|
v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
|
|
|
|
return pref.ValueOf(pvalue.ListOf(v, conv))
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-12 16:20:37 -07:00
|
|
|
var emptyBytes = reflect.ValueOf([]byte{})
|
|
|
|
|
|
|
|
func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
|
|
|
|
ft := fs.Type
|
|
|
|
nullable := fd.Syntax() == pref.Proto2
|
|
|
|
if nullable {
|
|
|
|
if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
|
|
|
|
panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
|
|
|
|
}
|
|
|
|
if ft.Kind() == reflect.Ptr {
|
|
|
|
ft = ft.Elem()
|
|
|
|
}
|
|
|
|
}
|
2019-05-22 13:42:54 -04:00
|
|
|
conv, _ := newConverter(ft, fd.Kind())
|
2019-04-25 23:48:08 -07:00
|
|
|
|
2018-09-12 16:20:37 -07:00
|
|
|
// TODO: Implement unsafe fast path?
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldOffset := offsetOf(fs)
|
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:
|
|
|
|
panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
|
|
|
|
}
|
|
|
|
},
|
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() {
|
|
|
|
return defaultValueOf(fd)
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
2018-09-12 16:20:37 -07:00
|
|
|
if nullable {
|
|
|
|
if rv.IsNil() {
|
2018-12-01 04:57:09 -08:00
|
|
|
return defaultValueOf(fd)
|
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))
|
2018-09-12 16:20:37 -07:00
|
|
|
if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
|
|
|
|
rv.Set(emptyBytes)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
|
2018-10-19 16:27:46 -07:00
|
|
|
ft := fs.Type
|
2019-05-22 13:42:54 -04:00
|
|
|
conv, _ := newConverter(ft, fd.Kind())
|
2019-04-25 23:48:08 -07:00
|
|
|
frozenEmpty := pref.ValueOf(frozenMessage{conv.NewMessage()})
|
|
|
|
|
|
|
|
// TODO: Implement unsafe fast path?
|
|
|
|
fieldOffset := offsetOf(fs)
|
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() {
|
2019-04-25 23:48:08 -07:00
|
|
|
return frozenEmpty
|
2018-12-01 04:57:09 -08:00
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
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() {
|
2019-04-25 23:48:08 -07:00
|
|
|
return frozenEmpty
|
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-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() {
|
|
|
|
panic("invalid nil pointer")
|
|
|
|
}
|
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() {
|
|
|
|
rv.Set(conv.GoValueOf(pref.ValueOf(conv.NewMessage())))
|
|
|
|
}
|
|
|
|
return conv.PBValueOf(rv)
|
2018-10-19 16:27:46 -07:00
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
newMessage: conv.NewMessage,
|
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
|
|
|
}
|
|
|
|
|
|
|
|
func makeOneofInfo(od pref.OneofDescriptor, fs reflect.StructField, wrappersByType map[reflect.Type]pref.FieldNumber) *oneofInfo {
|
|
|
|
fieldOffset := offsetOf(fs)
|
|
|
|
return &oneofInfo{
|
2019-04-25 23:48:08 -07:00
|
|
|
oneofDesc: od,
|
2019-04-03 13:40:53 -07:00
|
|
|
which: func(p pointer) pref.FieldNumber {
|
|
|
|
if p.IsNil() {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
|
|
|
if rv.IsNil() {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return wrappersByType[rv.Elem().Type().Elem()]
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2019-05-22 00:42:45 -04:00
|
|
|
|
2019-05-22 13:42:54 -04:00
|
|
|
var (
|
|
|
|
enumIfaceV2 = reflect.TypeOf((*pref.Enum)(nil)).Elem()
|
|
|
|
messageIfaceV1 = reflect.TypeOf((*piface.MessageV1)(nil)).Elem()
|
|
|
|
messageIfaceV2 = reflect.TypeOf((*pref.ProtoMessage)(nil)).Elem()
|
|
|
|
)
|
|
|
|
|
|
|
|
func newConverter(t reflect.Type, k pref.Kind) (conv pvalue.Converter, isLegacy bool) {
|
|
|
|
switch k {
|
|
|
|
case pref.EnumKind:
|
|
|
|
if t.Kind() == reflect.Int32 && !t.Implements(enumIfaceV2) {
|
|
|
|
return pvalue.Converter{
|
|
|
|
PBValueOf: func(v reflect.Value) pref.Value {
|
|
|
|
if v.Type() != t {
|
|
|
|
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), t))
|
|
|
|
}
|
|
|
|
return pref.ValueOf(pref.EnumNumber(v.Int()))
|
|
|
|
},
|
|
|
|
GoValueOf: func(v pref.Value) reflect.Value {
|
|
|
|
return reflect.ValueOf(v.Enum()).Convert(t)
|
|
|
|
},
|
|
|
|
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
|
|
|
return legacyWrapEnum(reflect.ValueOf(n).Convert(t))
|
|
|
|
},
|
|
|
|
}, true
|
|
|
|
}
|
|
|
|
case pref.MessageKind, pref.GroupKind:
|
|
|
|
if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV1) && !t.Implements(messageIfaceV2) {
|
|
|
|
return pvalue.Converter{
|
|
|
|
PBValueOf: func(v reflect.Value) pref.Value {
|
|
|
|
if v.Type() != t {
|
|
|
|
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), t))
|
|
|
|
}
|
|
|
|
return pref.ValueOf(Export{}.MessageOf(v.Interface()))
|
|
|
|
},
|
|
|
|
GoValueOf: func(v pref.Value) reflect.Value {
|
|
|
|
rv := reflect.ValueOf(v.Message().(pvalue.Unwrapper).ProtoUnwrap())
|
|
|
|
if rv.Type() != t {
|
|
|
|
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), t))
|
|
|
|
}
|
|
|
|
return rv
|
|
|
|
},
|
|
|
|
NewMessage: func() pref.Message {
|
|
|
|
return legacyWrapMessage(reflect.New(t.Elem())).ProtoReflect()
|
|
|
|
},
|
|
|
|
}, true
|
|
|
|
}
|
2019-05-22 00:42:45 -04:00
|
|
|
}
|
2019-05-22 13:42:54 -04:00
|
|
|
return pvalue.NewConverter(t, k), false
|
2019-05-22 00:42:45 -04:00
|
|
|
}
|
2019-04-25 23:48:08 -07:00
|
|
|
|
|
|
|
// defaultValueOf returns the default value for the field.
|
|
|
|
func defaultValueOf(fd pref.FieldDescriptor) pref.Value {
|
|
|
|
if fd == nil {
|
|
|
|
return pref.Value{}
|
|
|
|
}
|
|
|
|
pv := fd.Default() // invalid Value for messages and repeated fields
|
|
|
|
if fd.Kind() == pref.BytesKind && pv.IsValid() && len(pv.Bytes()) > 0 {
|
|
|
|
return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
|
|
|
|
}
|
|
|
|
return pv
|
|
|
|
}
|
|
|
|
|
|
|
|
// frozenValueOf returns a frozen version of any composite value.
|
|
|
|
func frozenValueOf(v pref.Value) pref.Value {
|
|
|
|
switch v := v.Interface().(type) {
|
|
|
|
case pref.Message:
|
|
|
|
if _, ok := v.(frozenMessage); !ok {
|
|
|
|
return pref.ValueOf(frozenMessage{v})
|
|
|
|
}
|
|
|
|
case pref.List:
|
|
|
|
if _, ok := v.(frozenList); !ok {
|
|
|
|
return pref.ValueOf(frozenList{v})
|
|
|
|
}
|
|
|
|
case pref.Map:
|
|
|
|
if _, ok := v.(frozenMap); !ok {
|
|
|
|
return pref.ValueOf(frozenMap{v})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
type frozenMessage struct{ pref.Message }
|
|
|
|
|
|
|
|
func (m frozenMessage) ProtoReflect() pref.Message { return m }
|
|
|
|
func (m frozenMessage) Interface() pref.ProtoMessage { return m }
|
|
|
|
func (m frozenMessage) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
|
|
|
|
m.Message.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
|
|
|
|
return f(fd, frozenValueOf(v))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
func (m frozenMessage) Get(fd pref.FieldDescriptor) pref.Value {
|
|
|
|
v := m.Message.Get(fd)
|
|
|
|
return frozenValueOf(v)
|
|
|
|
}
|
|
|
|
func (frozenMessage) Clear(pref.FieldDescriptor) { panic("invalid on read-only Message") }
|
|
|
|
func (frozenMessage) Set(pref.FieldDescriptor, pref.Value) { panic("invalid on read-only Message") }
|
|
|
|
func (frozenMessage) Mutable(pref.FieldDescriptor) pref.Value { panic("invalid on read-only Message") }
|
|
|
|
func (frozenMessage) SetUnknown(pref.RawFields) { panic("invalid on read-only Message") }
|
|
|
|
|
|
|
|
type frozenList struct{ pref.List }
|
|
|
|
|
|
|
|
func (ls frozenList) Get(i int) pref.Value {
|
|
|
|
v := ls.List.Get(i)
|
|
|
|
return frozenValueOf(v)
|
|
|
|
}
|
|
|
|
func (frozenList) Set(i int, v pref.Value) { panic("invalid on read-only List") }
|
|
|
|
func (frozenList) Append(v pref.Value) { panic("invalid on read-only List") }
|
|
|
|
func (frozenList) Truncate(i int) { panic("invalid on read-only List") }
|
|
|
|
|
|
|
|
type frozenMap struct{ pref.Map }
|
|
|
|
|
|
|
|
func (ms frozenMap) Get(k pref.MapKey) pref.Value {
|
|
|
|
v := ms.Map.Get(k)
|
|
|
|
return frozenValueOf(v)
|
|
|
|
}
|
|
|
|
func (ms frozenMap) Range(f func(pref.MapKey, pref.Value) bool) {
|
|
|
|
ms.Map.Range(func(k pref.MapKey, v pref.Value) bool {
|
|
|
|
return f(k, frozenValueOf(v))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
func (frozenMap) Set(k pref.MapKey, v pref.Value) { panic("invalid n read-only Map") }
|
|
|
|
func (frozenMap) Clear(k pref.MapKey) { panic("invalid on read-only Map") }
|