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.
|
|
|
|
|
2018-11-26 22:32:06 -08:00
|
|
|
package impl_test
|
2018-09-12 16:20:37 -07:00
|
|
|
|
|
|
|
import (
|
2018-09-13 13:24:35 -07:00
|
|
|
"fmt"
|
|
|
|
"math"
|
internal/fileinit: generate reflect data structures from raw descriptors
This CL takes a significantly different approach to generating support
for protobuf reflection. The previous approach involved generating a
large number of Go literals to represent the reflection information.
While that approach was correct, it resulted in too much binary bloat.
The approach taken here initializes the reflection information from
the raw descriptor proto, which is a relatively dense representation
of the protobuf reflection information. In order to keep initialization
cost low, several measures were taken:
* At program init, the bare minimum is parsed in order to initialize
naming information for enums, messages, extensions, and services declared
in the file. This is done because those top-level declarations are often
relevant for registration.
* Only upon first are most of the other data structures for protobuf
reflection actually initialized.
* Instead of using proto.Unmarshal, a hand-written unmarshaler is used.
This allows us to avoid a dependendency on the descriptor proto and also
because the API for the descriptor proto is fundamentally non-performant
since it requires an allocation for every primitive field.
At a high-level, the new implementation lives in internal/fileinit.
Several changes were made to other parts of the repository:
* cmd/protoc-gen-go:
* Stop compressing the raw descriptors. While compression does reduce
the size of the descriptors by approximately 2x, it is a pre-mature
optimization since the descriptors themselves are around 1% of the total
binary bloat that is due to generated protobufs.
* Seeding protobuf reflection from the raw descriptor significantly
simplifies the generator implementation since it is no longer responsible
for constructing a tree of Go literals to represent the same information.
* We remove the generation of the shadow types and instead call
protoimpl.MessageType.MessageOf. Unfortunately, this incurs an allocation
for every call to ProtoReflect since we need to allocate a tuple that wraps
a pointer to the message value, and a pointer to message type.
* internal/impl:
* We add a MessageType.GoType field and make it required that it is
set prior to first use. This is done so that we can avoid calling
MessageType.init except for when it is actually needed. The allows code
to call (*FooMessage)(nil).ProtoReflect().Type() without fearing that the
init code will run, possibly triggering a recursive deadlock (where the
init code depends on getting the Type of some dependency which may be
declared within the same file).
* internal/cmd/generate-types:
* The code to generate reflect/prototype/protofile_list_gen.go was copied
and altered to generated internal/fileinit.desc_list_gen.go.
At a high-level this CL adds significant technical complexity.
However, this is offset by several possible future changes:
* The prototype package can be drastically simplified. We can probably
reimplement internal/legacy to use internal/fileinit instead, allowing us
to drop another dependency on the prototype package. As a result, we can
probably delete most of the constructor types in that package.
* With the prototype package significantly pruned, and the fact that generated
code no longer depend on depends on that package, we can consider merging
what's left of prototype into protodesc.
Change-Id: I6090f023f2e1b6afaf62bd3ae883566242e30715
Reviewed-on: https://go-review.googlesource.com/c/158539
Reviewed-by: Herbie Ong <herbie@google.com>
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-01-18 09:32:24 -08:00
|
|
|
"reflect"
|
2018-09-13 13:24:35 -07:00
|
|
|
"strings"
|
2018-09-12 16:20:37 -07:00
|
|
|
"testing"
|
|
|
|
|
2018-11-14 21:59:49 -08:00
|
|
|
cmp "github.com/google/go-cmp/cmp"
|
|
|
|
cmpopts "github.com/google/go-cmp/cmp/cmpopts"
|
2019-06-06 13:01:53 -07:00
|
|
|
"google.golang.org/protobuf/encoding/prototext"
|
2019-05-13 23:55:40 -07:00
|
|
|
pimpl "google.golang.org/protobuf/internal/impl"
|
|
|
|
scalar "google.golang.org/protobuf/internal/scalar"
|
2019-06-06 13:01:53 -07:00
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
pdesc "google.golang.org/protobuf/reflect/protodesc"
|
2019-05-13 23:55:40 -07:00
|
|
|
pref "google.golang.org/protobuf/reflect/protoreflect"
|
2019-06-06 13:01:53 -07:00
|
|
|
"google.golang.org/protobuf/reflect/protoregistry"
|
2019-05-22 00:42:45 -04:00
|
|
|
"google.golang.org/protobuf/reflect/prototype"
|
2018-09-12 16:20:37 -07:00
|
|
|
|
2019-05-13 23:55:40 -07:00
|
|
|
proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
|
2019-05-16 12:47:20 -07:00
|
|
|
"google.golang.org/protobuf/types/descriptorpb"
|
2018-09-13 13:24:35 -07: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
|
|
|
// List of test operations to perform on messages, lists, or maps.
|
2018-09-13 13:24:35 -07:00
|
|
|
type (
|
2018-11-14 21:59:49 -08:00
|
|
|
messageOp interface{ isMessageOp() }
|
2018-09-13 13:24:35 -07:00
|
|
|
messageOps []messageOp
|
|
|
|
|
2018-11-14 21:59:49 -08:00
|
|
|
listOp interface{ isListOp() }
|
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
|
|
|
listOps []listOp
|
2018-09-13 13:24:35 -07:00
|
|
|
|
2018-11-14 21:59:49 -08:00
|
|
|
mapOp interface{ isMapOp() }
|
2018-10-17 00:27:21 +00:00
|
|
|
mapOps []mapOp
|
2018-09-13 13:24:35 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
// Test operations performed on a message.
|
|
|
|
type (
|
2018-11-14 21:59:49 -08:00
|
|
|
// check that the message contents match
|
|
|
|
equalMessage struct{ pref.Message }
|
|
|
|
// check presence for specific fields in the message
|
|
|
|
hasFields map[pref.FieldNumber]bool
|
|
|
|
// check that specific message fields match
|
|
|
|
getFields map[pref.FieldNumber]pref.Value
|
|
|
|
// set specific message fields
|
|
|
|
setFields map[pref.FieldNumber]pref.Value
|
|
|
|
// clear specific fields in the message
|
|
|
|
clearFields []pref.FieldNumber
|
2019-04-03 13:40:53 -07:00
|
|
|
// check for the presence of specific oneof member fields.
|
|
|
|
whichOneofs map[pref.Name]pref.FieldNumber
|
2018-11-14 21:59:49 -08:00
|
|
|
// apply messageOps on each specified message field
|
2019-04-25 23:48:08 -07:00
|
|
|
messageFields map[pref.FieldNumber]messageOps
|
|
|
|
messageFieldsMutable map[pref.FieldNumber]messageOps
|
2018-11-14 21:59:49 -08:00
|
|
|
// apply listOps on each specified list field
|
2019-04-25 23:48:08 -07:00
|
|
|
listFields map[pref.FieldNumber]listOps
|
|
|
|
listFieldsMutable map[pref.FieldNumber]listOps
|
2018-11-14 21:59:49 -08:00
|
|
|
// apply mapOps on each specified map fields
|
2019-04-25 23:48:08 -07:00
|
|
|
mapFields map[pref.FieldNumber]mapOps
|
|
|
|
mapFieldsMutable map[pref.FieldNumber]mapOps
|
2018-11-14 21:59:49 -08:00
|
|
|
// range through all fields and check that they match
|
|
|
|
rangeFields map[pref.FieldNumber]pref.Value
|
2018-09-12 16:20:37 -07:00
|
|
|
)
|
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
func (equalMessage) isMessageOp() {}
|
|
|
|
func (hasFields) isMessageOp() {}
|
|
|
|
func (getFields) isMessageOp() {}
|
|
|
|
func (setFields) isMessageOp() {}
|
|
|
|
func (clearFields) isMessageOp() {}
|
|
|
|
func (whichOneofs) isMessageOp() {}
|
|
|
|
func (messageFields) isMessageOp() {}
|
|
|
|
func (messageFieldsMutable) isMessageOp() {}
|
|
|
|
func (listFields) isMessageOp() {}
|
|
|
|
func (listFieldsMutable) isMessageOp() {}
|
|
|
|
func (mapFields) isMessageOp() {}
|
|
|
|
func (mapFieldsMutable) isMessageOp() {}
|
|
|
|
func (rangeFields) isMessageOp() {}
|
2018-11-14 21:59:49 -08: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
|
|
|
// Test operations performed on a list.
|
2018-09-13 13:24:35 -07:00
|
|
|
type (
|
2018-11-14 21:59:49 -08:00
|
|
|
// check that the list contents match
|
|
|
|
equalList struct{ pref.List }
|
|
|
|
// check that list length matches
|
|
|
|
lenList int
|
|
|
|
// check that specific list entries match
|
|
|
|
getList map[int]pref.Value
|
|
|
|
// set specific list entries
|
|
|
|
setList map[int]pref.Value
|
|
|
|
// append entries to the list
|
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
|
|
|
appendList []pref.Value
|
2018-11-14 21:59:49 -08:00
|
|
|
// apply messageOps on a newly appended message
|
|
|
|
appendMessageList messageOps
|
|
|
|
// truncate the list to the specified length
|
|
|
|
truncList int
|
2018-09-13 13:24:35 -07:00
|
|
|
)
|
|
|
|
|
2018-11-14 21:59:49 -08:00
|
|
|
func (equalList) isListOp() {}
|
|
|
|
func (lenList) isListOp() {}
|
|
|
|
func (getList) isListOp() {}
|
|
|
|
func (setList) isListOp() {}
|
|
|
|
func (appendList) isListOp() {}
|
|
|
|
func (appendMessageList) isListOp() {}
|
|
|
|
func (truncList) isListOp() {}
|
|
|
|
|
2018-10-17 00:27:21 +00:00
|
|
|
// Test operations performed on a map.
|
|
|
|
type (
|
2018-11-14 21:59:49 -08:00
|
|
|
// check that the map contents match
|
|
|
|
equalMap struct{ pref.Map }
|
|
|
|
// check that map length matches
|
|
|
|
lenMap int
|
|
|
|
// check presence for specific entries in the map
|
|
|
|
hasMap map[interface{}]bool
|
|
|
|
// check that specific map entries match
|
|
|
|
getMap map[interface{}]pref.Value
|
|
|
|
// set specific map entries
|
|
|
|
setMap map[interface{}]pref.Value
|
|
|
|
// clear specific entries in the map
|
|
|
|
clearMap []interface{}
|
|
|
|
// apply messageOps on each specified message entry
|
|
|
|
messageMap map[interface{}]messageOps
|
|
|
|
// range through all entries and check that they match
|
2018-10-17 00:27:21 +00:00
|
|
|
rangeMap map[interface{}]pref.Value
|
|
|
|
)
|
|
|
|
|
2018-11-14 21:59:49 -08:00
|
|
|
func (equalMap) isMapOp() {}
|
|
|
|
func (lenMap) isMapOp() {}
|
|
|
|
func (hasMap) isMapOp() {}
|
|
|
|
func (getMap) isMapOp() {}
|
|
|
|
func (setMap) isMapOp() {}
|
|
|
|
func (clearMap) isMapOp() {}
|
|
|
|
func (messageMap) isMapOp() {}
|
|
|
|
func (rangeMap) isMapOp() {}
|
|
|
|
|
2018-10-19 16:27:46 -07:00
|
|
|
type ScalarProto2 struct {
|
|
|
|
Bool *bool `protobuf:"1"`
|
|
|
|
Int32 *int32 `protobuf:"2"`
|
|
|
|
Int64 *int64 `protobuf:"3"`
|
|
|
|
Uint32 *uint32 `protobuf:"4"`
|
|
|
|
Uint64 *uint64 `protobuf:"5"`
|
|
|
|
Float32 *float32 `protobuf:"6"`
|
|
|
|
Float64 *float64 `protobuf:"7"`
|
|
|
|
String *string `protobuf:"8"`
|
|
|
|
StringA []byte `protobuf:"9"`
|
|
|
|
Bytes []byte `protobuf:"10"`
|
|
|
|
BytesA *string `protobuf:"11"`
|
|
|
|
|
|
|
|
MyBool *MyBool `protobuf:"12"`
|
|
|
|
MyInt32 *MyInt32 `protobuf:"13"`
|
|
|
|
MyInt64 *MyInt64 `protobuf:"14"`
|
|
|
|
MyUint32 *MyUint32 `protobuf:"15"`
|
|
|
|
MyUint64 *MyUint64 `protobuf:"16"`
|
|
|
|
MyFloat32 *MyFloat32 `protobuf:"17"`
|
|
|
|
MyFloat64 *MyFloat64 `protobuf:"18"`
|
|
|
|
MyString *MyString `protobuf:"19"`
|
|
|
|
MyStringA MyBytes `protobuf:"20"`
|
|
|
|
MyBytes MyBytes `protobuf:"21"`
|
|
|
|
MyBytesA *MyString `protobuf:"22"`
|
|
|
|
}
|
2018-09-13 13:24:35 -07:00
|
|
|
|
2019-06-06 13:01:53 -07:00
|
|
|
func mustMakeEnumDesc(path string, syntax pref.Syntax, enumDesc string) pref.EnumDescriptor {
|
|
|
|
s := fmt.Sprintf(`name:%q syntax:%q enum_type:[{%s}]`, path, syntax, enumDesc)
|
|
|
|
pb := new(descriptorpb.FileDescriptorProto)
|
|
|
|
if err := prototext.Unmarshal([]byte(s), pb); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
fd, err := pdesc.NewFile(pb, nil)
|
2018-11-14 21:59:49 -08:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2019-06-06 13:01:53 -07:00
|
|
|
return fd.Enums().Get(0)
|
2018-11-14 21:59:49 -08:00
|
|
|
}
|
|
|
|
|
2019-06-06 13:01:53 -07:00
|
|
|
func mustMakeMessageDesc(path string, syntax pref.Syntax, fileDesc, msgDesc string, r pdesc.Resolver) pref.MessageDescriptor {
|
|
|
|
s := fmt.Sprintf(`name:%q syntax:%q %s message_type:[{%s}]`, path, syntax, fileDesc, msgDesc)
|
|
|
|
pb := new(descriptorpb.FileDescriptorProto)
|
|
|
|
if err := prototext.Unmarshal([]byte(s), pb); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
fd, err := pdesc.NewFile(pb, r)
|
2018-11-14 21:59:49 -08:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2019-06-06 13:01:53 -07:00
|
|
|
return fd.Messages().Get(0)
|
2018-11-14 21:59:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
var V = pref.ValueOf
|
|
|
|
var VE = func(n pref.EnumNumber) pref.Value { return V(n) }
|
|
|
|
|
|
|
|
type (
|
|
|
|
MyBool bool
|
|
|
|
MyInt32 int32
|
|
|
|
MyInt64 int64
|
|
|
|
MyUint32 uint32
|
|
|
|
MyUint64 uint64
|
|
|
|
MyFloat32 float32
|
|
|
|
MyFloat64 float64
|
|
|
|
MyString string
|
|
|
|
MyBytes []byte
|
|
|
|
|
|
|
|
ListStrings []MyString
|
|
|
|
ListBytes []MyBytes
|
|
|
|
|
|
|
|
MapStrings map[MyString]MyString
|
|
|
|
MapBytes map[MyString]MyBytes
|
|
|
|
)
|
|
|
|
|
2019-05-22 00:42:45 -04:00
|
|
|
var scalarProto2Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto2)), PBType: &prototype.Message{
|
2019-06-06 13:01:53 -07:00
|
|
|
MessageDescriptor: mustMakeMessageDesc("scalar2.proto", pref.Proto2, "", `
|
|
|
|
name: "ScalarProto2"
|
|
|
|
field: [
|
|
|
|
{name:"f1" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL default_value:"true"},
|
|
|
|
{name:"f2" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 default_value:"2"},
|
|
|
|
{name:"f3" number:3 label:LABEL_OPTIONAL type:TYPE_INT64 default_value:"3"},
|
|
|
|
{name:"f4" number:4 label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"4"},
|
|
|
|
{name:"f5" number:5 label:LABEL_OPTIONAL type:TYPE_UINT64 default_value:"5"},
|
|
|
|
{name:"f6" number:6 label:LABEL_OPTIONAL type:TYPE_FLOAT default_value:"6"},
|
|
|
|
{name:"f7" number:7 label:LABEL_OPTIONAL type:TYPE_DOUBLE default_value:"7"},
|
|
|
|
{name:"f8" number:8 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"8"},
|
|
|
|
{name:"f9" number:9 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"9"},
|
|
|
|
{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"10"},
|
|
|
|
{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"11"},
|
|
|
|
|
|
|
|
{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_BOOL default_value:"true"},
|
|
|
|
{name:"f13" number:13 label:LABEL_OPTIONAL type:TYPE_INT32 default_value:"13"},
|
|
|
|
{name:"f14" number:14 label:LABEL_OPTIONAL type:TYPE_INT64 default_value:"14"},
|
|
|
|
{name:"f15" number:15 label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"15"},
|
|
|
|
{name:"f16" number:16 label:LABEL_OPTIONAL type:TYPE_UINT64 default_value:"16"},
|
|
|
|
{name:"f17" number:17 label:LABEL_OPTIONAL type:TYPE_FLOAT default_value:"17"},
|
|
|
|
{name:"f18" number:18 label:LABEL_OPTIONAL type:TYPE_DOUBLE default_value:"18"},
|
|
|
|
{name:"f19" number:19 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"19"},
|
|
|
|
{name:"f20" number:20 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"20"},
|
|
|
|
{name:"f21" number:21 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"21"},
|
|
|
|
{name:"f22" number:22 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"22"}
|
|
|
|
]
|
|
|
|
`, nil),
|
2019-05-22 00:42:45 -04:00
|
|
|
NewMessage: func() pref.Message {
|
2019-04-25 23:48:08 -07:00
|
|
|
return pref.ProtoMessage(new(ScalarProto2)).ProtoReflect()
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
}}
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
func (m *ScalarProto2) ProtoReflect() pref.Message { return scalarProto2Type.MessageOf(m) }
|
2018-09-13 13:24:35 -07:00
|
|
|
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
func TestScalarProto2(t *testing.T) {
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, new(ScalarProto2).ProtoReflect(), messageOps{
|
2018-09-13 13:24:35 -07:00
|
|
|
hasFields{
|
|
|
|
1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
|
|
|
|
12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
|
|
|
|
},
|
|
|
|
getFields{
|
|
|
|
1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V([]byte("10")), 11: V([]byte("11")),
|
|
|
|
12: V(bool(true)), 13: V(int32(13)), 14: V(int64(14)), 15: V(uint32(15)), 16: V(uint64(16)), 17: V(float32(17)), 18: V(float64(18)), 19: V(string("19")), 20: V(string("20")), 21: V([]byte("21")), 22: V([]byte("22")),
|
|
|
|
},
|
|
|
|
setFields{
|
|
|
|
1: V(bool(false)), 2: V(int32(0)), 3: V(int64(0)), 4: V(uint32(0)), 5: V(uint64(0)), 6: V(float32(0)), 7: V(float64(0)), 8: V(string("")), 9: V(string("")), 10: V([]byte(nil)), 11: V([]byte(nil)),
|
|
|
|
12: V(bool(false)), 13: V(int32(0)), 14: V(int64(0)), 15: V(uint32(0)), 16: V(uint64(0)), 17: V(float32(0)), 18: V(float64(0)), 19: V(string("")), 20: V(string("")), 21: V([]byte(nil)), 22: V([]byte(nil)),
|
|
|
|
},
|
|
|
|
hasFields{
|
|
|
|
1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true,
|
|
|
|
12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true,
|
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMessage{(&ScalarProto2{
|
2018-09-13 13:24:35 -07:00
|
|
|
new(bool), new(int32), new(int64), new(uint32), new(uint64), new(float32), new(float64), new(string), []byte{}, []byte{}, new(string),
|
|
|
|
new(MyBool), new(MyInt32), new(MyInt64), new(MyUint32), new(MyUint64), new(MyFloat32), new(MyFloat64), new(MyString), MyBytes{}, MyBytes{}, new(MyString),
|
2019-04-25 23:48:08 -07:00
|
|
|
}).ProtoReflect()},
|
2018-11-14 21:59:49 -08:00
|
|
|
clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMessage{new(ScalarProto2).ProtoReflect()},
|
2018-09-13 13:24:35 -07:00
|
|
|
})
|
2018-12-01 04:57:09 -08:00
|
|
|
|
|
|
|
// Test read-only operations on nil message.
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, (*ScalarProto2)(nil).ProtoReflect(), messageOps{
|
2018-12-01 04:57:09 -08:00
|
|
|
hasFields{
|
|
|
|
1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
|
|
|
|
12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
|
|
|
|
},
|
|
|
|
getFields{
|
|
|
|
1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V([]byte("10")), 11: V([]byte("11")),
|
|
|
|
12: V(bool(true)), 13: V(int32(13)), 14: V(int64(14)), 15: V(uint32(15)), 16: V(uint64(16)), 17: V(float32(17)), 18: V(float64(18)), 19: V(string("19")), 20: V(string("20")), 21: V([]byte("21")), 22: V([]byte("22")),
|
|
|
|
},
|
|
|
|
})
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
|
2018-10-19 16:27:46 -07:00
|
|
|
type ScalarProto3 struct {
|
|
|
|
Bool bool `protobuf:"1"`
|
|
|
|
Int32 int32 `protobuf:"2"`
|
|
|
|
Int64 int64 `protobuf:"3"`
|
|
|
|
Uint32 uint32 `protobuf:"4"`
|
|
|
|
Uint64 uint64 `protobuf:"5"`
|
|
|
|
Float32 float32 `protobuf:"6"`
|
|
|
|
Float64 float64 `protobuf:"7"`
|
|
|
|
String string `protobuf:"8"`
|
|
|
|
StringA []byte `protobuf:"9"`
|
|
|
|
Bytes []byte `protobuf:"10"`
|
|
|
|
BytesA string `protobuf:"11"`
|
|
|
|
|
|
|
|
MyBool MyBool `protobuf:"12"`
|
|
|
|
MyInt32 MyInt32 `protobuf:"13"`
|
|
|
|
MyInt64 MyInt64 `protobuf:"14"`
|
|
|
|
MyUint32 MyUint32 `protobuf:"15"`
|
|
|
|
MyUint64 MyUint64 `protobuf:"16"`
|
|
|
|
MyFloat32 MyFloat32 `protobuf:"17"`
|
|
|
|
MyFloat64 MyFloat64 `protobuf:"18"`
|
|
|
|
MyString MyString `protobuf:"19"`
|
|
|
|
MyStringA MyBytes `protobuf:"20"`
|
|
|
|
MyBytes MyBytes `protobuf:"21"`
|
|
|
|
MyBytesA MyString `protobuf:"22"`
|
|
|
|
}
|
2018-09-13 13:24:35 -07:00
|
|
|
|
2019-05-22 00:42:45 -04:00
|
|
|
var scalarProto3Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto3)), PBType: &prototype.Message{
|
2019-06-06 13:01:53 -07:00
|
|
|
MessageDescriptor: mustMakeMessageDesc("scalar3.proto", pref.Proto3, "", `
|
|
|
|
name: "ScalarProto3"
|
|
|
|
field: [
|
|
|
|
{name:"f1" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL},
|
|
|
|
{name:"f2" number:2 label:LABEL_OPTIONAL type:TYPE_INT32},
|
|
|
|
{name:"f3" number:3 label:LABEL_OPTIONAL type:TYPE_INT64},
|
|
|
|
{name:"f4" number:4 label:LABEL_OPTIONAL type:TYPE_UINT32},
|
|
|
|
{name:"f5" number:5 label:LABEL_OPTIONAL type:TYPE_UINT64},
|
|
|
|
{name:"f6" number:6 label:LABEL_OPTIONAL type:TYPE_FLOAT},
|
|
|
|
{name:"f7" number:7 label:LABEL_OPTIONAL type:TYPE_DOUBLE},
|
|
|
|
{name:"f8" number:8 label:LABEL_OPTIONAL type:TYPE_STRING},
|
|
|
|
{name:"f9" number:9 label:LABEL_OPTIONAL type:TYPE_STRING},
|
|
|
|
{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_BYTES},
|
|
|
|
{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_BYTES},
|
|
|
|
|
|
|
|
{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_BOOL},
|
|
|
|
{name:"f13" number:13 label:LABEL_OPTIONAL type:TYPE_INT32},
|
|
|
|
{name:"f14" number:14 label:LABEL_OPTIONAL type:TYPE_INT64},
|
|
|
|
{name:"f15" number:15 label:LABEL_OPTIONAL type:TYPE_UINT32},
|
|
|
|
{name:"f16" number:16 label:LABEL_OPTIONAL type:TYPE_UINT64},
|
|
|
|
{name:"f17" number:17 label:LABEL_OPTIONAL type:TYPE_FLOAT},
|
|
|
|
{name:"f18" number:18 label:LABEL_OPTIONAL type:TYPE_DOUBLE},
|
|
|
|
{name:"f19" number:19 label:LABEL_OPTIONAL type:TYPE_STRING},
|
|
|
|
{name:"f20" number:20 label:LABEL_OPTIONAL type:TYPE_STRING},
|
|
|
|
{name:"f21" number:21 label:LABEL_OPTIONAL type:TYPE_BYTES},
|
|
|
|
{name:"f22" number:22 label:LABEL_OPTIONAL type:TYPE_BYTES}
|
|
|
|
]
|
|
|
|
`, nil),
|
2019-05-22 00:42:45 -04:00
|
|
|
NewMessage: func() pref.Message {
|
2019-04-25 23:48:08 -07:00
|
|
|
return pref.ProtoMessage(new(ScalarProto3)).ProtoReflect()
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
}}
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
func (m *ScalarProto3) ProtoReflect() pref.Message { return scalarProto3Type.MessageOf(m) }
|
2018-09-13 13:24:35 -07:00
|
|
|
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
func TestScalarProto3(t *testing.T) {
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, new(ScalarProto3).ProtoReflect(), messageOps{
|
2018-09-13 13:24:35 -07:00
|
|
|
hasFields{
|
|
|
|
1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
|
|
|
|
12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
|
|
|
|
},
|
|
|
|
getFields{
|
|
|
|
1: V(bool(false)), 2: V(int32(0)), 3: V(int64(0)), 4: V(uint32(0)), 5: V(uint64(0)), 6: V(float32(0)), 7: V(float64(0)), 8: V(string("")), 9: V(string("")), 10: V([]byte(nil)), 11: V([]byte(nil)),
|
|
|
|
12: V(bool(false)), 13: V(int32(0)), 14: V(int64(0)), 15: V(uint32(0)), 16: V(uint64(0)), 17: V(float32(0)), 18: V(float64(0)), 19: V(string("")), 20: V(string("")), 21: V([]byte(nil)), 22: V([]byte(nil)),
|
|
|
|
},
|
|
|
|
setFields{
|
|
|
|
1: V(bool(false)), 2: V(int32(0)), 3: V(int64(0)), 4: V(uint32(0)), 5: V(uint64(0)), 6: V(float32(0)), 7: V(float64(0)), 8: V(string("")), 9: V(string("")), 10: V([]byte(nil)), 11: V([]byte(nil)),
|
|
|
|
12: V(bool(false)), 13: V(int32(0)), 14: V(int64(0)), 15: V(uint32(0)), 16: V(uint64(0)), 17: V(float32(0)), 18: V(float64(0)), 19: V(string("")), 20: V(string("")), 21: V([]byte(nil)), 22: V([]byte(nil)),
|
|
|
|
},
|
|
|
|
hasFields{
|
|
|
|
1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
|
|
|
|
12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
|
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMessage{new(ScalarProto3).ProtoReflect()},
|
2018-09-13 13:24:35 -07:00
|
|
|
setFields{
|
|
|
|
1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V([]byte("10")), 11: V([]byte("11")),
|
|
|
|
12: V(bool(true)), 13: V(int32(13)), 14: V(int64(14)), 15: V(uint32(15)), 16: V(uint64(16)), 17: V(float32(17)), 18: V(float64(18)), 19: V(string("19")), 20: V(string("20")), 21: V([]byte("21")), 22: V([]byte("22")),
|
|
|
|
},
|
|
|
|
hasFields{
|
|
|
|
1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true,
|
|
|
|
12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true,
|
|
|
|
},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMessage{(&ScalarProto3{
|
2018-09-13 13:24:35 -07:00
|
|
|
true, 2, 3, 4, 5, 6, 7, "8", []byte("9"), []byte("10"), "11",
|
|
|
|
true, 13, 14, 15, 16, 17, 18, "19", []byte("20"), []byte("21"), "22",
|
2019-04-25 23:48:08 -07:00
|
|
|
}).ProtoReflect()},
|
2018-11-19 15:27:09 -08:00
|
|
|
setFields{
|
|
|
|
2: V(int32(-2)), 3: V(int64(-3)), 6: V(float32(math.Inf(-1))), 7: V(float64(math.NaN())),
|
|
|
|
},
|
|
|
|
hasFields{
|
|
|
|
2: true, 3: true, 6: true, 7: true,
|
|
|
|
},
|
2018-11-14 21:59:49 -08:00
|
|
|
clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMessage{new(ScalarProto3).ProtoReflect()},
|
2019-04-22 11:44:49 -07:00
|
|
|
|
|
|
|
// Verify that -0 triggers proper Has behavior.
|
|
|
|
hasFields{6: false, 7: false},
|
|
|
|
setFields{6: V(float32(math.Copysign(0, -1))), 7: V(float64(math.Copysign(0, -1)))},
|
|
|
|
hasFields{6: true, 7: true},
|
2018-09-13 13:24:35 -07:00
|
|
|
})
|
2018-12-01 04:57:09 -08:00
|
|
|
|
|
|
|
// Test read-only operations on nil message.
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, (*ScalarProto3)(nil).ProtoReflect(), messageOps{
|
2018-12-01 04:57:09 -08:00
|
|
|
hasFields{
|
|
|
|
1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
|
|
|
|
12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
|
|
|
|
},
|
|
|
|
getFields{
|
|
|
|
1: V(bool(false)), 2: V(int32(0)), 3: V(int64(0)), 4: V(uint32(0)), 5: V(uint64(0)), 6: V(float32(0)), 7: V(float64(0)), 8: V(string("")), 9: V(string("")), 10: V([]byte(nil)), 11: V([]byte(nil)),
|
|
|
|
12: V(bool(false)), 13: V(int32(0)), 14: V(int64(0)), 15: V(uint32(0)), 16: V(uint64(0)), 17: V(float32(0)), 18: V(float64(0)), 19: V(string("")), 20: V(string("")), 21: V([]byte(nil)), 22: V([]byte(nil)),
|
|
|
|
},
|
|
|
|
})
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
|
|
|
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
type ListScalars struct {
|
2018-10-19 16:27:46 -07:00
|
|
|
Bools []bool `protobuf:"1"`
|
|
|
|
Int32s []int32 `protobuf:"2"`
|
|
|
|
Int64s []int64 `protobuf:"3"`
|
|
|
|
Uint32s []uint32 `protobuf:"4"`
|
|
|
|
Uint64s []uint64 `protobuf:"5"`
|
|
|
|
Float32s []float32 `protobuf:"6"`
|
|
|
|
Float64s []float64 `protobuf:"7"`
|
|
|
|
Strings []string `protobuf:"8"`
|
|
|
|
StringsA [][]byte `protobuf:"9"`
|
|
|
|
Bytes [][]byte `protobuf:"10"`
|
|
|
|
BytesA []string `protobuf:"11"`
|
|
|
|
|
|
|
|
MyStrings1 []MyString `protobuf:"12"`
|
|
|
|
MyStrings2 []MyBytes `protobuf:"13"`
|
|
|
|
MyBytes1 []MyBytes `protobuf:"14"`
|
|
|
|
MyBytes2 []MyString `protobuf:"15"`
|
|
|
|
|
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
|
|
|
MyStrings3 ListStrings `protobuf:"16"`
|
|
|
|
MyStrings4 ListBytes `protobuf:"17"`
|
|
|
|
MyBytes3 ListBytes `protobuf:"18"`
|
|
|
|
MyBytes4 ListStrings `protobuf:"19"`
|
2018-10-19 16:27:46 -07:00
|
|
|
}
|
2018-09-13 13:24:35 -07:00
|
|
|
|
2019-05-22 00:42:45 -04:00
|
|
|
var listScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ListScalars)), PBType: &prototype.Message{
|
2019-06-06 13:01:53 -07:00
|
|
|
MessageDescriptor: mustMakeMessageDesc("list-scalars.proto", pref.Proto2, "", `
|
|
|
|
name: "ListScalars"
|
|
|
|
field: [
|
|
|
|
{name:"f1" number:1 label:LABEL_REPEATED type:TYPE_BOOL},
|
|
|
|
{name:"f2" number:2 label:LABEL_REPEATED type:TYPE_INT32},
|
|
|
|
{name:"f3" number:3 label:LABEL_REPEATED type:TYPE_INT64},
|
|
|
|
{name:"f4" number:4 label:LABEL_REPEATED type:TYPE_UINT32},
|
|
|
|
{name:"f5" number:5 label:LABEL_REPEATED type:TYPE_UINT64},
|
|
|
|
{name:"f6" number:6 label:LABEL_REPEATED type:TYPE_FLOAT},
|
|
|
|
{name:"f7" number:7 label:LABEL_REPEATED type:TYPE_DOUBLE},
|
|
|
|
{name:"f8" number:8 label:LABEL_REPEATED type:TYPE_STRING},
|
|
|
|
{name:"f9" number:9 label:LABEL_REPEATED type:TYPE_STRING},
|
|
|
|
{name:"f10" number:10 label:LABEL_REPEATED type:TYPE_BYTES},
|
|
|
|
{name:"f11" number:11 label:LABEL_REPEATED type:TYPE_BYTES},
|
|
|
|
|
|
|
|
{name:"f12" number:12 label:LABEL_REPEATED type:TYPE_STRING},
|
|
|
|
{name:"f13" number:13 label:LABEL_REPEATED type:TYPE_STRING},
|
|
|
|
{name:"f14" number:14 label:LABEL_REPEATED type:TYPE_BYTES},
|
|
|
|
{name:"f15" number:15 label:LABEL_REPEATED type:TYPE_BYTES},
|
|
|
|
|
|
|
|
{name:"f16" number:16 label:LABEL_REPEATED type:TYPE_STRING},
|
|
|
|
{name:"f17" number:17 label:LABEL_REPEATED type:TYPE_STRING},
|
|
|
|
{name:"f18" number:18 label:LABEL_REPEATED type:TYPE_BYTES},
|
|
|
|
{name:"f19" number:19 label:LABEL_REPEATED type:TYPE_BYTES}
|
|
|
|
]
|
|
|
|
`, nil),
|
2019-05-22 00:42:45 -04:00
|
|
|
NewMessage: func() pref.Message {
|
2019-04-25 23:48:08 -07:00
|
|
|
return pref.ProtoMessage(new(ListScalars)).ProtoReflect()
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
}}
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
func (m *ListScalars) ProtoReflect() pref.Message { return listScalarsType.MessageOf(m) }
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
|
|
|
|
func TestListScalars(t *testing.T) {
|
2019-04-25 23:48:08 -07:00
|
|
|
empty := new(ListScalars).ProtoReflect()
|
|
|
|
want := (&ListScalars{
|
2018-09-13 13:24:35 -07:00
|
|
|
Bools: []bool{true, false, true},
|
|
|
|
Int32s: []int32{2, math.MinInt32, math.MaxInt32},
|
|
|
|
Int64s: []int64{3, math.MinInt64, math.MaxInt64},
|
|
|
|
Uint32s: []uint32{4, math.MaxUint32 / 2, math.MaxUint32},
|
|
|
|
Uint64s: []uint64{5, math.MaxUint64 / 2, math.MaxUint64},
|
|
|
|
Float32s: []float32{6, math.SmallestNonzeroFloat32, float32(math.NaN()), math.MaxFloat32},
|
|
|
|
Float64s: []float64{7, math.SmallestNonzeroFloat64, float64(math.NaN()), math.MaxFloat64},
|
|
|
|
Strings: []string{"8", "", "eight"},
|
|
|
|
StringsA: [][]byte{[]byte("9"), nil, []byte("nine")},
|
|
|
|
Bytes: [][]byte{[]byte("10"), nil, []byte("ten")},
|
|
|
|
BytesA: []string{"11", "", "eleven"},
|
|
|
|
|
|
|
|
MyStrings1: []MyString{"12", "", "twelve"},
|
|
|
|
MyStrings2: []MyBytes{[]byte("13"), nil, []byte("thirteen")},
|
|
|
|
MyBytes1: []MyBytes{[]byte("14"), nil, []byte("fourteen")},
|
|
|
|
MyBytes2: []MyString{"15", "", "fifteen"},
|
|
|
|
|
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
|
|
|
MyStrings3: ListStrings{"16", "", "sixteen"},
|
|
|
|
MyStrings4: ListBytes{[]byte("17"), nil, []byte("seventeen")},
|
|
|
|
MyBytes3: ListBytes{[]byte("18"), nil, []byte("eighteen")},
|
|
|
|
MyBytes4: ListStrings{"19", "", "nineteen"},
|
2019-04-25 23:48:08 -07:00
|
|
|
}).ProtoReflect()
|
2018-09-13 13:24:35 -07:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, new(ListScalars).ProtoReflect(), messageOps{
|
2018-09-13 13:24:35 -07:00
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false},
|
2019-04-25 23:48:08 -07:00
|
|
|
getFields{1: getField(empty, 1), 3: getField(empty, 3), 5: getField(empty, 5), 7: getField(empty, 7), 9: getField(empty, 9), 11: getField(empty, 11), 13: getField(empty, 13), 15: getField(empty, 15), 17: getField(empty, 17), 19: getField(empty, 19)},
|
|
|
|
setFields{1: getField(want, 1), 3: getField(want, 3), 5: getField(want, 5), 7: getField(want, 7), 9: getField(want, 9), 11: getField(want, 11), 13: getField(want, 13), 15: getField(want, 15), 17: getField(want, 17), 19: getField(want, 19)},
|
|
|
|
listFieldsMutable{
|
2018-09-13 13:24:35 -07:00
|
|
|
2: {
|
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
|
|
|
lenList(0),
|
|
|
|
appendList{V(int32(2)), V(int32(math.MinInt32)), V(int32(math.MaxInt32))},
|
|
|
|
getList{0: V(int32(2)), 1: V(int32(math.MinInt32)), 2: V(int32(math.MaxInt32))},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalList{getField(want, 2).List()},
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
4: {
|
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
|
|
|
appendList{V(uint32(0)), V(uint32(0)), V(uint32(0))},
|
|
|
|
setList{0: V(uint32(4)), 1: V(uint32(math.MaxUint32 / 2)), 2: V(uint32(math.MaxUint32))},
|
|
|
|
lenList(3),
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
6: {
|
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
|
|
|
appendList{V(float32(6)), V(float32(math.SmallestNonzeroFloat32)), V(float32(math.NaN())), V(float32(math.MaxFloat32))},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalList{getField(want, 6).List()},
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
8: {
|
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
|
|
|
appendList{V(""), V(""), V(""), V(""), V(""), V("")},
|
|
|
|
lenList(6),
|
|
|
|
setList{0: V("8"), 2: V("eight")},
|
|
|
|
truncList(3),
|
2019-04-25 23:48:08 -07:00
|
|
|
equalList{getField(want, 8).List()},
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
10: {
|
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
|
|
|
appendList{V([]byte(nil)), V([]byte(nil))},
|
|
|
|
setList{0: V([]byte("10"))},
|
|
|
|
appendList{V([]byte("wrong"))},
|
|
|
|
setList{2: V([]byte("ten"))},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalList{getField(want, 10).List()},
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
12: {
|
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
|
|
|
appendList{V("12"), V("wrong"), V("twelve")},
|
|
|
|
setList{1: V("")},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalList{getField(want, 12).List()},
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
14: {
|
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
|
|
|
appendList{V([]byte("14")), V([]byte(nil)), V([]byte("fourteen"))},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalList{getField(want, 14).List()},
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
16: {
|
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
|
|
|
appendList{V("16"), V(""), V("sixteen"), V("extra")},
|
|
|
|
truncList(3),
|
2019-04-25 23:48:08 -07:00
|
|
|
equalList{getField(want, 16).List()},
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
|
|
|
18: {
|
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
|
|
|
appendList{V([]byte("18")), V([]byte(nil)), V([]byte("eighteen"))},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalList{getField(want, 18).List()},
|
2018-09-13 13:24:35 -07:00
|
|
|
},
|
2018-09-12 16:20:37 -07:00
|
|
|
},
|
2018-09-13 13:24:35 -07:00
|
|
|
hasFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true},
|
2018-11-14 21:59:49 -08:00
|
|
|
equalMessage{want},
|
|
|
|
clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19},
|
|
|
|
equalMessage{empty},
|
2018-10-17 00:27:21 +00:00
|
|
|
})
|
2018-12-01 04:57:09 -08:00
|
|
|
|
|
|
|
// Test read-only operations on nil message.
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, (*ListScalars)(nil).ProtoReflect(), messageOps{
|
2018-12-01 04:57:09 -08:00
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false},
|
|
|
|
listFields{2: {lenList(0)}, 4: {lenList(0)}, 6: {lenList(0)}, 8: {lenList(0)}, 10: {lenList(0)}, 12: {lenList(0)}, 14: {lenList(0)}, 16: {lenList(0)}, 18: {lenList(0)}},
|
|
|
|
})
|
2018-10-17 00:27:21 +00:00
|
|
|
}
|
|
|
|
|
2018-10-19 16:27:46 -07:00
|
|
|
type MapScalars struct {
|
|
|
|
KeyBools map[bool]string `protobuf:"1"`
|
|
|
|
KeyInt32s map[int32]string `protobuf:"2"`
|
|
|
|
KeyInt64s map[int64]string `protobuf:"3"`
|
|
|
|
KeyUint32s map[uint32]string `protobuf:"4"`
|
|
|
|
KeyUint64s map[uint64]string `protobuf:"5"`
|
|
|
|
KeyStrings map[string]string `protobuf:"6"`
|
|
|
|
|
|
|
|
ValBools map[string]bool `protobuf:"7"`
|
|
|
|
ValInt32s map[string]int32 `protobuf:"8"`
|
|
|
|
ValInt64s map[string]int64 `protobuf:"9"`
|
|
|
|
ValUint32s map[string]uint32 `protobuf:"10"`
|
|
|
|
ValUint64s map[string]uint64 `protobuf:"11"`
|
|
|
|
ValFloat32s map[string]float32 `protobuf:"12"`
|
|
|
|
ValFloat64s map[string]float64 `protobuf:"13"`
|
|
|
|
ValStrings map[string]string `protobuf:"14"`
|
|
|
|
ValStringsA map[string][]byte `protobuf:"15"`
|
|
|
|
ValBytes map[string][]byte `protobuf:"16"`
|
|
|
|
ValBytesA map[string]string `protobuf:"17"`
|
|
|
|
|
|
|
|
MyStrings1 map[MyString]MyString `protobuf:"18"`
|
|
|
|
MyStrings2 map[MyString]MyBytes `protobuf:"19"`
|
|
|
|
MyBytes1 map[MyString]MyBytes `protobuf:"20"`
|
|
|
|
MyBytes2 map[MyString]MyString `protobuf:"21"`
|
|
|
|
|
|
|
|
MyStrings3 MapStrings `protobuf:"22"`
|
|
|
|
MyStrings4 MapBytes `protobuf:"23"`
|
|
|
|
MyBytes3 MapBytes `protobuf:"24"`
|
|
|
|
MyBytes4 MapStrings `protobuf:"25"`
|
|
|
|
}
|
2018-10-17 00:27:21 +00:00
|
|
|
|
2019-05-22 00:42:45 -04:00
|
|
|
var mapScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(MapScalars)), PBType: &prototype.Message{
|
2019-06-06 13:01:53 -07:00
|
|
|
MessageDescriptor: mustMakeMessageDesc("map-scalars.proto", pref.Proto2, "", `
|
|
|
|
name: "MapScalars"
|
|
|
|
field: [
|
|
|
|
{name:"f1" number:1 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F1Entry"},
|
|
|
|
{name:"f2" number:2 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F2Entry"},
|
|
|
|
{name:"f3" number:3 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F3Entry"},
|
|
|
|
{name:"f4" number:4 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F4Entry"},
|
|
|
|
{name:"f5" number:5 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F5Entry"},
|
|
|
|
{name:"f6" number:6 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F6Entry"},
|
|
|
|
|
|
|
|
{name:"f7" number:7 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F7Entry"},
|
|
|
|
{name:"f8" number:8 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F8Entry"},
|
|
|
|
{name:"f9" number:9 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F9Entry"},
|
|
|
|
{name:"f10" number:10 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F10Entry"},
|
|
|
|
{name:"f11" number:11 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F11Entry"},
|
|
|
|
{name:"f12" number:12 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F12Entry"},
|
|
|
|
{name:"f13" number:13 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F13Entry"},
|
|
|
|
{name:"f14" number:14 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F14Entry"},
|
|
|
|
{name:"f15" number:15 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F15Entry"},
|
|
|
|
{name:"f16" number:16 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F16Entry"},
|
|
|
|
{name:"f17" number:17 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F17Entry"},
|
|
|
|
|
|
|
|
{name:"f18" number:18 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F18Entry"},
|
|
|
|
{name:"f19" number:19 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F19Entry"},
|
|
|
|
{name:"f20" number:20 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F20Entry"},
|
|
|
|
{name:"f21" number:21 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F21Entry"},
|
|
|
|
|
|
|
|
{name:"f22" number:22 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F22Entry"},
|
|
|
|
{name:"f23" number:23 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F23Entry"},
|
|
|
|
{name:"f24" number:24 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F24Entry"},
|
|
|
|
{name:"f25" number:25 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F25Entry"}
|
|
|
|
]
|
|
|
|
nested_type: [
|
|
|
|
{name:"F1Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F2Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_INT32}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F3Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_INT64}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F4Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_UINT32}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F5Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_UINT64}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F6Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
|
|
|
|
{name:"F7Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BOOL}] options:{map_entry:true}},
|
|
|
|
{name:"F8Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_INT32}] options:{map_entry:true}},
|
|
|
|
{name:"F9Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_INT64}] options:{map_entry:true}},
|
|
|
|
{name:"F10Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_UINT32}] options:{map_entry:true}},
|
|
|
|
{name:"F11Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_UINT64}] options:{map_entry:true}},
|
|
|
|
{name:"F12Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_FLOAT}] options:{map_entry:true}},
|
|
|
|
{name:"F13Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_DOUBLE}] options:{map_entry:true}},
|
|
|
|
{name:"F14Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F15Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F16Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BYTES}] options:{map_entry:true}},
|
|
|
|
{name:"F17Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BYTES}] options:{map_entry:true}},
|
|
|
|
|
|
|
|
{name:"F18Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F19Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F20Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BYTES}] options:{map_entry:true}},
|
|
|
|
{name:"F21Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BYTES}] options:{map_entry:true}},
|
|
|
|
|
|
|
|
{name:"F22Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F23Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
|
|
|
|
{name:"F24Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BYTES}] options:{map_entry:true}},
|
|
|
|
{name:"F25Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BYTES}] options:{map_entry:true}}
|
|
|
|
]
|
|
|
|
`, nil),
|
2019-05-22 00:42:45 -04:00
|
|
|
NewMessage: func() pref.Message {
|
2019-04-25 23:48:08 -07:00
|
|
|
return pref.ProtoMessage(new(MapScalars)).ProtoReflect()
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
}}
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
func (m *MapScalars) ProtoReflect() pref.Message { return mapScalarsType.MessageOf(m) }
|
2018-10-17 00:27:21 +00:00
|
|
|
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
func TestMapScalars(t *testing.T) {
|
2019-04-25 23:48:08 -07:00
|
|
|
empty := new(MapScalars).ProtoReflect()
|
|
|
|
want := (&MapScalars{
|
2018-10-17 00:27:21 +00:00
|
|
|
KeyBools: map[bool]string{true: "true", false: "false"},
|
|
|
|
KeyInt32s: map[int32]string{0: "zero", -1: "one", 2: "two"},
|
|
|
|
KeyInt64s: map[int64]string{0: "zero", -10: "ten", 20: "twenty"},
|
|
|
|
KeyUint32s: map[uint32]string{0: "zero", 1: "one", 2: "two"},
|
|
|
|
KeyUint64s: map[uint64]string{0: "zero", 10: "ten", 20: "twenty"},
|
|
|
|
KeyStrings: map[string]string{"": "", "foo": "bar"},
|
|
|
|
|
|
|
|
ValBools: map[string]bool{"true": true, "false": false},
|
|
|
|
ValInt32s: map[string]int32{"one": 1, "two": 2, "three": 3},
|
|
|
|
ValInt64s: map[string]int64{"ten": 10, "twenty": -20, "thirty": 30},
|
|
|
|
ValUint32s: map[string]uint32{"0x00": 0x00, "0xff": 0xff, "0xdead": 0xdead},
|
|
|
|
ValUint64s: map[string]uint64{"0x00": 0x00, "0xff": 0xff, "0xdead": 0xdead},
|
|
|
|
ValFloat32s: map[string]float32{"nan": float32(math.NaN()), "pi": float32(math.Pi)},
|
|
|
|
ValFloat64s: map[string]float64{"nan": float64(math.NaN()), "pi": float64(math.Pi)},
|
|
|
|
ValStrings: map[string]string{"s1": "s1", "s2": "s2"},
|
|
|
|
ValStringsA: map[string][]byte{"s1": []byte("s1"), "s2": []byte("s2")},
|
|
|
|
ValBytes: map[string][]byte{"s1": []byte("s1"), "s2": []byte("s2")},
|
|
|
|
ValBytesA: map[string]string{"s1": "s1", "s2": "s2"},
|
|
|
|
|
|
|
|
MyStrings1: map[MyString]MyString{"s1": "s1", "s2": "s2"},
|
|
|
|
MyStrings2: map[MyString]MyBytes{"s1": []byte("s1"), "s2": []byte("s2")},
|
|
|
|
MyBytes1: map[MyString]MyBytes{"s1": []byte("s1"), "s2": []byte("s2")},
|
|
|
|
MyBytes2: map[MyString]MyString{"s1": "s1", "s2": "s2"},
|
|
|
|
|
|
|
|
MyStrings3: MapStrings{"s1": "s1", "s2": "s2"},
|
|
|
|
MyStrings4: MapBytes{"s1": []byte("s1"), "s2": []byte("s2")},
|
|
|
|
MyBytes3: MapBytes{"s1": []byte("s1"), "s2": []byte("s2")},
|
|
|
|
MyBytes4: MapStrings{"s1": "s1", "s2": "s2"},
|
2019-04-25 23:48:08 -07:00
|
|
|
}).ProtoReflect()
|
2018-10-17 00:27:21 +00:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, new(MapScalars).ProtoReflect(), messageOps{
|
2018-10-17 00:27:21 +00:00
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false, 23: false, 24: false, 25: false},
|
2019-04-25 23:48:08 -07:00
|
|
|
getFields{1: getField(empty, 1), 3: getField(empty, 3), 5: getField(empty, 5), 7: getField(empty, 7), 9: getField(empty, 9), 11: getField(empty, 11), 13: getField(empty, 13), 15: getField(empty, 15), 17: getField(empty, 17), 19: getField(empty, 19), 21: getField(empty, 21), 23: getField(empty, 23), 25: getField(empty, 25)},
|
|
|
|
setFields{1: getField(want, 1), 3: getField(want, 3), 5: getField(want, 5), 7: getField(want, 7), 9: getField(want, 9), 11: getField(want, 11), 13: getField(want, 13), 15: getField(want, 15), 17: getField(want, 17), 19: getField(want, 19), 21: getField(want, 21), 23: getField(want, 23), 25: getField(want, 25)},
|
|
|
|
mapFieldsMutable{
|
2018-10-17 00:27:21 +00:00
|
|
|
2: {
|
|
|
|
lenMap(0),
|
|
|
|
hasMap{int32(0): false, int32(-1): false, int32(2): false},
|
|
|
|
setMap{int32(0): V("zero")},
|
|
|
|
lenMap(1),
|
|
|
|
hasMap{int32(0): true, int32(-1): false, int32(2): false},
|
|
|
|
setMap{int32(-1): V("one")},
|
|
|
|
lenMap(2),
|
|
|
|
hasMap{int32(0): true, int32(-1): true, int32(2): false},
|
|
|
|
setMap{int32(2): V("two")},
|
|
|
|
lenMap(3),
|
|
|
|
hasMap{int32(0): true, int32(-1): true, int32(2): true},
|
|
|
|
},
|
|
|
|
4: {
|
|
|
|
setMap{uint32(0): V("zero"), uint32(1): V("one"), uint32(2): V("two")},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMap{getField(want, 4).Map()},
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
|
|
|
6: {
|
2018-11-14 21:59:49 -08:00
|
|
|
clearMap{"noexist"},
|
2018-10-17 00:27:21 +00:00
|
|
|
setMap{"foo": V("bar")},
|
|
|
|
setMap{"": V("empty")},
|
|
|
|
getMap{"": V("empty"), "foo": V("bar"), "noexist": V(nil)},
|
|
|
|
setMap{"": V(""), "extra": V("extra")},
|
2018-11-14 21:59:49 -08:00
|
|
|
clearMap{"extra", "noexist"},
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
|
|
|
8: {
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMap{getField(empty, 8).Map()},
|
2018-10-17 00:27:21 +00:00
|
|
|
setMap{"one": V(int32(1)), "two": V(int32(2)), "three": V(int32(3))},
|
|
|
|
},
|
|
|
|
10: {
|
|
|
|
setMap{"0x00": V(uint32(0x00)), "0xff": V(uint32(0xff)), "0xdead": V(uint32(0xdead))},
|
|
|
|
lenMap(3),
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMap{getField(want, 10).Map()},
|
2018-10-17 00:27:21 +00:00
|
|
|
getMap{"0x00": V(uint32(0x00)), "0xff": V(uint32(0xff)), "0xdead": V(uint32(0xdead)), "0xdeadbeef": V(nil)},
|
|
|
|
},
|
|
|
|
12: {
|
|
|
|
setMap{"nan": V(float32(math.NaN())), "pi": V(float32(math.Pi)), "e": V(float32(math.E))},
|
2018-11-14 21:59:49 -08:00
|
|
|
clearMap{"e", "phi"},
|
2018-10-17 00:27:21 +00:00
|
|
|
rangeMap{"nan": V(float32(math.NaN())), "pi": V(float32(math.Pi))},
|
|
|
|
},
|
|
|
|
14: {
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMap{getField(empty, 14).Map()},
|
2018-10-17 00:27:21 +00:00
|
|
|
setMap{"s1": V("s1"), "s2": V("s2")},
|
|
|
|
},
|
|
|
|
16: {
|
|
|
|
setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMap{getField(want, 16).Map()},
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
|
|
|
18: {
|
|
|
|
hasMap{"s1": false, "s2": false, "s3": false},
|
|
|
|
setMap{"s1": V("s1"), "s2": V("s2")},
|
|
|
|
hasMap{"s1": true, "s2": true, "s3": false},
|
|
|
|
},
|
|
|
|
20: {
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMap{getField(empty, 20).Map()},
|
2018-10-17 00:27:21 +00:00
|
|
|
setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))},
|
|
|
|
},
|
|
|
|
22: {
|
|
|
|
rangeMap{},
|
|
|
|
setMap{"s1": V("s1"), "s2": V("s2")},
|
|
|
|
rangeMap{"s1": V("s1"), "s2": V("s2")},
|
|
|
|
lenMap(2),
|
|
|
|
},
|
|
|
|
24: {
|
|
|
|
setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMap{getField(want, 24).Map()},
|
2018-10-17 00:27:21 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
hasFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true, 23: true, 24: true, 25: true},
|
2018-11-14 21:59:49 -08:00
|
|
|
equalMessage{want},
|
|
|
|
clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
|
|
equalMessage{empty},
|
2018-09-13 13:24:35 -07:00
|
|
|
})
|
2018-12-01 04:57:09 -08:00
|
|
|
|
|
|
|
// Test read-only operations on nil message.
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, (*MapScalars)(nil).ProtoReflect(), messageOps{
|
2018-12-01 04:57:09 -08:00
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false, 23: false, 24: false, 25: false},
|
|
|
|
mapFields{2: {lenMap(0)}, 4: {lenMap(0)}, 6: {lenMap(0)}, 8: {lenMap(0)}, 10: {lenMap(0)}, 12: {lenMap(0)}, 14: {lenMap(0)}, 16: {lenMap(0)}, 18: {lenMap(0)}, 20: {lenMap(0)}, 22: {lenMap(0)}, 24: {lenMap(0)}},
|
|
|
|
})
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
|
|
|
|
2018-11-14 21:59:49 -08:00
|
|
|
type OneofScalars struct {
|
|
|
|
Union isOneofScalars_Union `protobuf_oneof:"union"`
|
|
|
|
}
|
2018-10-17 11:46:52 -07:00
|
|
|
|
2019-05-22 00:42:45 -04:00
|
|
|
var oneofScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(OneofScalars)), PBType: &prototype.Message{
|
2019-06-06 13:01:53 -07:00
|
|
|
MessageDescriptor: mustMakeMessageDesc("oneof-scalars.proto", pref.Proto2, "", `
|
|
|
|
name: "OneofScalars"
|
|
|
|
field: [
|
|
|
|
{name:"f1" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL default_value:"true" oneof_index:0},
|
|
|
|
{name:"f2" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 default_value:"2" oneof_index:0},
|
|
|
|
{name:"f3" number:3 label:LABEL_OPTIONAL type:TYPE_INT64 default_value:"3" oneof_index:0},
|
|
|
|
{name:"f4" number:4 label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"4" oneof_index:0},
|
|
|
|
{name:"f5" number:5 label:LABEL_OPTIONAL type:TYPE_UINT64 default_value:"5" oneof_index:0},
|
|
|
|
{name:"f6" number:6 label:LABEL_OPTIONAL type:TYPE_FLOAT default_value:"6" oneof_index:0},
|
|
|
|
{name:"f7" number:7 label:LABEL_OPTIONAL type:TYPE_DOUBLE default_value:"7" oneof_index:0},
|
|
|
|
{name:"f8" number:8 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"8" oneof_index:0},
|
|
|
|
{name:"f9" number:9 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"9" oneof_index:0},
|
|
|
|
{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"10" oneof_index:0},
|
|
|
|
{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"11" oneof_index:0},
|
|
|
|
{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"12" oneof_index:0},
|
|
|
|
{name:"f13" number:13 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"13" oneof_index:0}
|
|
|
|
]
|
|
|
|
oneof_decl: [{name:"union"}]
|
|
|
|
`, nil),
|
2019-05-22 00:42:45 -04:00
|
|
|
NewMessage: func() pref.Message {
|
2019-04-25 23:48:08 -07:00
|
|
|
return pref.ProtoMessage(new(OneofScalars)).ProtoReflect()
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
}}
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
func (m *OneofScalars) ProtoReflect() pref.Message { return oneofScalarsType.MessageOf(m) }
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
|
2018-11-27 17:25:04 -08:00
|
|
|
func (*OneofScalars) XXX_OneofWrappers() []interface{} {
|
|
|
|
return []interface{}{
|
2018-10-17 11:46:52 -07:00
|
|
|
(*OneofScalars_Bool)(nil),
|
|
|
|
(*OneofScalars_Int32)(nil),
|
|
|
|
(*OneofScalars_Int64)(nil),
|
|
|
|
(*OneofScalars_Uint32)(nil),
|
|
|
|
(*OneofScalars_Uint64)(nil),
|
|
|
|
(*OneofScalars_Float32)(nil),
|
|
|
|
(*OneofScalars_Float64)(nil),
|
|
|
|
(*OneofScalars_String)(nil),
|
|
|
|
(*OneofScalars_StringA)(nil),
|
|
|
|
(*OneofScalars_StringB)(nil),
|
|
|
|
(*OneofScalars_Bytes)(nil),
|
|
|
|
(*OneofScalars_BytesA)(nil),
|
|
|
|
(*OneofScalars_BytesB)(nil),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 21:59:49 -08:00
|
|
|
type (
|
|
|
|
isOneofScalars_Union interface {
|
|
|
|
isOneofScalars_Union()
|
|
|
|
}
|
|
|
|
OneofScalars_Bool struct {
|
|
|
|
Bool bool `protobuf:"1"`
|
|
|
|
}
|
|
|
|
OneofScalars_Int32 struct {
|
|
|
|
Int32 MyInt32 `protobuf:"2"`
|
|
|
|
}
|
|
|
|
OneofScalars_Int64 struct {
|
|
|
|
Int64 int64 `protobuf:"3"`
|
|
|
|
}
|
|
|
|
OneofScalars_Uint32 struct {
|
|
|
|
Uint32 MyUint32 `protobuf:"4"`
|
|
|
|
}
|
|
|
|
OneofScalars_Uint64 struct {
|
|
|
|
Uint64 uint64 `protobuf:"5"`
|
|
|
|
}
|
|
|
|
OneofScalars_Float32 struct {
|
|
|
|
Float32 MyFloat32 `protobuf:"6"`
|
|
|
|
}
|
|
|
|
OneofScalars_Float64 struct {
|
|
|
|
Float64 float64 `protobuf:"7"`
|
|
|
|
}
|
|
|
|
OneofScalars_String struct {
|
|
|
|
String string `protobuf:"8"`
|
|
|
|
}
|
|
|
|
OneofScalars_StringA struct {
|
|
|
|
StringA []byte `protobuf:"9"`
|
|
|
|
}
|
|
|
|
OneofScalars_StringB struct {
|
|
|
|
StringB MyString `protobuf:"10"`
|
|
|
|
}
|
|
|
|
OneofScalars_Bytes struct {
|
|
|
|
Bytes []byte `protobuf:"11"`
|
|
|
|
}
|
|
|
|
OneofScalars_BytesA struct {
|
|
|
|
BytesA string `protobuf:"12"`
|
|
|
|
}
|
|
|
|
OneofScalars_BytesB struct {
|
|
|
|
BytesB MyBytes `protobuf:"13"`
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2018-10-17 11:46:52 -07:00
|
|
|
func (*OneofScalars_Bool) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_Int32) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_Int64) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_Uint32) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_Uint64) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_Float32) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_Float64) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_String) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_StringA) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_StringB) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_Bytes) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_BytesA) isOneofScalars_Union() {}
|
|
|
|
func (*OneofScalars_BytesB) isOneofScalars_Union() {}
|
|
|
|
|
|
|
|
func TestOneofs(t *testing.T) {
|
internal/impl: support legacy extension fields
Implement support for extension fields for messages that use the v1
data structures for extensions. The legacyExtensionFields type wraps a
v1 map to implement the v2 protoreflect.KnownFields interface.
Working on this change revealed a bug in the dynamic construction of
message types for protobuf messages that had cyclic dependencies (e.g.,
message Foo has a sub-field of message Bar, and Bar has a sub-field of Foo).
In such a situation, a deadlock occurs because initialization code depends on
the very initialization code that is currently running. To break these cycles,
we make some systematic changes listed in the following paragraphs.
Generally speaking, we separate the logic for construction and wrapping,
where constuction does not recursively rely on dependencies,
while wrapping may recursively inspect dependencies.
Promote the MessageType.MessageOf method as a standalone MessageOf function
that dynamically finds the proper *MessageType to use. We make it such that
MessageType only supports two forms of messages types:
* Those that fully implement the v2 API.
* Those that do not implement the v2 API at all.
This removes support for the hybrid form that was exploited by message_test.go
In impl/message_test.go, switch each message to look more like how future
generated messages will look like. This is done in reaction to the fact that
MessageType.MessageOf no longer exists.
In value/{map,vector}.go, fix Unwrap to return a pointer since the underlying
reflect.Value is addressable reference value, not a pointer value.
In value/convert.go, split the logic apart so that obtaining a v2 type and
wrapping a type as v2 are distinct operations. Wrapping requires further
initialization than simply creating the initial message type, and calling it
during initial construction would lead to a deadlock.
In protoreflect/go_type.go, we switch back to a lazy initialization of GoType
to avoid a deadlock since the user-provided fn may rely on the fact that
prototype.GoMessage returned.
Change-Id: I5dea00e36fe1a9899bd2ac0aed2c8e51d5d87420
Reviewed-on: https://go-review.googlesource.com/c/148826
Reviewed-by: Herbie Ong <herbie@google.com>
2018-11-06 13:05:20 -08:00
|
|
|
empty := &OneofScalars{}
|
|
|
|
want1 := &OneofScalars{Union: &OneofScalars_Bool{true}}
|
|
|
|
want2 := &OneofScalars{Union: &OneofScalars_Int32{20}}
|
|
|
|
want3 := &OneofScalars{Union: &OneofScalars_Int64{30}}
|
|
|
|
want4 := &OneofScalars{Union: &OneofScalars_Uint32{40}}
|
|
|
|
want5 := &OneofScalars{Union: &OneofScalars_Uint64{50}}
|
|
|
|
want6 := &OneofScalars{Union: &OneofScalars_Float32{60}}
|
|
|
|
want7 := &OneofScalars{Union: &OneofScalars_Float64{70}}
|
|
|
|
want8 := &OneofScalars{Union: &OneofScalars_String{string("80")}}
|
|
|
|
want9 := &OneofScalars{Union: &OneofScalars_StringA{[]byte("90")}}
|
|
|
|
want10 := &OneofScalars{Union: &OneofScalars_StringB{MyString("100")}}
|
|
|
|
want11 := &OneofScalars{Union: &OneofScalars_Bytes{[]byte("110")}}
|
|
|
|
want12 := &OneofScalars{Union: &OneofScalars_BytesA{string("120")}}
|
|
|
|
want13 := &OneofScalars{Union: &OneofScalars_BytesB{MyBytes("130")}}
|
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, new(OneofScalars).ProtoReflect(), messageOps{
|
2018-10-17 11:46:52 -07:00
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false},
|
|
|
|
getFields{1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V(string("10")), 11: V([]byte("11")), 12: V([]byte("12")), 13: V([]byte("13"))},
|
2019-04-25 23:48:08 -07:00
|
|
|
whichOneofs{"union": 0},
|
2018-10-17 11:46:52 -07:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
setFields{1: V(bool(true))}, hasFields{1: true}, equalMessage{want1.ProtoReflect()},
|
|
|
|
setFields{2: V(int32(20))}, hasFields{2: true}, equalMessage{want2.ProtoReflect()},
|
|
|
|
setFields{3: V(int64(30))}, hasFields{3: true}, equalMessage{want3.ProtoReflect()},
|
|
|
|
setFields{4: V(uint32(40))}, hasFields{4: true}, equalMessage{want4.ProtoReflect()},
|
|
|
|
setFields{5: V(uint64(50))}, hasFields{5: true}, equalMessage{want5.ProtoReflect()},
|
|
|
|
setFields{6: V(float32(60))}, hasFields{6: true}, equalMessage{want6.ProtoReflect()},
|
|
|
|
setFields{7: V(float64(70))}, hasFields{7: true}, equalMessage{want7.ProtoReflect()},
|
2019-04-03 13:40:53 -07:00
|
|
|
|
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: true, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false},
|
2019-04-25 23:48:08 -07:00
|
|
|
whichOneofs{"union": 7},
|
2019-04-03 13:40:53 -07:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
setFields{8: V(string("80"))}, hasFields{8: true}, equalMessage{want8.ProtoReflect()},
|
|
|
|
setFields{9: V(string("90"))}, hasFields{9: true}, equalMessage{want9.ProtoReflect()},
|
|
|
|
setFields{10: V(string("100"))}, hasFields{10: true}, equalMessage{want10.ProtoReflect()},
|
|
|
|
setFields{11: V([]byte("110"))}, hasFields{11: true}, equalMessage{want11.ProtoReflect()},
|
|
|
|
setFields{12: V([]byte("120"))}, hasFields{12: true}, equalMessage{want12.ProtoReflect()},
|
|
|
|
setFields{13: V([]byte("130"))}, hasFields{13: true}, equalMessage{want13.ProtoReflect()},
|
2018-10-17 11:46:52 -07:00
|
|
|
|
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: true},
|
|
|
|
getFields{1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V(string("10")), 11: V([]byte("11")), 12: V([]byte("12")), 13: V([]byte("130"))},
|
2018-11-14 21:59:49 -08:00
|
|
|
clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
|
2019-04-25 23:48:08 -07:00
|
|
|
whichOneofs{"union": 13},
|
|
|
|
equalMessage{want13.ProtoReflect()},
|
2018-11-14 21:59:49 -08:00
|
|
|
clearFields{13},
|
2019-04-25 23:48:08 -07:00
|
|
|
whichOneofs{"union": 0},
|
|
|
|
equalMessage{empty.ProtoReflect()},
|
2018-10-17 11:46:52 -07:00
|
|
|
})
|
2018-12-01 04:57:09 -08:00
|
|
|
|
|
|
|
// Test read-only operations on nil message.
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, (*OneofScalars)(nil).ProtoReflect(), messageOps{
|
2018-12-01 04:57:09 -08:00
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false},
|
|
|
|
getFields{1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V(string("10")), 11: V([]byte("11")), 12: V([]byte("12")), 13: V([]byte("13"))},
|
|
|
|
})
|
2018-10-17 11:46:52 -07:00
|
|
|
}
|
|
|
|
|
2018-11-14 21:59:49 -08:00
|
|
|
type EnumProto2 int32
|
|
|
|
|
2019-05-22 00:42:45 -04:00
|
|
|
var enumProto2Type = &prototype.Enum{
|
2019-06-06 13:01:53 -07:00
|
|
|
EnumDescriptor: mustMakeEnumDesc("enum2.proto", pref.Proto2, `
|
|
|
|
name: "EnumProto2"
|
|
|
|
value: [{name:"DEAD" number:0xdead}, {name:"BEEF" number:0xbeef}]
|
|
|
|
`),
|
2019-05-22 00:42:45 -04:00
|
|
|
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
2018-11-14 21:59:49 -08:00
|
|
|
return EnumProto2(n)
|
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
}
|
2018-11-14 21:59:49 -08:00
|
|
|
|
2019-05-01 12:29:25 -07:00
|
|
|
func (e EnumProto2) Descriptor() pref.EnumDescriptor { return enumProto2Type.Descriptor() }
|
|
|
|
func (e EnumProto2) Enum() *EnumProto2 { return &e }
|
|
|
|
func (e EnumProto2) Number() pref.EnumNumber { return pref.EnumNumber(e) }
|
2018-11-14 21:59:49 -08:00
|
|
|
|
|
|
|
type EnumProto3 int32
|
|
|
|
|
2019-05-22 00:42:45 -04:00
|
|
|
var enumProto3Type = &prototype.Enum{
|
2019-06-06 13:01:53 -07:00
|
|
|
EnumDescriptor: mustMakeEnumDesc("enum3.proto", pref.Proto3, `
|
|
|
|
name: "EnumProto3",
|
|
|
|
value: [{name:"ALPHA" number:0}, {name:"BRAVO" number:1}]
|
|
|
|
`),
|
2019-05-22 00:42:45 -04:00
|
|
|
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
2018-11-14 21:59:49 -08:00
|
|
|
return EnumProto3(n)
|
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
}
|
2018-11-14 21:59:49 -08:00
|
|
|
|
2019-05-01 12:29:25 -07:00
|
|
|
func (e EnumProto3) Descriptor() pref.EnumDescriptor { return enumProto3Type.Descriptor() }
|
|
|
|
func (e EnumProto3) Enum() *EnumProto3 { return &e }
|
|
|
|
func (e EnumProto3) Number() pref.EnumNumber { return pref.EnumNumber(e) }
|
2018-11-14 21:59:49 -08:00
|
|
|
|
|
|
|
type EnumMessages struct {
|
|
|
|
EnumP2 *EnumProto2 `protobuf:"1"`
|
|
|
|
EnumP3 *EnumProto3 `protobuf:"2"`
|
|
|
|
MessageLegacy *proto2_20180125.Message `protobuf:"3"`
|
|
|
|
MessageCycle *EnumMessages `protobuf:"4"`
|
|
|
|
EnumList []EnumProto2 `protobuf:"5"`
|
|
|
|
MessageList []*ScalarProto2 `protobuf:"6"`
|
|
|
|
EnumMap map[string]EnumProto3 `protobuf:"7"`
|
|
|
|
MessageMap map[string]*ScalarProto3 `protobuf:"8"`
|
|
|
|
Union isEnumMessages_Union `protobuf_oneof:"union"`
|
|
|
|
}
|
|
|
|
|
2019-05-22 00:42:45 -04:00
|
|
|
var enumMessagesType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(EnumMessages)), PBType: &prototype.Message{
|
2019-06-06 13:01:53 -07:00
|
|
|
MessageDescriptor: mustMakeMessageDesc("enum-messages.proto", pref.Proto2, `
|
|
|
|
dependency: ["enum2.proto", "enum3.proto", "scalar2.proto", "scalar3.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]
|
|
|
|
`, `
|
|
|
|
name: "EnumMessages"
|
|
|
|
field: [
|
|
|
|
{name:"f1" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".EnumProto2" default_value:"BEEF"},
|
|
|
|
{name:"f2" number:2 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".EnumProto3" default_value:"BRAVO"},
|
2019-06-24 19:21:46 -07:00
|
|
|
{name:"f3" number:3 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".google.golang.org.proto2_20180125.Message"},
|
|
|
|
{name:"f4" number:4 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".EnumMessages"},
|
2019-06-06 13:01:53 -07:00
|
|
|
{name:"f5" number:5 label:LABEL_REPEATED type:TYPE_ENUM type_name:".EnumProto2"},
|
|
|
|
{name:"f6" number:6 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".ScalarProto2"},
|
|
|
|
{name:"f7" number:7 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".EnumMessages.F7Entry"},
|
|
|
|
{name:"f8" number:8 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".EnumMessages.F8Entry"},
|
|
|
|
{name:"f9" number:9 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".EnumProto2" oneof_index:0 default_value:"BEEF"},
|
|
|
|
{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".EnumProto3" oneof_index:0 default_value:"BRAVO"},
|
|
|
|
{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".ScalarProto2" oneof_index:0},
|
|
|
|
{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".ScalarProto3" oneof_index:0}
|
|
|
|
]
|
|
|
|
oneof_decl: [{name:"union"}]
|
|
|
|
nested_type: [
|
|
|
|
{name:"F7Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".EnumProto3"}] options:{map_entry:true}},
|
|
|
|
{name:"F8Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".ScalarProto3"}] options:{map_entry:true}}
|
|
|
|
]
|
|
|
|
`, protoregistry.NewFiles(
|
|
|
|
EnumProto2(0).Descriptor().ParentFile(),
|
|
|
|
EnumProto3(0).Descriptor().ParentFile(),
|
|
|
|
((*ScalarProto2)(nil)).ProtoReflect().Descriptor().ParentFile(),
|
|
|
|
((*ScalarProto3)(nil)).ProtoReflect().Descriptor().ParentFile(),
|
|
|
|
pimpl.Export{}.MessageDescriptorOf((*proto2_20180125.Message)(nil)).ParentFile(),
|
|
|
|
)),
|
2019-05-22 00:42:45 -04:00
|
|
|
NewMessage: func() pref.Message {
|
2019-04-25 23:48:08 -07:00
|
|
|
return pref.ProtoMessage(new(EnumMessages)).ProtoReflect()
|
2018-11-14 21:59:49 -08:00
|
|
|
},
|
2019-05-22 00:42:45 -04:00
|
|
|
}}
|
2018-11-14 21:59:49 -08:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
func (m *EnumMessages) ProtoReflect() pref.Message { return enumMessagesType.MessageOf(m) }
|
2018-11-14 21:59:49 -08:00
|
|
|
|
2018-11-27 17:25:04 -08:00
|
|
|
func (*EnumMessages) XXX_OneofWrappers() []interface{} {
|
|
|
|
return []interface{}{
|
2018-11-14 21:59:49 -08:00
|
|
|
(*EnumMessages_OneofE2)(nil),
|
|
|
|
(*EnumMessages_OneofE3)(nil),
|
|
|
|
(*EnumMessages_OneofM2)(nil),
|
|
|
|
(*EnumMessages_OneofM3)(nil),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type (
|
|
|
|
isEnumMessages_Union interface {
|
|
|
|
isEnumMessages_Union()
|
|
|
|
}
|
|
|
|
EnumMessages_OneofE2 struct {
|
|
|
|
OneofE2 EnumProto2 `protobuf:"9"`
|
|
|
|
}
|
|
|
|
EnumMessages_OneofE3 struct {
|
|
|
|
OneofE3 EnumProto3 `protobuf:"10"`
|
|
|
|
}
|
|
|
|
EnumMessages_OneofM2 struct {
|
|
|
|
OneofM2 *ScalarProto2 `protobuf:"11"`
|
|
|
|
}
|
|
|
|
EnumMessages_OneofM3 struct {
|
|
|
|
OneofM3 *ScalarProto3 `protobuf:"12"`
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func (*EnumMessages_OneofE2) isEnumMessages_Union() {}
|
|
|
|
func (*EnumMessages_OneofE3) isEnumMessages_Union() {}
|
|
|
|
func (*EnumMessages_OneofM2) isEnumMessages_Union() {}
|
|
|
|
func (*EnumMessages_OneofM3) isEnumMessages_Union() {}
|
|
|
|
|
|
|
|
func TestEnumMessages(t *testing.T) {
|
2019-04-25 23:48:08 -07:00
|
|
|
emptyL := pimpl.Export{}.MessageOf(new(proto2_20180125.Message))
|
|
|
|
emptyM := new(EnumMessages).ProtoReflect()
|
|
|
|
emptyM2 := new(ScalarProto2).ProtoReflect()
|
|
|
|
emptyM3 := new(ScalarProto3).ProtoReflect()
|
|
|
|
|
2018-11-26 22:32:06 -08:00
|
|
|
wantL := pimpl.Export{}.MessageOf(&proto2_20180125.Message{OptionalFloat: scalar.Float32(math.E)})
|
2019-04-25 23:48:08 -07:00
|
|
|
wantM := (&EnumMessages{EnumP2: EnumProto2(1234).Enum()}).ProtoReflect()
|
2018-11-27 18:45:07 -08:00
|
|
|
wantM2a := &ScalarProto2{Float32: scalar.Float32(math.Pi)}
|
|
|
|
wantM2b := &ScalarProto2{Float32: scalar.Float32(math.Phi)}
|
2018-11-14 21:59:49 -08:00
|
|
|
wantM3a := &ScalarProto3{Float32: math.Pi}
|
|
|
|
wantM3b := &ScalarProto3{Float32: math.Ln2}
|
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
wantList5 := getField((&EnumMessages{EnumList: []EnumProto2{333, 222}}).ProtoReflect(), 5)
|
|
|
|
wantList6 := getField((&EnumMessages{MessageList: []*ScalarProto2{wantM2a, wantM2b}}).ProtoReflect(), 6)
|
2018-11-14 21:59:49 -08:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
wantMap7 := getField((&EnumMessages{EnumMap: map[string]EnumProto3{"one": 1, "two": 2}}).ProtoReflect(), 7)
|
|
|
|
wantMap8 := getField((&EnumMessages{MessageMap: map[string]*ScalarProto3{"pi": wantM3a, "ln2": wantM3b}}).ProtoReflect(), 8)
|
2018-11-14 21:59:49 -08:00
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, new(EnumMessages).ProtoReflect(), messageOps{
|
2018-11-14 21:59:49 -08:00
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false},
|
2019-04-25 23:48:08 -07:00
|
|
|
getFields{1: VE(0xbeef), 2: VE(1), 3: V(emptyL), 4: V(emptyM), 9: VE(0xbeef), 10: VE(1)},
|
2018-11-14 21:59:49 -08:00
|
|
|
|
|
|
|
// Test singular enums.
|
|
|
|
setFields{1: VE(0xdead), 2: VE(0)},
|
|
|
|
getFields{1: VE(0xdead), 2: VE(0)},
|
|
|
|
hasFields{1: true, 2: true},
|
|
|
|
|
|
|
|
// Test singular messages.
|
2019-04-25 23:48:08 -07:00
|
|
|
messageFieldsMutable{3: messageOps{setFields{109: V(float32(math.E))}}},
|
|
|
|
messageFieldsMutable{4: messageOps{setFields{1: VE(1234)}}},
|
2018-11-14 21:59:49 -08:00
|
|
|
getFields{3: V(wantL), 4: V(wantM)},
|
|
|
|
clearFields{3, 4},
|
|
|
|
hasFields{3: false, 4: false},
|
|
|
|
setFields{3: V(wantL), 4: V(wantM)},
|
|
|
|
hasFields{3: true, 4: true},
|
|
|
|
|
|
|
|
// Test list of enums and messages.
|
2019-04-25 23:48:08 -07:00
|
|
|
listFieldsMutable{
|
2018-11-14 21:59:49 -08:00
|
|
|
5: listOps{
|
|
|
|
appendList{VE(111), VE(222)},
|
|
|
|
setList{0: VE(333)},
|
|
|
|
getList{0: VE(333), 1: VE(222)},
|
|
|
|
lenList(2),
|
|
|
|
},
|
|
|
|
6: listOps{
|
|
|
|
appendMessageList{setFields{4: V(uint32(1e6))}},
|
|
|
|
appendMessageList{setFields{6: V(float32(math.Phi))}},
|
2019-04-25 23:48:08 -07:00
|
|
|
setList{0: V(wantM2a.ProtoReflect())},
|
|
|
|
getList{0: V(wantM2a.ProtoReflect()), 1: V(wantM2b.ProtoReflect())},
|
2018-11-14 21:59:49 -08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
getFields{5: wantList5, 6: wantList6},
|
|
|
|
hasFields{5: true, 6: true},
|
|
|
|
listFields{5: listOps{truncList(0)}},
|
|
|
|
hasFields{5: false, 6: true},
|
|
|
|
|
|
|
|
// Test maps of enums and messages.
|
2019-04-25 23:48:08 -07:00
|
|
|
mapFieldsMutable{
|
2018-11-14 21:59:49 -08:00
|
|
|
7: mapOps{
|
|
|
|
setMap{"one": VE(1), "two": VE(2)},
|
|
|
|
hasMap{"one": true, "two": true, "three": false},
|
|
|
|
lenMap(2),
|
|
|
|
},
|
|
|
|
8: mapOps{
|
|
|
|
messageMap{"pi": messageOps{setFields{6: V(float32(math.Pi))}}},
|
2019-04-25 23:48:08 -07:00
|
|
|
setMap{"ln2": V(wantM3b.ProtoReflect())},
|
|
|
|
getMap{"pi": V(wantM3a.ProtoReflect()), "ln2": V(wantM3b.ProtoReflect()), "none": V(nil)},
|
2018-11-14 21:59:49 -08:00
|
|
|
lenMap(2),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
getFields{7: wantMap7, 8: wantMap8},
|
|
|
|
hasFields{7: true, 8: true},
|
|
|
|
mapFields{8: mapOps{clearMap{"pi", "ln2", "none"}}},
|
|
|
|
hasFields{7: true, 8: false},
|
|
|
|
|
|
|
|
// Test oneofs of enums and messages.
|
|
|
|
setFields{9: VE(0xdead)},
|
|
|
|
hasFields{1: true, 2: true, 9: true, 10: false, 11: false, 12: false},
|
|
|
|
setFields{10: VE(0)},
|
|
|
|
hasFields{1: true, 2: true, 9: false, 10: true, 11: false, 12: false},
|
2019-04-25 23:48:08 -07:00
|
|
|
messageFieldsMutable{11: messageOps{setFields{6: V(float32(math.Pi))}}},
|
|
|
|
getFields{11: V(wantM2a.ProtoReflect())},
|
2018-11-14 21:59:49 -08:00
|
|
|
hasFields{1: true, 2: true, 9: false, 10: false, 11: true, 12: false},
|
2019-04-25 23:48:08 -07:00
|
|
|
messageFieldsMutable{12: messageOps{setFields{6: V(float32(math.Pi))}}},
|
|
|
|
getFields{12: V(wantM3a.ProtoReflect())},
|
2018-11-14 21:59:49 -08:00
|
|
|
hasFields{1: true, 2: true, 9: false, 10: false, 11: false, 12: true},
|
|
|
|
|
|
|
|
// Check entire message.
|
2019-04-25 23:48:08 -07:00
|
|
|
rangeFields{1: VE(0xdead), 2: VE(0), 3: V(wantL), 4: V(wantM), 6: wantList6, 7: wantMap7, 12: V(wantM3a.ProtoReflect())},
|
|
|
|
equalMessage{(&EnumMessages{
|
2018-11-14 21:59:49 -08:00
|
|
|
EnumP2: EnumProto2(0xdead).Enum(),
|
|
|
|
EnumP3: EnumProto3(0).Enum(),
|
2018-11-27 18:45:07 -08:00
|
|
|
MessageLegacy: &proto2_20180125.Message{OptionalFloat: scalar.Float32(math.E)},
|
2019-04-25 23:48:08 -07:00
|
|
|
MessageCycle: wantM.Interface().(*EnumMessages),
|
2018-11-14 21:59:49 -08:00
|
|
|
MessageList: []*ScalarProto2{wantM2a, wantM2b},
|
|
|
|
EnumMap: map[string]EnumProto3{"one": 1, "two": 2},
|
|
|
|
Union: &EnumMessages_OneofM3{wantM3a},
|
2019-04-25 23:48:08 -07:00
|
|
|
}).ProtoReflect()},
|
2018-11-14 21:59:49 -08:00
|
|
|
clearFields{1, 2, 3, 4, 6, 7, 12},
|
2019-04-25 23:48:08 -07:00
|
|
|
equalMessage{new(EnumMessages).ProtoReflect()},
|
2018-11-14 21:59:49 -08:00
|
|
|
})
|
2018-12-01 04:57:09 -08:00
|
|
|
|
|
|
|
// Test read-only operations on nil message.
|
2019-04-25 23:48:08 -07:00
|
|
|
testMessage(t, nil, (*EnumMessages)(nil).ProtoReflect(), messageOps{
|
2018-12-01 04:57:09 -08:00
|
|
|
hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false},
|
2019-04-25 23:48:08 -07:00
|
|
|
getFields{1: VE(0xbeef), 2: VE(1), 3: V(emptyL), 4: V(emptyM), 9: VE(0xbeef), 10: VE(1), 11: V(emptyM2), 12: V(emptyM3)},
|
2018-12-01 04:57:09 -08:00
|
|
|
listFields{5: {lenList(0)}, 6: {lenList(0)}},
|
|
|
|
mapFields{7: {lenMap(0)}, 8: {lenMap(0)}},
|
|
|
|
})
|
2018-11-14 21:59:49 -08:00
|
|
|
}
|
2018-09-13 13:24:35 -07:00
|
|
|
|
|
|
|
var cmpOpts = cmp.Options{
|
2018-11-14 21:59:49 -08:00
|
|
|
cmp.Comparer(func(x, y *proto2_20180125.Message) bool {
|
2019-06-06 13:01:53 -07:00
|
|
|
mx := pimpl.Export{}.MessageOf(x).Interface()
|
|
|
|
my := pimpl.Export{}.MessageOf(y).Interface()
|
|
|
|
return proto.Equal(mx, my)
|
2018-09-13 13:24:35 -07:00
|
|
|
}),
|
2018-11-14 21:59:49 -08:00
|
|
|
cmp.Transformer("UnwrapValue", func(pv pref.Value) interface{} {
|
2019-04-25 23:48:08 -07:00
|
|
|
switch v := pv.Interface().(type) {
|
|
|
|
case pref.Message:
|
|
|
|
out := make(map[pref.FieldNumber]pref.Value)
|
|
|
|
v.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
|
|
|
|
out[fd.Number()] = v
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
return out
|
|
|
|
case pref.List:
|
|
|
|
var out []pref.Value
|
|
|
|
for i := 0; i < v.Len(); i++ {
|
|
|
|
out = append(out, v.Get(i))
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
case pref.Map:
|
|
|
|
out := make(map[interface{}]pref.Value)
|
|
|
|
v.Range(func(k pref.MapKey, v pref.Value) bool {
|
|
|
|
out[k.Interface()] = v
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
return out
|
|
|
|
default:
|
|
|
|
return v
|
|
|
|
}
|
2018-09-13 13:24:35 -07:00
|
|
|
}),
|
|
|
|
cmpopts.EquateNaNs(),
|
2018-11-14 21:59:49 -08:00
|
|
|
cmpopts.EquateEmpty(),
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func testMessage(t *testing.T, p path, m pref.Message, tt messageOps) {
|
2019-04-25 23:48:08 -07:00
|
|
|
fieldDescs := m.Descriptor().Fields()
|
|
|
|
oneofDescs := m.Descriptor().Oneofs()
|
2018-09-13 13:24:35 -07:00
|
|
|
for i, op := range tt {
|
|
|
|
p.Push(i)
|
|
|
|
switch op := op.(type) {
|
|
|
|
case equalMessage:
|
2019-04-25 23:48:08 -07:00
|
|
|
if diff := cmp.Diff(V(op.Message), V(m), cmpOpts); diff != "" {
|
2018-09-13 13:24:35 -07:00
|
|
|
t.Errorf("operation %v, message mismatch (-want, +got):\n%s", p, diff)
|
|
|
|
}
|
|
|
|
case hasFields:
|
|
|
|
got := map[pref.FieldNumber]bool{}
|
|
|
|
want := map[pref.FieldNumber]bool(op)
|
|
|
|
for n := range want {
|
2019-04-25 23:48:08 -07:00
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
got[n] = m.Has(fd)
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
|
|
|
if diff := cmp.Diff(want, got); diff != "" {
|
2019-04-25 23:48:08 -07:00
|
|
|
t.Errorf("operation %v, Message.Has mismatch (-want, +got):\n%s", p, diff)
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
|
|
|
case getFields:
|
|
|
|
got := map[pref.FieldNumber]pref.Value{}
|
|
|
|
want := map[pref.FieldNumber]pref.Value(op)
|
|
|
|
for n := range want {
|
2019-04-25 23:48:08 -07:00
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
got[n] = m.Get(fd)
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
|
|
|
if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
|
2019-04-25 23:48:08 -07:00
|
|
|
t.Errorf("operation %v, Message.Get mismatch (-want, +got):\n%s", p, diff)
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
|
|
|
case setFields:
|
|
|
|
for n, v := range op {
|
2019-04-25 23:48:08 -07:00
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
m.Set(fd, v)
|
2018-09-13 13:24:35 -07:00
|
|
|
}
|
|
|
|
case clearFields:
|
2018-11-14 21:59:49 -08:00
|
|
|
for _, n := range op {
|
2019-04-25 23:48:08 -07:00
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
m.Clear(fd)
|
2018-11-14 21:59:49 -08:00
|
|
|
}
|
2019-04-03 13:40:53 -07:00
|
|
|
case whichOneofs:
|
|
|
|
got := map[pref.Name]pref.FieldNumber{}
|
|
|
|
want := map[pref.Name]pref.FieldNumber(op)
|
|
|
|
for s := range want {
|
2019-04-25 23:48:08 -07:00
|
|
|
od := oneofDescs.ByName(s)
|
|
|
|
fd := m.WhichOneof(od)
|
|
|
|
if fd == nil {
|
|
|
|
got[s] = 0
|
|
|
|
} else {
|
|
|
|
got[s] = fd.Number()
|
|
|
|
}
|
2019-04-03 13:40:53 -07:00
|
|
|
}
|
|
|
|
if diff := cmp.Diff(want, got); diff != "" {
|
2019-04-25 23:48:08 -07:00
|
|
|
t.Errorf("operation %v, Message.WhichOneof mismatch (-want, +got):\n%s", p, diff)
|
2019-04-03 13:40:53 -07:00
|
|
|
}
|
2018-11-14 21:59:49 -08:00
|
|
|
case messageFields:
|
|
|
|
for n, tt := range op {
|
|
|
|
p.Push(int(n))
|
2019-04-25 23:48:08 -07:00
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
testMessage(t, p, m.Get(fd).Message(), tt)
|
|
|
|
p.Pop()
|
|
|
|
}
|
|
|
|
case messageFieldsMutable:
|
|
|
|
for n, tt := range op {
|
|
|
|
p.Push(int(n))
|
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
testMessage(t, p, m.Mutable(fd).Message(), tt)
|
2018-11-14 21:59:49 -08:00
|
|
|
p.Pop()
|
2018-09-12 16:20:37 -07: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
|
|
|
case listFields:
|
2018-09-13 13:24:35 -07:00
|
|
|
for n, tt := range op {
|
|
|
|
p.Push(int(n))
|
2019-04-25 23:48:08 -07:00
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
testLists(t, p, m.Get(fd).List(), tt)
|
|
|
|
p.Pop()
|
|
|
|
}
|
|
|
|
case listFieldsMutable:
|
|
|
|
for n, tt := range op {
|
|
|
|
p.Push(int(n))
|
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
testLists(t, p, m.Mutable(fd).List(), tt)
|
2018-09-13 13:24:35 -07:00
|
|
|
p.Pop()
|
|
|
|
}
|
2018-10-17 00:27:21 +00:00
|
|
|
case mapFields:
|
|
|
|
for n, tt := range op {
|
|
|
|
p.Push(int(n))
|
2019-04-25 23:48:08 -07:00
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
testMaps(t, p, m.Get(fd).Map(), tt)
|
|
|
|
p.Pop()
|
|
|
|
}
|
|
|
|
case mapFieldsMutable:
|
|
|
|
for n, tt := range op {
|
|
|
|
p.Push(int(n))
|
|
|
|
fd := fieldDescs.ByNumber(n)
|
|
|
|
testMaps(t, p, m.Mutable(fd).Map(), tt)
|
2018-10-17 00:27:21 +00:00
|
|
|
p.Pop()
|
|
|
|
}
|
2018-11-14 21:59:49 -08:00
|
|
|
case rangeFields:
|
|
|
|
got := map[pref.FieldNumber]pref.Value{}
|
|
|
|
want := map[pref.FieldNumber]pref.Value(op)
|
2019-04-25 23:48:08 -07:00
|
|
|
m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
|
|
|
|
got[fd.Number()] = v
|
2018-11-14 21:59:49 -08:00
|
|
|
return true
|
|
|
|
})
|
|
|
|
if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
|
2019-04-25 23:48:08 -07:00
|
|
|
t.Errorf("operation %v, Message.Range mismatch (-want, +got):\n%s", p, diff)
|
2018-11-14 21:59:49 -08:00
|
|
|
}
|
2018-09-13 13:24:35 -07:00
|
|
|
default:
|
|
|
|
t.Fatalf("operation %v, invalid operation: %T", p, op)
|
|
|
|
}
|
|
|
|
p.Pop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 testLists(t *testing.T, p path, v pref.List, tt listOps) {
|
2018-09-13 13:24:35 -07:00
|
|
|
for i, op := range tt {
|
|
|
|
p.Push(i)
|
|
|
|
switch op := op.(type) {
|
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
|
|
|
case equalList:
|
2019-04-25 23:48:08 -07:00
|
|
|
if diff := cmp.Diff(V(op.List), V(v), cmpOpts); diff != "" {
|
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
|
|
|
t.Errorf("operation %v, list mismatch (-want, +got):\n%s", p, diff)
|
2018-09-13 13:24:35 -07: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
|
|
|
case lenList:
|
2018-09-13 13:24:35 -07:00
|
|
|
if got, want := v.Len(), int(op); got != want {
|
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
|
|
|
t.Errorf("operation %v, List.Len = %d, want %d", p, got, want)
|
2018-09-13 13:24:35 -07: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
|
|
|
case getList:
|
2018-09-13 13:24:35 -07:00
|
|
|
got := map[int]pref.Value{}
|
|
|
|
want := map[int]pref.Value(op)
|
|
|
|
for n := range want {
|
|
|
|
got[n] = v.Get(n)
|
|
|
|
}
|
|
|
|
if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
|
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
|
|
|
t.Errorf("operation %v, List.Get mismatch (-want, +got):\n%s", p, diff)
|
2018-09-13 13:24:35 -07: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
|
|
|
case setList:
|
2018-09-13 13:24:35 -07:00
|
|
|
for n, e := range op {
|
|
|
|
v.Set(n, e)
|
|
|
|
}
|
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
|
|
|
case appendList:
|
2018-09-13 13:24:35 -07:00
|
|
|
for _, e := range op {
|
|
|
|
v.Append(e)
|
|
|
|
}
|
2018-11-14 21:59:49 -08:00
|
|
|
case appendMessageList:
|
2019-01-09 02:57:13 -08:00
|
|
|
m := v.NewMessage()
|
2018-12-07 14:28:33 -08:00
|
|
|
v.Append(V(m))
|
|
|
|
testMessage(t, p, m, messageOps(op))
|
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
|
|
|
case truncList:
|
2018-09-13 13:24:35 -07:00
|
|
|
v.Truncate(int(op))
|
|
|
|
default:
|
|
|
|
t.Fatalf("operation %v, invalid operation: %T", p, op)
|
|
|
|
}
|
|
|
|
p.Pop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-17 00:27:21 +00:00
|
|
|
func testMaps(t *testing.T, p path, m pref.Map, tt mapOps) {
|
|
|
|
for i, op := range tt {
|
|
|
|
p.Push(i)
|
|
|
|
switch op := op.(type) {
|
|
|
|
case equalMap:
|
2019-04-25 23:48:08 -07:00
|
|
|
if diff := cmp.Diff(V(op.Map), V(m), cmpOpts); diff != "" {
|
2018-10-17 00:27:21 +00:00
|
|
|
t.Errorf("operation %v, map mismatch (-want, +got):\n%s", p, diff)
|
|
|
|
}
|
|
|
|
case lenMap:
|
|
|
|
if got, want := m.Len(), int(op); got != want {
|
|
|
|
t.Errorf("operation %v, Map.Len = %d, want %d", p, got, want)
|
|
|
|
}
|
|
|
|
case hasMap:
|
|
|
|
got := map[interface{}]bool{}
|
|
|
|
want := map[interface{}]bool(op)
|
|
|
|
for k := range want {
|
|
|
|
got[k] = m.Has(V(k).MapKey())
|
|
|
|
}
|
|
|
|
if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
|
|
|
|
t.Errorf("operation %v, Map.Has mismatch (-want, +got):\n%s", p, diff)
|
|
|
|
}
|
|
|
|
case getMap:
|
|
|
|
got := map[interface{}]pref.Value{}
|
|
|
|
want := map[interface{}]pref.Value(op)
|
|
|
|
for k := range want {
|
|
|
|
got[k] = m.Get(V(k).MapKey())
|
|
|
|
}
|
|
|
|
if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
|
|
|
|
t.Errorf("operation %v, Map.Get mismatch (-want, +got):\n%s", p, diff)
|
|
|
|
}
|
|
|
|
case setMap:
|
|
|
|
for k, v := range op {
|
|
|
|
m.Set(V(k).MapKey(), v)
|
|
|
|
}
|
|
|
|
case clearMap:
|
2018-11-14 21:59:49 -08:00
|
|
|
for _, k := range op {
|
|
|
|
m.Clear(V(k).MapKey())
|
|
|
|
}
|
|
|
|
case messageMap:
|
|
|
|
for k, tt := range op {
|
2018-12-07 14:28:33 -08:00
|
|
|
mk := V(k).MapKey()
|
|
|
|
if !m.Has(mk) {
|
|
|
|
m.Set(mk, V(m.NewMessage()))
|
|
|
|
}
|
|
|
|
testMessage(t, p, m.Get(mk).Message(), tt)
|
2018-10-17 00:27:21 +00:00
|
|
|
}
|
|
|
|
case rangeMap:
|
|
|
|
got := map[interface{}]pref.Value{}
|
|
|
|
want := map[interface{}]pref.Value(op)
|
|
|
|
m.Range(func(k pref.MapKey, v pref.Value) bool {
|
|
|
|
got[k.Interface()] = v
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
|
|
|
|
t.Errorf("operation %v, Map.Range mismatch (-want, +got):\n%s", p, diff)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Fatalf("operation %v, invalid operation: %T", p, op)
|
|
|
|
}
|
|
|
|
p.Pop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-25 23:48:08 -07:00
|
|
|
func getField(m pref.Message, n pref.FieldNumber) pref.Value {
|
|
|
|
fd := m.Descriptor().Fields().ByNumber(n)
|
|
|
|
return m.Get(fd)
|
|
|
|
}
|
|
|
|
|
2018-09-13 13:24:35 -07:00
|
|
|
type path []int
|
|
|
|
|
|
|
|
func (p *path) Push(i int) { *p = append(*p, i) }
|
|
|
|
func (p *path) Pop() { *p = (*p)[:len(*p)-1] }
|
|
|
|
func (p path) String() string {
|
|
|
|
var ss []string
|
|
|
|
for _, i := range p {
|
|
|
|
ss = append(ss, fmt.Sprint(i))
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|
2018-09-13 13:24:35 -07:00
|
|
|
return strings.Join(ss, ".")
|
2018-09-12 16:20:37 -07:00
|
|
|
}
|