mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-27 21:35:28 +00:00
reflect/prototype: initial commit
The prototype package provides constructors to create protobuf types that implement the interfaces defined in the protoreflect package. High-level API: func NewFile(t *File) (protoreflect.FileDescriptor, error) type File struct{ ... } type Message struct{ ... } type Field struct{ ... } type Oneof struct{ ... } type Enum struct{ ... } type EnumValue struct{ ... } type Extension struct{ ... } type Service struct{ ... } type Method struct{ ... } func NewEnum(t *StandaloneEnum) (protoreflect.EnumDescriptor, error) func NewMessage(t *StandaloneMessage) (protoreflect.MessageDescriptor, error) func NewExtension(t *StandaloneExtension) (protoreflect.ExtensionDescriptor, error) type StandaloneEnum struct{ ... } type StandaloneMessage struct{ ... } type StandaloneExtension struct{ ... } func PlaceholderFile(path string, pkg protoreflect.FullName) protoreflect.FileDescriptor func PlaceholderEnum(name protoreflect.FullName) protoreflect.EnumDescriptor func PlaceholderMessage(name protoreflect.FullName) protoreflect.MessageDescriptor This CL is missing some features that are to be added later: * The stringer methods are not implemented, providing no way to print the descriptors in a humanly readable manner. * There is no support for proto options or retrieving the raw descriptor. * There are constructors for Go specific types (e.g., protoreflect.MessageType). We drop go1.9 support since we use strings.Builder. We switch to go.11rc1 to obtain some bug fixes for modules. Change-Id: Ieac9a2530afc81e5a5bb9ab5816804372f652b18 Reviewed-on: https://go-review.googlesource.com/129057 Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Herbie Ong <herbie@google.com>
This commit is contained in:
parent
dbc9a12dbd
commit
bfda014ecd
244
internal/cmd/generate-types/main.go
Normal file
244
internal/cmd/generate-types/main.go
Normal file
@ -0,0 +1,244 @@
|
||||
// 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.
|
||||
|
||||
//go:generate go run . -execute
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var run = flag.Bool("execute", false, "Write generated files to destination.")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
chdirRoot()
|
||||
writeSource("reflect/prototype/protofile_list_gen.go", generateListTypes())
|
||||
}
|
||||
|
||||
// chdirRoot changes the working directory to the repository root.
|
||||
func chdirRoot() {
|
||||
out, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := os.Chdir(strings.TrimSuffix(string(out), "\n")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Expr is a single line Go expression.
|
||||
type Expr string
|
||||
|
||||
type DescriptorType string
|
||||
|
||||
const (
|
||||
MessageDesc DescriptorType = "Message"
|
||||
FieldDesc DescriptorType = "Field"
|
||||
OneofDesc DescriptorType = "Oneof"
|
||||
ExtensionDesc DescriptorType = "Extension"
|
||||
EnumDesc DescriptorType = "Enum"
|
||||
EnumValueDesc DescriptorType = "EnumValue"
|
||||
ServiceDesc DescriptorType = "Service"
|
||||
MethodDesc DescriptorType = "Method"
|
||||
)
|
||||
|
||||
func (d DescriptorType) Expr() Expr {
|
||||
return "protoreflect." + Expr(d) + "Descriptor"
|
||||
}
|
||||
func (d DescriptorType) NumberExpr() Expr {
|
||||
switch d {
|
||||
case FieldDesc:
|
||||
return "protoreflect.FieldNumber"
|
||||
case EnumValueDesc:
|
||||
return "protoreflect.EnumNumber"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func generateListTypes() string {
|
||||
// TODO: If Go2 has generics, replace this with a single container type.
|
||||
return mustExecute(listTypesTemplate, []DescriptorType{
|
||||
MessageDesc, FieldDesc, OneofDesc, ExtensionDesc, EnumDesc, EnumValueDesc, ServiceDesc, MethodDesc,
|
||||
})
|
||||
}
|
||||
|
||||
var listTypesTemplate = template.Must(template.New("").Funcs(template.FuncMap{
|
||||
"unexport": func(t DescriptorType) Expr {
|
||||
return Expr(string(unicode.ToLower(rune(t[0]))) + string(t[1:]))
|
||||
},
|
||||
}).Parse(`
|
||||
{{- range .}}
|
||||
{{$nameList := (printf "%ss" (unexport .))}} {{/* e.g., "messages" */}}
|
||||
{{$nameListMeta := (printf "%ssMeta" (unexport .))}} {{/* e.g., "messagesMeta" */}}
|
||||
{{$nameMeta := (printf "%sMeta" (unexport .))}} {{/* e.g., "messageMeta" */}}
|
||||
{{$nameDesc := (printf "%sDesc" (unexport .))}} {{/* e.g., "messageDesc" */}}
|
||||
|
||||
type {{$nameListMeta}} struct {
|
||||
once sync.Once
|
||||
typs []{{.}}
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*{{.}}
|
||||
{{- if (eq . "Field")}}
|
||||
jsonOnce sync.Once
|
||||
byJSON map[string]*{{.}}
|
||||
{{- end}}
|
||||
{{- if .NumberExpr}}
|
||||
numOnce sync.Once
|
||||
byNum map[{{.NumberExpr}}]*{{.}}
|
||||
{{- end}}
|
||||
}
|
||||
type {{$nameList}} {{$nameListMeta}}
|
||||
|
||||
func (p *{{$nameListMeta}}) lazyInit(parent protoreflect.Descriptor, ts []{{.}}) *{{$nameList}} {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]{{$nameMeta}}, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.{{$nameMeta}} != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.{{$nameMeta}} = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, {{printf "%v" (eq . "EnumValue")}})
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*{{$nameList}})(p)
|
||||
}
|
||||
func (p *{{$nameList}}) Len() int { return len(p.typs) }
|
||||
func (p *{{$nameList}}) Get(i int) {{.Expr}} { return {{$nameDesc}}{&p.typs[i]} }
|
||||
func (p *{{$nameList}}) ByName(s protoreflect.Name) {{.Expr}} {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*{{.}}, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return {{$nameDesc}}{t}
|
||||
}
|
||||
{{- if (eq . "Field")}}
|
||||
func (p *{{$nameList}}) ByJSONName(s string) {{.Expr}} {
|
||||
p.jsonOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byJSON = make(map[string]*{{.}}, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
s := {{$nameDesc}}{t}.JSONName()
|
||||
if _, ok := p.byJSON[s]; !ok {
|
||||
p.byJSON[s] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byJSON[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return {{$nameDesc}}{t}
|
||||
}
|
||||
{{- end}}
|
||||
{{- if .NumberExpr}}
|
||||
func (p *{{$nameList}}) ByNumber(n {{.NumberExpr}}) {{.Expr}} {
|
||||
p.numOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byNum = make(map[{{.NumberExpr}}]*{{.}}, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
if _, ok := p.byNum[t.Number]; !ok {
|
||||
p.byNum[t.Number] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byNum[n]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return {{$nameDesc}}{t}
|
||||
}
|
||||
{{- end}}
|
||||
func (p *{{$nameList}}) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *{{$nameList}}) ProtoInternal(pragma.DoNotImplement) {}
|
||||
{{- end}}
|
||||
`))
|
||||
|
||||
func mustExecute(t *template.Template, data interface{}) string {
|
||||
var sb strings.Builder
|
||||
if err := t.Execute(&sb, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func writeSource(file, src string) {
|
||||
// Crude but effective way to detect used imports.
|
||||
var imports []string
|
||||
for _, pkg := range []string{
|
||||
"fmt",
|
||||
"sync",
|
||||
"",
|
||||
"google.golang.org/proto/internal/pragma",
|
||||
"google.golang.org/proto/reflect/protoreflect",
|
||||
} {
|
||||
if pkg == "" {
|
||||
imports = append(imports, "") // blank line between stdlib and proto packages
|
||||
} else if regexp.MustCompile(`[^\pL_0-9]` + path.Base(pkg) + `\.`).MatchString(src) {
|
||||
imports = append(imports, strconv.Quote(pkg))
|
||||
}
|
||||
}
|
||||
|
||||
s := strings.Join([]string{
|
||||
"// 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.",
|
||||
"",
|
||||
"// Code generated by generate-types. DO NOT EDIT.",
|
||||
"",
|
||||
"package " + path.Base(path.Dir(path.Join("proto", file))),
|
||||
"",
|
||||
"import (" + strings.Join(imports, "\n") + ")",
|
||||
"",
|
||||
src,
|
||||
}, "\n")
|
||||
b, err := format.Source([]byte(s))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if *run {
|
||||
if err := ioutil.WriteFile(file, b, 0664); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
if err := ioutil.WriteFile(file+".tmp", b, 0664); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.Remove(file + ".tmp")
|
||||
|
||||
cmd := exec.Command("diff", file, file+".tmp", "-u")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Run()
|
||||
}
|
||||
}
|
29
reflect/prototype/descriptor.go
Normal file
29
reflect/prototype/descriptor.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
pref "google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// TODO: This cannot be implemented without proto.Unmarshal.
|
||||
|
||||
type descriptorFileMeta struct{}
|
||||
|
||||
func (p *descriptorFileMeta) lazyInit(t fileDesc) (pref.Message, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
type descriptorSubMeta struct{}
|
||||
|
||||
func (p *descriptorSubMeta) lazyInit(t pref.Descriptor) (pref.Message, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
type descriptorOptionsMeta struct{}
|
||||
|
||||
func (p *descriptorOptionsMeta) lazyInit(t pref.Descriptor) (pref.DescriptorOptions, bool) {
|
||||
return nil, false
|
||||
}
|
32
reflect/prototype/placeholder.go
Normal file
32
reflect/prototype/placeholder.go
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import "google.golang.org/proto/reflect/protoreflect"
|
||||
|
||||
// PlaceholderFile returns a placeholder protoreflect.FileType where
|
||||
// only the Path and Package accessors are valid.
|
||||
func PlaceholderFile(path string, pkg protoreflect.FullName) protoreflect.FileDescriptor {
|
||||
// TODO: Is Package needed for placeholders?
|
||||
return placeholderFile{path, placeholderName(pkg)}
|
||||
}
|
||||
|
||||
// PlaceholderMessage returns a placeholder protoreflect.MessageType
|
||||
// where only the Name and FullName accessors are valid.
|
||||
//
|
||||
// A placeholder can be used within File literals when referencing a message
|
||||
// that is declared within that file.
|
||||
func PlaceholderMessage(name protoreflect.FullName) protoreflect.MessageDescriptor {
|
||||
return placeholderMessage{placeholderName(name)}
|
||||
}
|
||||
|
||||
// PlaceholderEnum returns a placeholder protoreflect.EnumType
|
||||
// where only the Name and FullName accessors are valid.
|
||||
//
|
||||
// A placeholder can be used within File literals when referencing an enum
|
||||
// that is declared within that file.
|
||||
func PlaceholderEnum(name protoreflect.FullName) protoreflect.EnumDescriptor {
|
||||
return placeholderEnum{placeholderName(name)}
|
||||
}
|
74
reflect/prototype/placeholder_type.go
Normal file
74
reflect/prototype/placeholder_type.go
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/proto/internal/pragma"
|
||||
pref "google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
var (
|
||||
emptyFiles fileImports
|
||||
emptyMessages messages
|
||||
emptyFields fields
|
||||
emptyOneofs oneofs
|
||||
emptyNumbers numbers
|
||||
emptyRanges ranges
|
||||
emptyEnums enums
|
||||
emptyEnumValues enumValues
|
||||
emptyExtensions extensions
|
||||
emptyServices services
|
||||
)
|
||||
|
||||
type placeholderName pref.FullName
|
||||
|
||||
func (t placeholderName) Parent() (pref.Descriptor, bool) { return nil, false }
|
||||
func (t placeholderName) Syntax() pref.Syntax { return 0 }
|
||||
func (t placeholderName) Name() pref.Name { return pref.FullName(t).Name() }
|
||||
func (t placeholderName) FullName() pref.FullName { return pref.FullName(t) }
|
||||
func (t placeholderName) IsPlaceholder() bool { return true }
|
||||
func (t placeholderName) DescriptorProto() (pref.Message, bool) { return nil, false }
|
||||
func (t placeholderName) DescriptorOptions() (pref.DescriptorOptions, bool) { return nil, false }
|
||||
func (t placeholderName) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type placeholderFile struct {
|
||||
path string
|
||||
placeholderName
|
||||
}
|
||||
|
||||
func (t placeholderFile) Path() string { return t.path }
|
||||
func (t placeholderFile) Package() pref.FullName { return t.FullName() }
|
||||
func (t placeholderFile) Imports() pref.FileImports { return &emptyFiles }
|
||||
func (t placeholderFile) Messages() pref.MessageDescriptors { return &emptyMessages }
|
||||
func (t placeholderFile) Enums() pref.EnumDescriptors { return &emptyEnums }
|
||||
func (t placeholderFile) Extensions() pref.ExtensionDescriptors { return &emptyExtensions }
|
||||
func (t placeholderFile) Services() pref.ServiceDescriptors { return &emptyServices }
|
||||
func (t placeholderFile) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t placeholderFile) ProtoType(pref.FileDescriptor) {}
|
||||
|
||||
type placeholderMessage struct {
|
||||
placeholderName
|
||||
}
|
||||
|
||||
func (t placeholderMessage) IsMapEntry() bool { return false }
|
||||
func (t placeholderMessage) Fields() pref.FieldDescriptors { return &emptyFields }
|
||||
func (t placeholderMessage) Oneofs() pref.OneofDescriptors { return &emptyOneofs }
|
||||
func (t placeholderMessage) RequiredNumbers() pref.FieldNumbers { return &emptyNumbers }
|
||||
func (t placeholderMessage) ExtensionRanges() pref.FieldRanges { return &emptyRanges }
|
||||
func (t placeholderMessage) Messages() pref.MessageDescriptors { return &emptyMessages }
|
||||
func (t placeholderMessage) Enums() pref.EnumDescriptors { return &emptyEnums }
|
||||
func (t placeholderMessage) Extensions() pref.ExtensionDescriptors { return &emptyExtensions }
|
||||
func (t placeholderMessage) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t placeholderMessage) ProtoType(pref.MessageDescriptor) {}
|
||||
|
||||
type placeholderEnum struct {
|
||||
placeholderName
|
||||
}
|
||||
|
||||
func (t placeholderEnum) Values() pref.EnumValueDescriptors { return &emptyEnumValues }
|
||||
func (t placeholderEnum) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t placeholderEnum) ProtoType(pref.EnumDescriptor) {}
|
161
reflect/prototype/protofile.go
Normal file
161
reflect/prototype/protofile.go
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package prototype provides builders to construct protobuf types that
|
||||
// implement the interfaces defined in the protoreflect package.
|
||||
//
|
||||
// Protobuf types can either be constructed as standalone types
|
||||
// (e.g., StandaloneMessage), or together as a batch of types in a single
|
||||
// proto file (e.g., File). When creating standalone types, additional
|
||||
// information must be provided such as the full type name and the proto syntax.
|
||||
// When creating an entire file, the syntax and full name is derived from
|
||||
// the parent type.
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// Every struct has a "meta" struct embedded within it as a pointer.
|
||||
// The meta type provides additional data structures for efficient lookup on
|
||||
// certain methods (e.g., ByName) or derived information that can be
|
||||
// derived from the parent (e.g., FullName). The meta type is lazily allocated
|
||||
// and initialized. This architectural approach keeps the literal representation
|
||||
// smaller, which then keeps the generated code size smaller.
|
||||
|
||||
// TODO: Support initializing File from a google.protobuf.FileDescriptor?
|
||||
|
||||
// TODO: Instead of a top-down construction approach where internal references
|
||||
// to message types use placeholder types, we could add a Reference method
|
||||
// on Message and Enum that creates a MessageDescriptor or EnumDescriptor
|
||||
// reference that only becomes valid after NewFile.
|
||||
// However, that API approach is more error prone, as it causes more memory
|
||||
// aliasing and provides more opportunity for misuse.
|
||||
// Also, it requires that NewFile at least eagerly initialize all
|
||||
// messages and enums list types. We can always add that API in the future.
|
||||
|
||||
// File is a constructor for protoreflect.FileDescriptor.
|
||||
type File struct {
|
||||
Syntax protoreflect.Syntax
|
||||
Path string
|
||||
Package protoreflect.FullName
|
||||
Imports []protoreflect.FileImport
|
||||
|
||||
Messages []Message
|
||||
Enums []Enum
|
||||
Extensions []Extension
|
||||
Services []Service
|
||||
|
||||
*fileMeta
|
||||
}
|
||||
|
||||
// NewFile creates a new protoreflect.FileDescriptor from the provided value.
|
||||
// The file must represent a valid proto file according to protobuf semantics.
|
||||
//
|
||||
// Fields that reference an enum or message that is being declared within the
|
||||
// same File can be represented using a placeholder descriptor. NewFile will
|
||||
// automatically resolve the placeholder to point to the concrete type.
|
||||
//
|
||||
// The caller must relinquish full ownership of the input t and must not
|
||||
// access or mutate any fields. The input must not contain slices that are
|
||||
// sub-slices of each other.
|
||||
func NewFile(t *File) (protoreflect.FileDescriptor, error) {
|
||||
// TODO: Provide an unverified make that avoids validating the file.
|
||||
// This is useful for generated code since we know that protoc-gen-go
|
||||
// already validated the protobuf types.
|
||||
ft := newFile(t)
|
||||
if err := validateFile(ft); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ft, nil
|
||||
}
|
||||
|
||||
// Message is a constructor for protoreflect.MessageDescriptor.
|
||||
type Message struct {
|
||||
Name protoreflect.Name
|
||||
IsMapEntry bool
|
||||
Fields []Field
|
||||
Oneofs []Oneof
|
||||
ExtensionRanges [][2]protoreflect.FieldNumber
|
||||
|
||||
Messages []Message
|
||||
Enums []Enum
|
||||
Extensions []Extension
|
||||
|
||||
*messageMeta
|
||||
}
|
||||
|
||||
// Field is a constructor for protoreflect.FieldDescriptor.
|
||||
type Field struct {
|
||||
Name protoreflect.Name
|
||||
Number protoreflect.FieldNumber
|
||||
Cardinality protoreflect.Cardinality
|
||||
Kind protoreflect.Kind
|
||||
JSONName string
|
||||
IsPacked bool
|
||||
IsWeak bool
|
||||
Default protoreflect.Value
|
||||
OneofName protoreflect.Name
|
||||
MessageType protoreflect.MessageDescriptor
|
||||
EnumType protoreflect.EnumDescriptor
|
||||
|
||||
*fieldMeta
|
||||
}
|
||||
|
||||
// Oneof is a constructor for protoreflect.OneofDescriptor.
|
||||
type Oneof struct {
|
||||
Name protoreflect.Name
|
||||
|
||||
*oneofMeta
|
||||
}
|
||||
|
||||
// Extension is a constructor for protoreflect.ExtensionDescriptor.
|
||||
type Extension struct {
|
||||
Name protoreflect.Name
|
||||
Number protoreflect.FieldNumber
|
||||
Cardinality protoreflect.Cardinality
|
||||
Kind protoreflect.Kind
|
||||
IsPacked bool
|
||||
Default protoreflect.Value
|
||||
MessageType protoreflect.MessageDescriptor
|
||||
EnumType protoreflect.EnumDescriptor
|
||||
ExtendedType protoreflect.MessageDescriptor
|
||||
|
||||
*extensionMeta
|
||||
}
|
||||
|
||||
// Enum is a constructor for protoreflect.EnumDescriptor.
|
||||
type Enum struct {
|
||||
Name protoreflect.Name
|
||||
Values []EnumValue
|
||||
|
||||
*enumMeta
|
||||
}
|
||||
|
||||
// EnumValue is a constructor for protoreflect.EnumValueDescriptor.
|
||||
type EnumValue struct {
|
||||
Name protoreflect.Name
|
||||
Number protoreflect.EnumNumber
|
||||
|
||||
*enumValueMeta
|
||||
}
|
||||
|
||||
// Service is a constructor for protoreflect.ServiceDescriptor.
|
||||
type Service struct {
|
||||
Name protoreflect.Name
|
||||
Methods []Method
|
||||
|
||||
*serviceMeta
|
||||
}
|
||||
|
||||
// Method is a constructor for protoreflect.MethodDescriptor.
|
||||
type Method struct {
|
||||
Name protoreflect.Name
|
||||
InputType protoreflect.MessageDescriptor
|
||||
OutputType protoreflect.MessageDescriptor
|
||||
IsStreamingClient bool
|
||||
IsStreamingServer bool
|
||||
|
||||
*methodMeta
|
||||
}
|
100
reflect/prototype/protofile_list.go
Normal file
100
reflect/prototype/protofile_list.go
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/proto/internal/pragma"
|
||||
"google.golang.org/proto/internal/set"
|
||||
pref "google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
type numbersMeta struct {
|
||||
once sync.Once
|
||||
ns []pref.FieldNumber
|
||||
nss set.Ints
|
||||
}
|
||||
type numbers numbersMeta
|
||||
|
||||
func (p *numbersMeta) lazyInit(fs []Field) *numbers {
|
||||
p.once.Do(func() {
|
||||
for i := range fs {
|
||||
if f := &fs[i]; f.Cardinality == pref.Required {
|
||||
p.ns = append(p.ns, f.Number)
|
||||
p.nss.Set(uint64(f.Number))
|
||||
}
|
||||
}
|
||||
})
|
||||
return (*numbers)(p)
|
||||
}
|
||||
func (p *numbers) Len() int { return len(p.ns) }
|
||||
func (p *numbers) Get(i int) pref.FieldNumber { return p.ns[i] }
|
||||
func (p *numbers) Has(n pref.FieldNumber) bool { return p.nss.Has(uint64(n)) }
|
||||
func (p *numbers) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *numbers) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type ranges [][2]pref.FieldNumber
|
||||
|
||||
func (p *ranges) Len() int { return len(*p) }
|
||||
func (p *ranges) Get(i int) [2]pref.FieldNumber { return (*p)[i] }
|
||||
func (p *ranges) Has(n pref.FieldNumber) bool {
|
||||
for _, r := range *p {
|
||||
if r[0] <= n && n < r[1] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (p *ranges) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *ranges) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type fileImports []pref.FileImport
|
||||
|
||||
func (p *fileImports) Len() int { return len(*p) }
|
||||
func (p *fileImports) Get(i int) pref.FileImport { return (*p)[i] }
|
||||
func (p *fileImports) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *fileImports) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type oneofFieldsMeta struct {
|
||||
once sync.Once
|
||||
typs []pref.FieldDescriptor
|
||||
byName map[pref.Name]pref.FieldDescriptor
|
||||
byJSON map[string]pref.FieldDescriptor
|
||||
byNum map[pref.FieldNumber]pref.FieldDescriptor
|
||||
}
|
||||
type oneofFields oneofFieldsMeta
|
||||
|
||||
func (p *oneofFieldsMeta) lazyInit(parent pref.Descriptor) *oneofFields {
|
||||
p.once.Do(func() {
|
||||
otyp := parent.(pref.OneofDescriptor)
|
||||
mtyp, _ := parent.Parent()
|
||||
fs := mtyp.(pref.MessageDescriptor).Fields()
|
||||
for i := 0; i < fs.Len(); i++ {
|
||||
if f := fs.Get(i); otyp == f.OneofType() {
|
||||
p.typs = append(p.typs, f)
|
||||
}
|
||||
}
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[pref.Name]pref.FieldDescriptor, len(p.typs))
|
||||
p.byJSON = make(map[string]pref.FieldDescriptor, len(p.typs))
|
||||
p.byNum = make(map[pref.FieldNumber]pref.FieldDescriptor, len(p.typs))
|
||||
for _, f := range p.typs {
|
||||
p.byName[f.Name()] = f
|
||||
p.byJSON[f.JSONName()] = f
|
||||
p.byNum[f.Number()] = f
|
||||
}
|
||||
}
|
||||
})
|
||||
return (*oneofFields)(p)
|
||||
}
|
||||
func (p *oneofFields) Len() int { return len(p.typs) }
|
||||
func (p *oneofFields) Get(i int) pref.FieldDescriptor { return p.typs[i] }
|
||||
func (p *oneofFields) ByName(s pref.Name) pref.FieldDescriptor { return p.byName[s] }
|
||||
func (p *oneofFields) ByJSONName(s string) pref.FieldDescriptor { return p.byJSON[s] }
|
||||
func (p *oneofFields) ByNumber(n pref.FieldNumber) pref.FieldDescriptor { return p.byNum[n] }
|
||||
func (p *oneofFields) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *oneofFields) ProtoInternal(pragma.DoNotImplement) {}
|
444
reflect/prototype/protofile_list_gen.go
Normal file
444
reflect/prototype/protofile_list_gen.go
Normal file
@ -0,0 +1,444 @@
|
||||
// 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.
|
||||
|
||||
// Code generated by generate-types. DO NOT EDIT.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/proto/internal/pragma"
|
||||
"google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
type messagesMeta struct {
|
||||
once sync.Once
|
||||
typs []Message
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*Message
|
||||
}
|
||||
type messages messagesMeta
|
||||
|
||||
func (p *messagesMeta) lazyInit(parent protoreflect.Descriptor, ts []Message) *messages {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]messageMeta, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.messageMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.messageMeta = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, false)
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*messages)(p)
|
||||
}
|
||||
func (p *messages) Len() int { return len(p.typs) }
|
||||
func (p *messages) Get(i int) protoreflect.MessageDescriptor { return messageDesc{&p.typs[i]} }
|
||||
func (p *messages) ByName(s protoreflect.Name) protoreflect.MessageDescriptor {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*Message, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return messageDesc{t}
|
||||
}
|
||||
func (p *messages) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *messages) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type fieldsMeta struct {
|
||||
once sync.Once
|
||||
typs []Field
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*Field
|
||||
jsonOnce sync.Once
|
||||
byJSON map[string]*Field
|
||||
numOnce sync.Once
|
||||
byNum map[protoreflect.FieldNumber]*Field
|
||||
}
|
||||
type fields fieldsMeta
|
||||
|
||||
func (p *fieldsMeta) lazyInit(parent protoreflect.Descriptor, ts []Field) *fields {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]fieldMeta, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.fieldMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.fieldMeta = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, false)
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*fields)(p)
|
||||
}
|
||||
func (p *fields) Len() int { return len(p.typs) }
|
||||
func (p *fields) Get(i int) protoreflect.FieldDescriptor { return fieldDesc{&p.typs[i]} }
|
||||
func (p *fields) ByName(s protoreflect.Name) protoreflect.FieldDescriptor {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*Field, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return fieldDesc{t}
|
||||
}
|
||||
func (p *fields) ByJSONName(s string) protoreflect.FieldDescriptor {
|
||||
p.jsonOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byJSON = make(map[string]*Field, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
s := fieldDesc{t}.JSONName()
|
||||
if _, ok := p.byJSON[s]; !ok {
|
||||
p.byJSON[s] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byJSON[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return fieldDesc{t}
|
||||
}
|
||||
func (p *fields) ByNumber(n protoreflect.FieldNumber) protoreflect.FieldDescriptor {
|
||||
p.numOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byNum = make(map[protoreflect.FieldNumber]*Field, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
if _, ok := p.byNum[t.Number]; !ok {
|
||||
p.byNum[t.Number] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byNum[n]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return fieldDesc{t}
|
||||
}
|
||||
func (p *fields) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *fields) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type oneofsMeta struct {
|
||||
once sync.Once
|
||||
typs []Oneof
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*Oneof
|
||||
}
|
||||
type oneofs oneofsMeta
|
||||
|
||||
func (p *oneofsMeta) lazyInit(parent protoreflect.Descriptor, ts []Oneof) *oneofs {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]oneofMeta, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.oneofMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.oneofMeta = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, false)
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*oneofs)(p)
|
||||
}
|
||||
func (p *oneofs) Len() int { return len(p.typs) }
|
||||
func (p *oneofs) Get(i int) protoreflect.OneofDescriptor { return oneofDesc{&p.typs[i]} }
|
||||
func (p *oneofs) ByName(s protoreflect.Name) protoreflect.OneofDescriptor {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*Oneof, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return oneofDesc{t}
|
||||
}
|
||||
func (p *oneofs) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *oneofs) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type extensionsMeta struct {
|
||||
once sync.Once
|
||||
typs []Extension
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*Extension
|
||||
}
|
||||
type extensions extensionsMeta
|
||||
|
||||
func (p *extensionsMeta) lazyInit(parent protoreflect.Descriptor, ts []Extension) *extensions {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]extensionMeta, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.extensionMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.extensionMeta = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, false)
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*extensions)(p)
|
||||
}
|
||||
func (p *extensions) Len() int { return len(p.typs) }
|
||||
func (p *extensions) Get(i int) protoreflect.ExtensionDescriptor { return extensionDesc{&p.typs[i]} }
|
||||
func (p *extensions) ByName(s protoreflect.Name) protoreflect.ExtensionDescriptor {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*Extension, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return extensionDesc{t}
|
||||
}
|
||||
func (p *extensions) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *extensions) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type enumsMeta struct {
|
||||
once sync.Once
|
||||
typs []Enum
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*Enum
|
||||
}
|
||||
type enums enumsMeta
|
||||
|
||||
func (p *enumsMeta) lazyInit(parent protoreflect.Descriptor, ts []Enum) *enums {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]enumMeta, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.enumMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.enumMeta = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, false)
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*enums)(p)
|
||||
}
|
||||
func (p *enums) Len() int { return len(p.typs) }
|
||||
func (p *enums) Get(i int) protoreflect.EnumDescriptor { return enumDesc{&p.typs[i]} }
|
||||
func (p *enums) ByName(s protoreflect.Name) protoreflect.EnumDescriptor {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*Enum, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return enumDesc{t}
|
||||
}
|
||||
func (p *enums) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *enums) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type enumValuesMeta struct {
|
||||
once sync.Once
|
||||
typs []EnumValue
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*EnumValue
|
||||
numOnce sync.Once
|
||||
byNum map[protoreflect.EnumNumber]*EnumValue
|
||||
}
|
||||
type enumValues enumValuesMeta
|
||||
|
||||
func (p *enumValuesMeta) lazyInit(parent protoreflect.Descriptor, ts []EnumValue) *enumValues {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]enumValueMeta, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.enumValueMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.enumValueMeta = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, true)
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*enumValues)(p)
|
||||
}
|
||||
func (p *enumValues) Len() int { return len(p.typs) }
|
||||
func (p *enumValues) Get(i int) protoreflect.EnumValueDescriptor { return enumValueDesc{&p.typs[i]} }
|
||||
func (p *enumValues) ByName(s protoreflect.Name) protoreflect.EnumValueDescriptor {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*EnumValue, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return enumValueDesc{t}
|
||||
}
|
||||
func (p *enumValues) ByNumber(n protoreflect.EnumNumber) protoreflect.EnumValueDescriptor {
|
||||
p.numOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byNum = make(map[protoreflect.EnumNumber]*EnumValue, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
if _, ok := p.byNum[t.Number]; !ok {
|
||||
p.byNum[t.Number] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byNum[n]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return enumValueDesc{t}
|
||||
}
|
||||
func (p *enumValues) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *enumValues) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type servicesMeta struct {
|
||||
once sync.Once
|
||||
typs []Service
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*Service
|
||||
}
|
||||
type services servicesMeta
|
||||
|
||||
func (p *servicesMeta) lazyInit(parent protoreflect.Descriptor, ts []Service) *services {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]serviceMeta, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.serviceMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.serviceMeta = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, false)
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*services)(p)
|
||||
}
|
||||
func (p *services) Len() int { return len(p.typs) }
|
||||
func (p *services) Get(i int) protoreflect.ServiceDescriptor { return serviceDesc{&p.typs[i]} }
|
||||
func (p *services) ByName(s protoreflect.Name) protoreflect.ServiceDescriptor {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*Service, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return serviceDesc{t}
|
||||
}
|
||||
func (p *services) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *services) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type methodsMeta struct {
|
||||
once sync.Once
|
||||
typs []Method
|
||||
nameOnce sync.Once
|
||||
byName map[protoreflect.Name]*Method
|
||||
}
|
||||
type methods methodsMeta
|
||||
|
||||
func (p *methodsMeta) lazyInit(parent protoreflect.Descriptor, ts []Method) *methods {
|
||||
p.once.Do(func() {
|
||||
nb := nameBuilderPool.Get().(*nameBuilder)
|
||||
defer nameBuilderPool.Put(nb)
|
||||
metas := make([]methodMeta, len(ts))
|
||||
for i := range ts {
|
||||
t := &ts[i]
|
||||
if t.methodMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
t.methodMeta = &metas[i]
|
||||
t.inheritedMeta.init(nb, parent, t.Name, false)
|
||||
}
|
||||
p.typs = ts
|
||||
})
|
||||
return (*methods)(p)
|
||||
}
|
||||
func (p *methods) Len() int { return len(p.typs) }
|
||||
func (p *methods) Get(i int) protoreflect.MethodDescriptor { return methodDesc{&p.typs[i]} }
|
||||
func (p *methods) ByName(s protoreflect.Name) protoreflect.MethodDescriptor {
|
||||
p.nameOnce.Do(func() {
|
||||
if len(p.typs) > 0 {
|
||||
p.byName = make(map[protoreflect.Name]*Method, len(p.typs))
|
||||
for i := range p.typs {
|
||||
t := &p.typs[i]
|
||||
p.byName[t.Name] = t
|
||||
}
|
||||
}
|
||||
})
|
||||
t := p.byName[s]
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return methodDesc{t}
|
||||
}
|
||||
func (p *methods) Format(s fmt.State, r rune) { formatList(s, r, p) }
|
||||
func (p *methods) ProtoInternal(pragma.DoNotImplement) {}
|
506
reflect/prototype/protofile_type.go
Normal file
506
reflect/prototype/protofile_type.go
Normal file
@ -0,0 +1,506 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/proto/internal/pragma"
|
||||
pref "google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// inheritedMeta is information inherited from the parent.
|
||||
type inheritedMeta struct {
|
||||
parent pref.Descriptor
|
||||
syntax pref.Syntax
|
||||
fullName pref.FullName
|
||||
|
||||
desc descriptorSubMeta
|
||||
opts descriptorOptionsMeta
|
||||
}
|
||||
|
||||
func (m *inheritedMeta) init(nb *nameBuilder, parent pref.Descriptor, name pref.Name, child bool) {
|
||||
// Most descriptors are namespaced as a child of their parent.
|
||||
// However, EnumValues are the exception in that they are namespaced
|
||||
// as a sibling of the parent Enum type.
|
||||
prefix := parent.FullName()
|
||||
if child {
|
||||
prefix = prefix.Parent()
|
||||
}
|
||||
|
||||
m.parent = parent
|
||||
m.syntax = parent.Syntax()
|
||||
m.fullName = nb.Append(prefix, name)
|
||||
}
|
||||
|
||||
type fileMeta struct {
|
||||
desc descriptorFileMeta
|
||||
opts descriptorOptionsMeta
|
||||
|
||||
ms messagesMeta
|
||||
es enumsMeta
|
||||
xs extensionsMeta
|
||||
ss servicesMeta
|
||||
}
|
||||
type fileDesc struct{ f *File }
|
||||
|
||||
func newFile(f *File) fileDesc {
|
||||
if f.fileMeta != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
f.fileMeta = new(fileMeta)
|
||||
return fileDesc{f}
|
||||
}
|
||||
func (t fileDesc) Parent() (pref.Descriptor, bool) { return nil, false }
|
||||
func (t fileDesc) Syntax() pref.Syntax { return t.f.Syntax }
|
||||
func (t fileDesc) Name() pref.Name { return t.f.Package.Name() }
|
||||
func (t fileDesc) FullName() pref.FullName { return t.f.Package }
|
||||
func (t fileDesc) IsPlaceholder() bool { return false }
|
||||
func (t fileDesc) DescriptorProto() (pref.Message, bool) { return t.f.desc.lazyInit(t) }
|
||||
func (t fileDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.f.opts.lazyInit(t) }
|
||||
func (t fileDesc) Path() string { return t.f.Path }
|
||||
func (t fileDesc) Package() pref.FullName { return t.f.Package }
|
||||
func (t fileDesc) Imports() pref.FileImports { return (*fileImports)(&t.f.Imports) }
|
||||
func (t fileDesc) Messages() pref.MessageDescriptors { return t.f.ms.lazyInit(t, t.f.Messages) }
|
||||
func (t fileDesc) Enums() pref.EnumDescriptors { return t.f.es.lazyInit(t, t.f.Enums) }
|
||||
func (t fileDesc) Extensions() pref.ExtensionDescriptors { return t.f.xs.lazyInit(t, t.f.Extensions) }
|
||||
func (t fileDesc) Services() pref.ServiceDescriptors { return t.f.ss.lazyInit(t, t.f.Services) }
|
||||
func (t fileDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t fileDesc) ProtoType(pref.FileDescriptor) {}
|
||||
func (t fileDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type messageMeta struct {
|
||||
inheritedMeta
|
||||
|
||||
fs fieldsMeta
|
||||
os oneofsMeta
|
||||
ns numbersMeta
|
||||
ms messagesMeta
|
||||
es enumsMeta
|
||||
xs extensionsMeta
|
||||
}
|
||||
type messageDesc struct{ m *Message }
|
||||
|
||||
func (t messageDesc) Parent() (pref.Descriptor, bool) { return t.m.parent, true }
|
||||
func (t messageDesc) Syntax() pref.Syntax { return t.m.syntax }
|
||||
func (t messageDesc) Name() pref.Name { return t.m.Name }
|
||||
func (t messageDesc) FullName() pref.FullName { return t.m.fullName }
|
||||
func (t messageDesc) IsPlaceholder() bool { return false }
|
||||
func (t messageDesc) DescriptorProto() (pref.Message, bool) { return t.m.desc.lazyInit(t) }
|
||||
func (t messageDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.m.opts.lazyInit(t) }
|
||||
func (t messageDesc) IsMapEntry() bool { return t.m.IsMapEntry }
|
||||
func (t messageDesc) Fields() pref.FieldDescriptors { return t.m.fs.lazyInit(t, t.m.Fields) }
|
||||
func (t messageDesc) Oneofs() pref.OneofDescriptors { return t.m.os.lazyInit(t, t.m.Oneofs) }
|
||||
func (t messageDesc) RequiredNumbers() pref.FieldNumbers { return t.m.ns.lazyInit(t.m.Fields) }
|
||||
func (t messageDesc) ExtensionRanges() pref.FieldRanges { return (*ranges)(&t.m.ExtensionRanges) }
|
||||
func (t messageDesc) Messages() pref.MessageDescriptors { return t.m.ms.lazyInit(t, t.m.Messages) }
|
||||
func (t messageDesc) Enums() pref.EnumDescriptors { return t.m.es.lazyInit(t, t.m.Enums) }
|
||||
func (t messageDesc) Extensions() pref.ExtensionDescriptors { return t.m.xs.lazyInit(t, t.m.Extensions) }
|
||||
func (t messageDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t messageDesc) ProtoType(pref.MessageDescriptor) {}
|
||||
func (t messageDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type fieldMeta struct {
|
||||
inheritedMeta
|
||||
|
||||
js jsonName
|
||||
dv defaultValue
|
||||
ot oneofReference
|
||||
mt messageReference
|
||||
et enumReference
|
||||
}
|
||||
type fieldDesc struct{ f *Field }
|
||||
|
||||
func (t fieldDesc) Parent() (pref.Descriptor, bool) { return t.f.parent, true }
|
||||
func (t fieldDesc) Syntax() pref.Syntax { return t.f.syntax }
|
||||
func (t fieldDesc) Name() pref.Name { return t.f.Name }
|
||||
func (t fieldDesc) FullName() pref.FullName { return t.f.fullName }
|
||||
func (t fieldDesc) IsPlaceholder() bool { return false }
|
||||
func (t fieldDesc) DescriptorProto() (pref.Message, bool) { return t.f.desc.lazyInit(t) }
|
||||
func (t fieldDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.f.opts.lazyInit(t) }
|
||||
func (t fieldDesc) Number() pref.FieldNumber { return t.f.Number }
|
||||
func (t fieldDesc) Cardinality() pref.Cardinality { return t.f.Cardinality }
|
||||
func (t fieldDesc) Kind() pref.Kind { return t.f.Kind }
|
||||
func (t fieldDesc) JSONName() string { return t.f.js.lazyInit(t.f) }
|
||||
func (t fieldDesc) IsPacked() bool { return t.f.IsPacked }
|
||||
func (t fieldDesc) IsMap() bool { return isMap(t) }
|
||||
func (t fieldDesc) IsWeak() bool { return t.f.IsWeak }
|
||||
func (t fieldDesc) Default() pref.Value { return t.f.dv.lazyInit(t, t.f.Default) }
|
||||
func (t fieldDesc) OneofType() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) }
|
||||
func (t fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
|
||||
func (t fieldDesc) MessageType() pref.MessageDescriptor { return t.f.mt.lazyInit(t, &t.f.MessageType) }
|
||||
func (t fieldDesc) EnumType() pref.EnumDescriptor { return t.f.et.lazyInit(t, &t.f.EnumType) }
|
||||
func (t fieldDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t fieldDesc) ProtoType(pref.FieldDescriptor) {}
|
||||
func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
func isMap(t pref.FieldDescriptor) bool {
|
||||
if t.Cardinality() == pref.Repeated && t.Kind() == pref.MessageKind {
|
||||
if mt := t.MessageType(); mt != nil {
|
||||
return mt.IsMapEntry()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type jsonName struct{ once sync.Once }
|
||||
|
||||
func (p *jsonName) lazyInit(f *Field) string {
|
||||
p.once.Do(func() {
|
||||
// TODO: We may need to share this logic with jsonpb for implementation
|
||||
// of the FieldMask well-known type.
|
||||
if f.JSONName != "" {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
var wasUnderscore bool
|
||||
for i := 0; i < len(f.Name); i++ { // proto identifiers are always ASCII
|
||||
c := f.Name[i]
|
||||
if c != '_' {
|
||||
isLower := 'a' <= c && c <= 'z'
|
||||
if wasUnderscore && isLower {
|
||||
c -= 'a' - 'A'
|
||||
}
|
||||
b = append(b, c)
|
||||
}
|
||||
wasUnderscore = c == '_'
|
||||
}
|
||||
f.JSONName = string(b)
|
||||
})
|
||||
return f.JSONName
|
||||
}
|
||||
|
||||
// oneofReference resolves the name of a oneof by searching the parent
|
||||
// message for the matching OneofDescriptor declaration.
|
||||
type oneofReference struct {
|
||||
once sync.Once
|
||||
otyp pref.OneofDescriptor
|
||||
}
|
||||
|
||||
func (p *oneofReference) lazyInit(parent pref.Descriptor, name pref.Name) pref.OneofDescriptor {
|
||||
p.once.Do(func() {
|
||||
if name != "" {
|
||||
mtyp, _ := parent.Parent()
|
||||
p.otyp = mtyp.(pref.MessageDescriptor).Oneofs().ByName(name)
|
||||
// TODO: We need validate to detect this mismatch.
|
||||
}
|
||||
})
|
||||
return p.otyp
|
||||
}
|
||||
|
||||
type oneofMeta struct {
|
||||
inheritedMeta
|
||||
|
||||
fs oneofFieldsMeta
|
||||
}
|
||||
type oneofDesc struct{ o *Oneof }
|
||||
|
||||
func (t oneofDesc) Parent() (pref.Descriptor, bool) { return t.o.parent, true }
|
||||
func (t oneofDesc) Syntax() pref.Syntax { return t.o.syntax }
|
||||
func (t oneofDesc) Name() pref.Name { return t.o.Name }
|
||||
func (t oneofDesc) FullName() pref.FullName { return t.o.fullName }
|
||||
func (t oneofDesc) IsPlaceholder() bool { return false }
|
||||
func (t oneofDesc) DescriptorProto() (pref.Message, bool) { return t.o.desc.lazyInit(t) }
|
||||
func (t oneofDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.o.opts.lazyInit(t) }
|
||||
func (t oneofDesc) Fields() pref.FieldDescriptors { return t.o.fs.lazyInit(t) }
|
||||
func (t oneofDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t oneofDesc) ProtoType(pref.OneofDescriptor) {}
|
||||
func (t oneofDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type extensionMeta struct {
|
||||
inheritedMeta
|
||||
|
||||
dv defaultValue
|
||||
xt messageReference
|
||||
mt messageReference
|
||||
et enumReference
|
||||
}
|
||||
type extensionDesc struct{ x *Extension }
|
||||
|
||||
func (t extensionDesc) Parent() (pref.Descriptor, bool) { return t.x.parent, true }
|
||||
func (t extensionDesc) Syntax() pref.Syntax { return t.x.syntax }
|
||||
func (t extensionDesc) Name() pref.Name { return t.x.Name }
|
||||
func (t extensionDesc) FullName() pref.FullName { return t.x.fullName }
|
||||
func (t extensionDesc) IsPlaceholder() bool { return false }
|
||||
func (t extensionDesc) DescriptorProto() (pref.Message, bool) { return t.x.desc.lazyInit(t) }
|
||||
func (t extensionDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.x.opts.lazyInit(t) }
|
||||
func (t extensionDesc) Number() pref.FieldNumber { return t.x.Number }
|
||||
func (t extensionDesc) Cardinality() pref.Cardinality { return t.x.Cardinality }
|
||||
func (t extensionDesc) Kind() pref.Kind { return t.x.Kind }
|
||||
func (t extensionDesc) JSONName() string { return "" }
|
||||
func (t extensionDesc) IsPacked() bool { return t.x.IsPacked }
|
||||
func (t extensionDesc) IsMap() bool { return false }
|
||||
func (t extensionDesc) IsWeak() bool { return false }
|
||||
func (t extensionDesc) Default() pref.Value { return t.x.dv.lazyInit(t, t.x.Default) }
|
||||
func (t extensionDesc) OneofType() pref.OneofDescriptor { return nil }
|
||||
func (t extensionDesc) ExtendedType() pref.MessageDescriptor {
|
||||
return t.x.xt.lazyInit(t, &t.x.ExtendedType)
|
||||
}
|
||||
func (t extensionDesc) MessageType() pref.MessageDescriptor {
|
||||
return t.x.mt.lazyInit(t, &t.x.MessageType)
|
||||
}
|
||||
func (t extensionDesc) EnumType() pref.EnumDescriptor { return t.x.et.lazyInit(t, &t.x.EnumType) }
|
||||
func (t extensionDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t extensionDesc) ProtoType(pref.FieldDescriptor) {}
|
||||
func (t extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type enumMeta struct {
|
||||
inheritedMeta
|
||||
|
||||
vs enumValuesMeta
|
||||
}
|
||||
type enumDesc struct{ e *Enum }
|
||||
|
||||
func (t enumDesc) Parent() (pref.Descriptor, bool) { return t.e.parent, true }
|
||||
func (t enumDesc) Syntax() pref.Syntax { return t.e.syntax }
|
||||
func (t enumDesc) Name() pref.Name { return t.e.Name }
|
||||
func (t enumDesc) FullName() pref.FullName { return t.e.fullName }
|
||||
func (t enumDesc) IsPlaceholder() bool { return false }
|
||||
func (t enumDesc) DescriptorProto() (pref.Message, bool) { return t.e.desc.lazyInit(t) }
|
||||
func (t enumDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.e.opts.lazyInit(t) }
|
||||
func (t enumDesc) Values() pref.EnumValueDescriptors { return t.e.vs.lazyInit(t, t.e.Values) }
|
||||
func (t enumDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t enumDesc) ProtoType(pref.EnumDescriptor) {}
|
||||
func (t enumDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type enumValueMeta struct {
|
||||
inheritedMeta
|
||||
}
|
||||
type enumValueDesc struct{ v *EnumValue }
|
||||
|
||||
func (t enumValueDesc) Parent() (pref.Descriptor, bool) { return t.v.parent, true }
|
||||
func (t enumValueDesc) Syntax() pref.Syntax { return t.v.syntax }
|
||||
func (t enumValueDesc) Name() pref.Name { return t.v.Name }
|
||||
func (t enumValueDesc) FullName() pref.FullName { return t.v.fullName }
|
||||
func (t enumValueDesc) IsPlaceholder() bool { return false }
|
||||
func (t enumValueDesc) DescriptorProto() (pref.Message, bool) { return t.v.desc.lazyInit(t) }
|
||||
func (t enumValueDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.v.opts.lazyInit(t) }
|
||||
func (t enumValueDesc) Number() pref.EnumNumber { return t.v.Number }
|
||||
func (t enumValueDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t enumValueDesc) ProtoType(pref.EnumValueDescriptor) {}
|
||||
func (t enumValueDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type serviceMeta struct {
|
||||
inheritedMeta
|
||||
|
||||
ms methodsMeta
|
||||
}
|
||||
type serviceDesc struct{ s *Service }
|
||||
|
||||
func (t serviceDesc) Parent() (pref.Descriptor, bool) { return t.s.parent, true }
|
||||
func (t serviceDesc) Syntax() pref.Syntax { return t.s.syntax }
|
||||
func (t serviceDesc) Name() pref.Name { return t.s.Name }
|
||||
func (t serviceDesc) FullName() pref.FullName { return t.s.fullName }
|
||||
func (t serviceDesc) IsPlaceholder() bool { return false }
|
||||
func (t serviceDesc) DescriptorProto() (pref.Message, bool) { return t.s.desc.lazyInit(t) }
|
||||
func (t serviceDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.s.opts.lazyInit(t) }
|
||||
func (t serviceDesc) Methods() pref.MethodDescriptors { return t.s.ms.lazyInit(t, t.s.Methods) }
|
||||
func (t serviceDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t serviceDesc) ProtoType(pref.ServiceDescriptor) {}
|
||||
func (t serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type methodMeta struct {
|
||||
inheritedMeta
|
||||
|
||||
mit messageReference
|
||||
mot messageReference
|
||||
}
|
||||
type methodDesc struct{ m *Method }
|
||||
|
||||
func (t methodDesc) Parent() (pref.Descriptor, bool) { return t.m.parent, true }
|
||||
func (t methodDesc) Syntax() pref.Syntax { return t.m.syntax }
|
||||
func (t methodDesc) Name() pref.Name { return t.m.Name }
|
||||
func (t methodDesc) FullName() pref.FullName { return t.m.fullName }
|
||||
func (t methodDesc) IsPlaceholder() bool { return false }
|
||||
func (t methodDesc) DescriptorProto() (pref.Message, bool) { return t.m.desc.lazyInit(t) }
|
||||
func (t methodDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.m.opts.lazyInit(t) }
|
||||
func (t methodDesc) InputType() pref.MessageDescriptor { return t.m.mit.lazyInit(t, &t.m.InputType) }
|
||||
func (t methodDesc) OutputType() pref.MessageDescriptor { return t.m.mot.lazyInit(t, &t.m.OutputType) }
|
||||
func (t methodDesc) IsStreamingClient() bool { return t.m.IsStreamingClient }
|
||||
func (t methodDesc) IsStreamingServer() bool { return t.m.IsStreamingServer }
|
||||
func (t methodDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t methodDesc) ProtoType(pref.MethodDescriptor) {}
|
||||
func (t methodDesc) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type defaultValue struct {
|
||||
once sync.Once
|
||||
val pref.Value
|
||||
buf []byte
|
||||
}
|
||||
|
||||
var (
|
||||
zeroBool = pref.ValueOf(false)
|
||||
zeroInt32 = pref.ValueOf(int32(0))
|
||||
zeroInt64 = pref.ValueOf(int64(0))
|
||||
zeroUint32 = pref.ValueOf(uint32(0))
|
||||
zeroUint64 = pref.ValueOf(uint64(0))
|
||||
zeroFloat32 = pref.ValueOf(float32(0))
|
||||
zeroFloat64 = pref.ValueOf(float64(0))
|
||||
zeroString = pref.ValueOf(string(""))
|
||||
zeroBytes = pref.ValueOf([]byte(nil))
|
||||
zeroEnum = pref.ValueOf(pref.EnumNumber(0))
|
||||
)
|
||||
|
||||
func (p *defaultValue) lazyInit(t pref.FieldDescriptor, v pref.Value) pref.Value {
|
||||
p.once.Do(func() {
|
||||
p.val = v
|
||||
if !v.IsNull() {
|
||||
if t.Kind() == pref.BytesKind {
|
||||
if b, ok := v.Interface().([]byte); ok && len(b) > 0 {
|
||||
p.buf = append([]byte(nil), b...)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
switch t.Kind() {
|
||||
case pref.BoolKind:
|
||||
p.val = zeroBool
|
||||
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
|
||||
p.val = zeroInt32
|
||||
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
|
||||
p.val = zeroInt64
|
||||
case pref.Uint32Kind, pref.Fixed32Kind:
|
||||
p.val = zeroUint32
|
||||
case pref.Uint64Kind, pref.Fixed64Kind:
|
||||
p.val = zeroUint64
|
||||
case pref.FloatKind:
|
||||
p.val = zeroFloat32
|
||||
case pref.DoubleKind:
|
||||
p.val = zeroFloat64
|
||||
case pref.StringKind:
|
||||
p.val = zeroString
|
||||
case pref.BytesKind:
|
||||
p.val = zeroBytes
|
||||
case pref.EnumKind:
|
||||
p.val = zeroEnum
|
||||
if t.Syntax() == pref.Proto2 {
|
||||
if et := t.EnumType(); et != nil {
|
||||
if vs := et.Values(); vs.Len() > 0 {
|
||||
p.val = pref.ValueOf(vs.Get(0).Number())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
if len(p.buf) > 0 && !bytes.Equal(p.buf, p.val.Bytes()) {
|
||||
// TODO: Avoid panic if we're running with the race detector and instead
|
||||
// spawn a goroutine that periodically resets this value back to the
|
||||
// original to induce a race that can be detected by the detector.
|
||||
panic(fmt.Sprintf("proto: detected mutation on the default bytes for %v", t.FullName()))
|
||||
}
|
||||
return p.val
|
||||
}
|
||||
|
||||
// messageReference resolves PlaceholderMessages that reference declarations
|
||||
// within the FileDescriptor tree that parent is a member of.
|
||||
type messageReference struct{ once sync.Once }
|
||||
|
||||
func (p *messageReference) lazyInit(parent pref.Descriptor, pt *pref.MessageDescriptor) pref.MessageDescriptor {
|
||||
p.once.Do(func() {
|
||||
if t := *pt; t != nil && t.IsPlaceholder() {
|
||||
if d, ok := resolveReference(parent, t.FullName()).(pref.MessageDescriptor); ok {
|
||||
*pt = d
|
||||
}
|
||||
}
|
||||
})
|
||||
return *pt
|
||||
}
|
||||
|
||||
// enumReference resolves PlaceholderEnums that reference declarations
|
||||
// within the FileDescriptor tree that parent is a member of.
|
||||
type enumReference struct{ once sync.Once }
|
||||
|
||||
func (p *enumReference) lazyInit(parent pref.Descriptor, pt *pref.EnumDescriptor) pref.EnumDescriptor {
|
||||
p.once.Do(func() {
|
||||
if t := *pt; t != nil && t.IsPlaceholder() {
|
||||
if d, ok := resolveReference(parent, t.FullName()).(pref.EnumDescriptor); ok {
|
||||
*pt = d
|
||||
}
|
||||
}
|
||||
})
|
||||
return *pt
|
||||
}
|
||||
|
||||
// resolveReference searches parent for the MessageDescriptor or EnumDescriptor
|
||||
// declaration identified by refName. This returns nil if not found.
|
||||
func resolveReference(parent pref.Descriptor, refName pref.FullName) pref.Descriptor {
|
||||
// Ascend upwards until a prefix match is found.
|
||||
cur := parent
|
||||
for cur != nil {
|
||||
curName := cur.FullName()
|
||||
if strings.HasPrefix(string(refName), string(curName)) {
|
||||
if len(refName) == len(curName) {
|
||||
refName = refName[len(curName):]
|
||||
break // e.g., refName: foo.firetruck, curName: foo.firetruck
|
||||
} else if refName[len(curName)] == '.' {
|
||||
refName = refName[len(curName)+len("."):]
|
||||
break // e.g., refName: foo.firetruck.driver, curName: foo.firetruck
|
||||
}
|
||||
// No match. (e.g., refName: foo.firetruck, curName: foo.fire)
|
||||
}
|
||||
cur, _ = cur.Parent() // nil after ascending above FileDescriptor
|
||||
}
|
||||
|
||||
// Descend downwards to resolve all relative names.
|
||||
for cur != nil && len(refName) > 0 {
|
||||
var head pref.Name
|
||||
head, refName = pref.Name(refName), ""
|
||||
if i := strings.IndexByte(string(head), '.'); i >= 0 {
|
||||
head, refName = head[:i], pref.FullName(head[i+len("."):])
|
||||
}
|
||||
|
||||
// Search the current descriptor for the nested declaration.
|
||||
var next pref.Descriptor
|
||||
if t, ok := cur.(interface {
|
||||
Messages() pref.MessageDescriptors
|
||||
}); ok && next == nil {
|
||||
if d := t.Messages().ByName(head); d != nil {
|
||||
next = d
|
||||
}
|
||||
}
|
||||
if t, ok := cur.(interface {
|
||||
Enums() pref.EnumDescriptors
|
||||
}); ok && next == nil {
|
||||
if d := t.Enums().ByName(head); d != nil {
|
||||
next = d
|
||||
}
|
||||
}
|
||||
cur = next // nil if not found
|
||||
}
|
||||
return cur
|
||||
}
|
||||
|
||||
var nameBuilderPool = sync.Pool{
|
||||
New: func() interface{} { return new(nameBuilder) },
|
||||
}
|
||||
|
||||
type nameBuilder struct {
|
||||
sb strings.Builder
|
||||
|
||||
// TODO: See https://golang.org/issue/26269
|
||||
rem int // conservative approximation for Cap-Len
|
||||
}
|
||||
|
||||
// Append is equivalent to protoreflect.FullName.Append, but is optimized for
|
||||
// large batches of operations where each name has a shared lifetime.
|
||||
func (b *nameBuilder) Append(prefix pref.FullName, name pref.Name) pref.FullName {
|
||||
const batchSize = 1 << 12
|
||||
n := len(prefix) + len(".") + len(name)
|
||||
if b.rem < n {
|
||||
b.sb.Reset()
|
||||
b.sb.Grow(batchSize)
|
||||
b.rem = batchSize - n
|
||||
}
|
||||
if !strings.HasSuffix(b.sb.String(), string(prefix)) {
|
||||
b.sb.WriteString(string(prefix))
|
||||
}
|
||||
b.sb.WriteByte('.')
|
||||
b.sb.WriteString(string(name))
|
||||
s := b.sb.String()
|
||||
return pref.FullName(strings.TrimPrefix(s[len(s)-n:], "."))
|
||||
}
|
85
reflect/prototype/standalone.go
Normal file
85
reflect/prototype/standalone.go
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// TODO: Should the constructors take in a value rather than a pointer?
|
||||
// TODO: Support initializing StandaloneMessage from a google.protobuf.Type?
|
||||
|
||||
// StandaloneMessage is a constructor for a protoreflect.MessageDescriptor
|
||||
// that does not have a parent and has no child declarations.
|
||||
type StandaloneMessage struct {
|
||||
Syntax protoreflect.Syntax
|
||||
FullName protoreflect.FullName
|
||||
IsMapEntry bool
|
||||
Fields []Field
|
||||
Oneofs []Oneof
|
||||
ExtensionRanges [][2]protoreflect.FieldNumber
|
||||
|
||||
fields fieldsMeta
|
||||
oneofs oneofsMeta
|
||||
nums numbersMeta
|
||||
}
|
||||
|
||||
// NewMessage creates a new protoreflect.MessageDescriptor.
|
||||
// The caller must relinquish full ownership of the input t and must not
|
||||
// access or mutate any fields.
|
||||
func NewMessage(t *StandaloneMessage) (protoreflect.MessageDescriptor, error) {
|
||||
mt := standaloneMessage{t}
|
||||
if err := validateMessage(mt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mt, nil
|
||||
}
|
||||
|
||||
// StandaloneEnum is a constructor for a protoreflect.EnumDescriptor
|
||||
// that does not have a parent.
|
||||
type StandaloneEnum struct {
|
||||
Syntax protoreflect.Syntax
|
||||
FullName protoreflect.FullName
|
||||
Values []EnumValue
|
||||
|
||||
vals enumValuesMeta
|
||||
}
|
||||
|
||||
// NewEnum creates a new protoreflect.EnumDescriptor.
|
||||
// The caller must relinquish full ownership of the input t and must not
|
||||
// access or mutate any fields.
|
||||
func NewEnum(t *StandaloneEnum) (protoreflect.EnumDescriptor, error) {
|
||||
et := standaloneEnum{t}
|
||||
if err := validateEnum(et); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return et, nil
|
||||
}
|
||||
|
||||
// StandaloneExtension is a constructor for a protoreflect.ExtensionDescriptor
|
||||
// that does not have a parent.
|
||||
type StandaloneExtension struct {
|
||||
Syntax protoreflect.Syntax
|
||||
FullName protoreflect.FullName
|
||||
Number protoreflect.FieldNumber
|
||||
Cardinality protoreflect.Cardinality
|
||||
Kind protoreflect.Kind
|
||||
IsPacked bool
|
||||
Default protoreflect.Value
|
||||
MessageType protoreflect.MessageDescriptor
|
||||
EnumType protoreflect.EnumDescriptor
|
||||
ExtendedType protoreflect.MessageDescriptor
|
||||
}
|
||||
|
||||
// NewExtension creates a new protoreflect.ExtensionDescriptor.
|
||||
// The caller must relinquish full ownership of the input t and must not
|
||||
// access or mutate any fields.
|
||||
func NewExtension(t *StandaloneExtension) (protoreflect.ExtensionDescriptor, error) {
|
||||
xt := standaloneExtension{t}
|
||||
if err := validateExtension(xt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return xt, nil
|
||||
}
|
72
reflect/prototype/standalone_type.go
Normal file
72
reflect/prototype/standalone_type.go
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/proto/internal/pragma"
|
||||
pref "google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
type standaloneMessage struct{ m *StandaloneMessage }
|
||||
|
||||
func (t standaloneMessage) Parent() (pref.Descriptor, bool) { return nil, false }
|
||||
func (t standaloneMessage) Syntax() pref.Syntax { return t.m.Syntax }
|
||||
func (t standaloneMessage) Name() pref.Name { return t.m.FullName.Name() }
|
||||
func (t standaloneMessage) FullName() pref.FullName { return t.m.FullName }
|
||||
func (t standaloneMessage) IsPlaceholder() bool { return false }
|
||||
func (t standaloneMessage) DescriptorProto() (pref.Message, bool) { return nil, false }
|
||||
func (t standaloneMessage) DescriptorOptions() (pref.DescriptorOptions, bool) { return nil, false }
|
||||
func (t standaloneMessage) IsMapEntry() bool { return t.m.IsMapEntry }
|
||||
func (t standaloneMessage) Fields() pref.FieldDescriptors { return t.m.fields.lazyInit(t, t.m.Fields) }
|
||||
func (t standaloneMessage) Oneofs() pref.OneofDescriptors { return t.m.oneofs.lazyInit(t, t.m.Oneofs) }
|
||||
func (t standaloneMessage) RequiredNumbers() pref.FieldNumbers { return t.m.nums.lazyInit(t.m.Fields) }
|
||||
func (t standaloneMessage) ExtensionRanges() pref.FieldRanges { return (*ranges)(&t.m.ExtensionRanges) }
|
||||
func (t standaloneMessage) Messages() pref.MessageDescriptors { return &emptyMessages }
|
||||
func (t standaloneMessage) Enums() pref.EnumDescriptors { return &emptyEnums }
|
||||
func (t standaloneMessage) Extensions() pref.ExtensionDescriptors { return &emptyExtensions }
|
||||
func (t standaloneMessage) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t standaloneMessage) ProtoType(pref.MessageDescriptor) {}
|
||||
func (t standaloneMessage) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type standaloneEnum struct{ e *StandaloneEnum }
|
||||
|
||||
func (t standaloneEnum) Parent() (pref.Descriptor, bool) { return nil, false }
|
||||
func (t standaloneEnum) Syntax() pref.Syntax { return t.e.Syntax }
|
||||
func (t standaloneEnum) Name() pref.Name { return t.e.FullName.Name() }
|
||||
func (t standaloneEnum) FullName() pref.FullName { return t.e.FullName }
|
||||
func (t standaloneEnum) IsPlaceholder() bool { return false }
|
||||
func (t standaloneEnum) DescriptorProto() (pref.Message, bool) { return nil, false }
|
||||
func (t standaloneEnum) DescriptorOptions() (pref.DescriptorOptions, bool) { return nil, false }
|
||||
func (t standaloneEnum) Values() pref.EnumValueDescriptors { return t.e.vals.lazyInit(t, t.e.Values) }
|
||||
func (t standaloneEnum) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t standaloneEnum) ProtoType(pref.EnumDescriptor) {}
|
||||
func (t standaloneEnum) ProtoInternal(pragma.DoNotImplement) {}
|
||||
|
||||
type standaloneExtension struct{ x *StandaloneExtension }
|
||||
|
||||
func (t standaloneExtension) Parent() (pref.Descriptor, bool) { return nil, false }
|
||||
func (t standaloneExtension) Syntax() pref.Syntax { return t.x.Syntax }
|
||||
func (t standaloneExtension) Name() pref.Name { return t.x.FullName.Name() }
|
||||
func (t standaloneExtension) FullName() pref.FullName { return t.x.FullName }
|
||||
func (t standaloneExtension) IsPlaceholder() bool { return false }
|
||||
func (t standaloneExtension) DescriptorProto() (pref.Message, bool) { return nil, false }
|
||||
func (t standaloneExtension) DescriptorOptions() (pref.DescriptorOptions, bool) { return nil, false }
|
||||
func (t standaloneExtension) Number() pref.FieldNumber { return t.x.Number }
|
||||
func (t standaloneExtension) Cardinality() pref.Cardinality { return t.x.Cardinality }
|
||||
func (t standaloneExtension) Kind() pref.Kind { return t.x.Kind }
|
||||
func (t standaloneExtension) JSONName() string { return "" }
|
||||
func (t standaloneExtension) IsPacked() bool { return t.x.IsPacked }
|
||||
func (t standaloneExtension) IsMap() bool { return false }
|
||||
func (t standaloneExtension) IsWeak() bool { return false }
|
||||
func (t standaloneExtension) Default() pref.Value { return t.x.Default }
|
||||
func (t standaloneExtension) OneofType() pref.OneofDescriptor { return nil }
|
||||
func (t standaloneExtension) MessageType() pref.MessageDescriptor { return t.x.MessageType }
|
||||
func (t standaloneExtension) EnumType() pref.EnumDescriptor { return t.x.EnumType }
|
||||
func (t standaloneExtension) ExtendedType() pref.MessageDescriptor { return t.x.ExtendedType }
|
||||
func (t standaloneExtension) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
|
||||
func (t standaloneExtension) ProtoType(pref.FieldDescriptor) {}
|
||||
func (t standaloneExtension) ProtoInternal(pragma.DoNotImplement) {}
|
26
reflect/prototype/stringer.go
Normal file
26
reflect/prototype/stringer.go
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/proto/internal/pragma"
|
||||
pref "google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// TODO: This is useful for print descriptor types in a human readable way.
|
||||
// This is not strictly necessary.
|
||||
|
||||
// list is an interface that matches any of the list interfaces defined in the
|
||||
// protoreflect package.
|
||||
type list interface {
|
||||
Len() int
|
||||
pragma.DoNotImplement
|
||||
}
|
||||
|
||||
func formatList(s fmt.State, r rune, vs list) {}
|
||||
|
||||
func formatDesc(s fmt.State, r rune, t pref.Descriptor) {}
|
585
reflect/prototype/type_test.go
Normal file
585
reflect/prototype/type_test.go
Normal file
@ -0,0 +1,585 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
pref "google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// TestDescriptors tests that the implementations do not declare additional
|
||||
// methods that do not exist on the interface types.
|
||||
func TestDescriptors(t *testing.T) {
|
||||
tests := []interface{}{
|
||||
[]pref.FileDescriptor{placeholderFile{}, fileDesc{}},
|
||||
[]pref.MessageDescriptor{placeholderMessage{}, standaloneMessage{}, messageDesc{}},
|
||||
[]pref.FieldDescriptor{standaloneExtension{}, fieldDesc{}, extensionDesc{}},
|
||||
[]pref.OneofDescriptor{oneofDesc{}},
|
||||
[]pref.EnumDescriptor{placeholderEnum{}, standaloneEnum{}, enumDesc{}},
|
||||
[]pref.EnumValueDescriptor{enumValueDesc{}},
|
||||
[]pref.ServiceDescriptor{serviceDesc{}},
|
||||
[]pref.MethodDescriptor{methodDesc{}},
|
||||
|
||||
[]pref.FileImports{(*fileImports)(nil)},
|
||||
[]pref.MessageDescriptors{(*messages)(nil)},
|
||||
[]pref.FieldNumbers{(*numbers)(nil)},
|
||||
[]pref.FieldRanges{(*ranges)(nil)},
|
||||
[]pref.FieldDescriptors{(*fields)(nil), (*oneofFields)(nil)},
|
||||
[]pref.OneofDescriptors{(*oneofs)(nil)},
|
||||
[]pref.ExtensionDescriptors{(*extensions)(nil)},
|
||||
[]pref.EnumDescriptors{(*enums)(nil)},
|
||||
[]pref.EnumValueDescriptors{(*enumValues)(nil)},
|
||||
[]pref.ServiceDescriptors{(*services)(nil)},
|
||||
[]pref.MethodDescriptors{(*methods)(nil)},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
v := reflect.ValueOf(tt) // []T where T is an interface
|
||||
ifaceType := v.Type().Elem()
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
implType := v.Index(i).Elem().Type()
|
||||
|
||||
var hasName bool
|
||||
for j := 0; j < implType.NumMethod(); j++ {
|
||||
if name := implType.Method(j).Name; name == "Format" {
|
||||
hasName = true
|
||||
} else if _, ok := ifaceType.MethodByName(name); !ok {
|
||||
t.Errorf("spurious method: %v.%v", implType, name)
|
||||
}
|
||||
}
|
||||
if !hasName {
|
||||
t.Errorf("missing method: %v.Format", implType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile(t *testing.T) {
|
||||
f := &File{
|
||||
Syntax: pref.Proto2,
|
||||
Path: "path/to/file.proto",
|
||||
Package: "test",
|
||||
Messages: []Message{{
|
||||
Name: "A", // "test.A"
|
||||
IsMapEntry: true,
|
||||
Fields: []Field{{
|
||||
Name: "key", // "test.A.key"
|
||||
Number: 1,
|
||||
Cardinality: pref.Optional,
|
||||
Kind: pref.StringKind,
|
||||
}, {
|
||||
Name: "value", // "test.A.value"
|
||||
Number: 2,
|
||||
Cardinality: pref.Optional,
|
||||
Kind: pref.MessageKind,
|
||||
MessageType: PlaceholderMessage("test.B"),
|
||||
}},
|
||||
}, {
|
||||
Name: "B", // "test.B"
|
||||
Fields: []Field{{
|
||||
Name: "field_one",
|
||||
Number: 1,
|
||||
Cardinality: pref.Optional,
|
||||
Kind: pref.StringKind,
|
||||
Default: pref.ValueOf("hello"),
|
||||
OneofName: "O1",
|
||||
}, {
|
||||
Name: "field_two",
|
||||
JSONName: "Field2",
|
||||
Number: 2,
|
||||
Cardinality: pref.Optional,
|
||||
Kind: pref.EnumKind,
|
||||
Default: pref.ValueOf(pref.EnumNumber(1)),
|
||||
EnumType: PlaceholderEnum("test.E1"),
|
||||
OneofName: "O2",
|
||||
}, {
|
||||
Name: "field_three",
|
||||
Number: 3,
|
||||
Cardinality: pref.Optional,
|
||||
Kind: pref.MessageKind,
|
||||
MessageType: PlaceholderMessage("test.C"),
|
||||
OneofName: "O2",
|
||||
}, {
|
||||
Name: "field_four",
|
||||
JSONName: "Field4",
|
||||
Number: 4,
|
||||
Cardinality: pref.Repeated,
|
||||
Kind: pref.MessageKind,
|
||||
MessageType: PlaceholderMessage("test.A"),
|
||||
}, {
|
||||
Name: "field_five",
|
||||
Number: 5,
|
||||
Cardinality: pref.Repeated,
|
||||
Kind: pref.Int32Kind,
|
||||
IsPacked: true,
|
||||
}, {
|
||||
Name: "field_six",
|
||||
Number: 6,
|
||||
Cardinality: pref.Required,
|
||||
Kind: pref.StringKind,
|
||||
}},
|
||||
Oneofs: []Oneof{{Name: "O1"}, {Name: "O2"}},
|
||||
ExtensionRanges: [][2]pref.FieldNumber{{1000, 2000}},
|
||||
}, {
|
||||
Name: "C", // "test.C"
|
||||
Messages: []Message{{
|
||||
Name: "A", // "test.C.A"
|
||||
Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Required, Kind: pref.BytesKind}},
|
||||
}},
|
||||
Enums: []Enum{{
|
||||
Name: "E1", // "test.C.E1"
|
||||
Values: []EnumValue{{Name: "FOO", Number: 0}, {Name: "BAR", Number: 1}},
|
||||
}},
|
||||
Extensions: []Extension{{
|
||||
Name: "X", // "test.C.X"
|
||||
Number: 1000,
|
||||
Cardinality: pref.Repeated,
|
||||
Kind: pref.MessageKind,
|
||||
IsPacked: false,
|
||||
MessageType: PlaceholderMessage("test.C"),
|
||||
ExtendedType: PlaceholderMessage("test.B"),
|
||||
}},
|
||||
}},
|
||||
Enums: []Enum{{
|
||||
Name: "E1", // "test.E1"
|
||||
Values: []EnumValue{{Name: "FOO", Number: 0}, {Name: "BAR", Number: 1}},
|
||||
}},
|
||||
Extensions: []Extension{{
|
||||
Name: "X", // "test.X"
|
||||
Number: 1000,
|
||||
Cardinality: pref.Repeated,
|
||||
Kind: pref.MessageKind,
|
||||
IsPacked: false,
|
||||
MessageType: PlaceholderMessage("test.C"),
|
||||
ExtendedType: PlaceholderMessage("test.B"),
|
||||
}},
|
||||
Services: []Service{{
|
||||
Name: "S", // "test.S"
|
||||
Methods: []Method{{
|
||||
Name: "M", // "test.S.M"
|
||||
InputType: PlaceholderMessage("test.A"),
|
||||
OutputType: PlaceholderMessage("test.C.A"),
|
||||
IsStreamingClient: true,
|
||||
IsStreamingServer: true,
|
||||
}},
|
||||
}},
|
||||
}
|
||||
|
||||
fd, err := NewFile(f)
|
||||
if err != nil {
|
||||
t.Fatalf("NewFile() error: %v", err)
|
||||
}
|
||||
|
||||
// Represent the descriptor as a map where each key is an accessor method
|
||||
// and the value is either the wanted tail value or another accessor map.
|
||||
type M = map[string]interface{}
|
||||
want := M{
|
||||
"Parent": nil,
|
||||
"Syntax": pref.Proto2,
|
||||
"Name": pref.Name("test"),
|
||||
"FullName": pref.FullName("test"),
|
||||
"Path": "path/to/file.proto",
|
||||
"Package": pref.FullName("test"),
|
||||
"IsPlaceholder": false,
|
||||
"Messages": M{
|
||||
"Len": 3,
|
||||
"Get:0": M{
|
||||
"Parent": M{"FullName": pref.FullName("test")},
|
||||
"Syntax": pref.Proto2,
|
||||
"Name": pref.Name("A"),
|
||||
"FullName": pref.FullName("test.A"),
|
||||
"IsPlaceholder": false,
|
||||
"IsMapEntry": true,
|
||||
"Fields": M{
|
||||
"Len": 2,
|
||||
"ByNumber:1": M{
|
||||
"Parent": M{"FullName": pref.FullName("test.A")},
|
||||
"Name": pref.Name("key"),
|
||||
"FullName": pref.FullName("test.A.key"),
|
||||
"Number": pref.FieldNumber(1),
|
||||
"Cardinality": pref.Optional,
|
||||
"Kind": pref.StringKind,
|
||||
"JSONName": "key",
|
||||
"IsPacked": false,
|
||||
"IsMap": false,
|
||||
"IsWeak": false,
|
||||
"Default": "",
|
||||
"OneofType": nil,
|
||||
"ExtendedType": nil,
|
||||
"MessageType": nil,
|
||||
"EnumType": nil,
|
||||
},
|
||||
"ByNumber:2": M{
|
||||
"Parent": M{"FullName": pref.FullName("test.A")},
|
||||
"Name": pref.Name("value"),
|
||||
"FullName": pref.FullName("test.A.value"),
|
||||
"Number": pref.FieldNumber(2),
|
||||
"Cardinality": pref.Optional,
|
||||
"Kind": pref.MessageKind,
|
||||
"JSONName": "value",
|
||||
"IsPacked": false,
|
||||
"IsMap": false,
|
||||
"IsWeak": false,
|
||||
"Default": nil,
|
||||
"OneofType": nil,
|
||||
"ExtendedType": nil,
|
||||
"MessageType": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
|
||||
"EnumType": nil,
|
||||
},
|
||||
"ByNumber:3": nil,
|
||||
},
|
||||
"Oneofs": M{"Len": 0},
|
||||
"RequiredNumbers": M{"Len": 0},
|
||||
"ExtensionRanges": M{"Len": 0},
|
||||
"Messages": M{"Len": 0},
|
||||
"Enums": M{"Len": 0},
|
||||
"Extensions": M{"Len": 0},
|
||||
},
|
||||
"ByName:B": M{
|
||||
"Name": pref.Name("B"),
|
||||
"Fields": M{
|
||||
"Len": 6,
|
||||
"ByJSONName:field_one": nil,
|
||||
"ByJSONName:fieldOne": M{
|
||||
"Name": pref.Name("field_one"),
|
||||
"JSONName": "fieldOne",
|
||||
"Default": "hello",
|
||||
"OneofType": M{"Name": pref.Name("O1"), "IsPlaceholder": false},
|
||||
},
|
||||
"ByJSONName:fieldTwo": nil,
|
||||
"ByJSONName:Field2": M{
|
||||
"Name": pref.Name("field_two"),
|
||||
"JSONName": "Field2",
|
||||
"Default": pref.EnumNumber(1),
|
||||
"OneofType": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
|
||||
},
|
||||
"ByName:fieldThree": nil,
|
||||
"ByName:field_three": M{
|
||||
"IsMap": false,
|
||||
"MessageType": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
|
||||
"OneofType": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
|
||||
},
|
||||
"ByNumber:12": nil,
|
||||
"ByNumber:4": M{
|
||||
"Cardinality": pref.Repeated,
|
||||
"IsMap": true,
|
||||
"Default": nil,
|
||||
"MessageType": M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
|
||||
},
|
||||
"ByNumber:5": M{
|
||||
"Cardinality": pref.Repeated,
|
||||
"Kind": pref.Int32Kind,
|
||||
"IsPacked": true,
|
||||
"Default": int32(0),
|
||||
},
|
||||
"ByNumber:6": M{
|
||||
"Cardinality": pref.Required,
|
||||
"Default": "",
|
||||
"OneofType": nil,
|
||||
},
|
||||
},
|
||||
"Oneofs": M{
|
||||
"Len": 2,
|
||||
"ByName:O0": nil,
|
||||
"ByName:O1": M{
|
||||
"FullName": pref.FullName("test.B.O1"),
|
||||
"Fields": M{
|
||||
"Len": 1,
|
||||
"Get:0": M{"FullName": pref.FullName("test.B.field_one")},
|
||||
},
|
||||
},
|
||||
"Get:1": M{
|
||||
"FullName": pref.FullName("test.B.O2"),
|
||||
"Fields": M{
|
||||
"Len": 2,
|
||||
"ByName:field_two": M{"Name": pref.Name("field_two")},
|
||||
"Get:1": M{"Name": pref.Name("field_three")},
|
||||
},
|
||||
},
|
||||
},
|
||||
"RequiredNumbers": M{
|
||||
"Len": 1,
|
||||
"Get:0": pref.FieldNumber(6),
|
||||
"Has:1": false,
|
||||
"Has:6": true,
|
||||
},
|
||||
"ExtensionRanges": M{
|
||||
"Len": 1,
|
||||
"Get:0": [2]pref.FieldNumber{1000, 2000},
|
||||
"Has:999": false,
|
||||
"Has:1000": true,
|
||||
"Has:1500": true,
|
||||
"Has:1999": true,
|
||||
"Has:2000": false,
|
||||
},
|
||||
},
|
||||
"Get:2": M{
|
||||
"Name": pref.Name("C"),
|
||||
"Messages": M{
|
||||
"Len": 1,
|
||||
"Get:0": M{"FullName": pref.FullName("test.C.A")},
|
||||
},
|
||||
"Enums": M{
|
||||
"Len": 1,
|
||||
"Get:0": M{"FullName": pref.FullName("test.C.E1")},
|
||||
},
|
||||
"Extensions": M{
|
||||
"Len": 1,
|
||||
"Get:0": M{"FullName": pref.FullName("test.C.X")},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Enums": M{
|
||||
"Len": 1,
|
||||
"Get:0": M{
|
||||
"Name": pref.Name("E1"),
|
||||
"Values": M{
|
||||
"Len": 2,
|
||||
"ByName:Foo": nil,
|
||||
"ByName:FOO": M{"FullName": pref.FullName("test.FOO")},
|
||||
"ByNumber:2": nil,
|
||||
"ByNumber:1": M{"FullName": pref.FullName("test.BAR")},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Extensions": M{
|
||||
"Len": 1,
|
||||
"ByName:X": M{
|
||||
"Name": pref.Name("X"),
|
||||
"Number": pref.FieldNumber(1000),
|
||||
"Cardinality": pref.Repeated,
|
||||
"Kind": pref.MessageKind,
|
||||
"IsPacked": false,
|
||||
"MessageType": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
|
||||
"ExtendedType": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
|
||||
},
|
||||
},
|
||||
"Services": M{
|
||||
"Len": 1,
|
||||
"ByName:s": nil,
|
||||
"ByName:S": M{
|
||||
"Parent": M{"FullName": pref.FullName("test")},
|
||||
"Name": pref.Name("S"),
|
||||
"FullName": pref.FullName("test.S"),
|
||||
"Methods": M{
|
||||
"Len": 1,
|
||||
"Get:0": M{
|
||||
"Parent": M{"FullName": pref.FullName("test.S")},
|
||||
"Name": pref.Name("M"),
|
||||
"FullName": pref.FullName("test.S.M"),
|
||||
"InputType": M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
|
||||
"OutputType": M{"FullName": pref.FullName("test.C.A"), "IsPlaceholder": false},
|
||||
"IsStreamingClient": true,
|
||||
"IsStreamingServer": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Concurrently explore the file tree to induce races.
|
||||
const numGoRoutines = 2
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
for i := 0; i < numGoRoutines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
checkAccessors(t, "", reflect.ValueOf(fd), want)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func checkAccessors(t *testing.T, p string, rv reflect.Value, want map[string]interface{}) {
|
||||
if rv.Interface() == nil {
|
||||
t.Errorf("%v is nil, want non-nil", p)
|
||||
return
|
||||
}
|
||||
for s, v := range want {
|
||||
// Call the accessor method.
|
||||
p := p + "." + s
|
||||
var rets []reflect.Value
|
||||
if i := strings.IndexByte(s, ':'); i >= 0 {
|
||||
// Accessor method takes in a single argument, which is encoded
|
||||
// after the accessor name, separated by a ':' delimiter.
|
||||
fnc := rv.MethodByName(s[:i])
|
||||
arg := reflect.New(fnc.Type().In(0)).Elem()
|
||||
s = s[i+len(":"):]
|
||||
switch arg.Kind() {
|
||||
case reflect.String:
|
||||
arg.SetString(s)
|
||||
case reflect.Int32, reflect.Int:
|
||||
n, _ := strconv.ParseInt(s, 0, 64)
|
||||
arg.SetInt(n)
|
||||
}
|
||||
rets = fnc.Call([]reflect.Value{arg})
|
||||
} else {
|
||||
rets = rv.MethodByName(s).Call(nil)
|
||||
}
|
||||
|
||||
// Check that (val, ok) pattern is internally consistent.
|
||||
if len(rets) == 2 {
|
||||
if rets[0].IsNil() && rets[1].Bool() {
|
||||
t.Errorf("%v = (nil, true), want (nil, false)", p)
|
||||
}
|
||||
if !rets[0].IsNil() && !rets[1].Bool() {
|
||||
t.Errorf("%v = (non-nil, false), want (non-nil, true)", p)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the accessor output matches.
|
||||
if want, ok := v.(map[string]interface{}); ok {
|
||||
checkAccessors(t, p, rets[0], want)
|
||||
} else {
|
||||
got := rets[0].Interface()
|
||||
if pv, ok := got.(pref.Value); ok {
|
||||
got = pv.Interface()
|
||||
}
|
||||
if want := v; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("%v = %v, want %v", p, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolve(t *testing.T) {
|
||||
f := &File{
|
||||
Syntax: pref.Proto2,
|
||||
Package: "test",
|
||||
Messages: []Message{{
|
||||
Name: "FooMessage",
|
||||
Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
|
||||
Messages: []Message{{
|
||||
Name: "FooMessage",
|
||||
Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
|
||||
}, {
|
||||
Name: "BarMessage",
|
||||
Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
|
||||
}},
|
||||
Enums: []Enum{{
|
||||
Name: "FooEnum",
|
||||
Values: []EnumValue{{Name: "E", Number: 0}},
|
||||
}, {
|
||||
Name: "BarEnum",
|
||||
Values: []EnumValue{{Name: "E", Number: 0}},
|
||||
}},
|
||||
}, {
|
||||
Name: "BarMessage",
|
||||
Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
|
||||
}},
|
||||
Enums: []Enum{{
|
||||
Name: "FooEnum",
|
||||
Values: []EnumValue{{Name: "E", Number: 0}},
|
||||
}, {
|
||||
Name: "BarEnum",
|
||||
Values: []EnumValue{{Name: "E", Number: 0}},
|
||||
}},
|
||||
}
|
||||
|
||||
fd, err := NewFile(f)
|
||||
if err != nil {
|
||||
t.Fatalf("NewFile() error: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
parent pref.Descriptor
|
||||
name pref.FullName
|
||||
want pref.Descriptor
|
||||
}{{
|
||||
parent: fd.Enums().Get(0),
|
||||
name: "test.Foo",
|
||||
want: nil,
|
||||
}, {
|
||||
parent: fd.Enums().Get(0),
|
||||
name: "test.FooEnum",
|
||||
want: fd.Enums().Get(0),
|
||||
}, {
|
||||
parent: fd.Enums().Get(0),
|
||||
name: "test.BarEnum",
|
||||
want: fd.Enums().Get(1),
|
||||
}, {
|
||||
parent: fd.Enums().Get(0),
|
||||
name: "test.BarMessage",
|
||||
want: fd.Messages().Get(1),
|
||||
}, {
|
||||
parent: fd.Enums().Get(0),
|
||||
name: "test.FooMessage.BarMessage",
|
||||
want: fd.Messages().Get(0).Messages().Get(1),
|
||||
}, {
|
||||
parent: fd.Enums().Get(0),
|
||||
name: "test.FooMessage.Bar",
|
||||
want: nil,
|
||||
}, {
|
||||
parent: fd.Messages().Get(1),
|
||||
name: "test.FooMessage.BarEnum",
|
||||
want: fd.Messages().Get(0).Enums().Get(1),
|
||||
}, {
|
||||
parent: fd.Messages().Get(1),
|
||||
name: "test.FooEnum",
|
||||
want: fd.Enums().Get(0),
|
||||
}, {
|
||||
parent: fd.Messages().Get(0),
|
||||
name: "test.FooEnum",
|
||||
want: fd.Enums().Get(0),
|
||||
}, {
|
||||
parent: fd.Messages().Get(0),
|
||||
name: "test.FooEnum.NonExistent",
|
||||
want: nil,
|
||||
}, {
|
||||
parent: fd.Messages().Get(0),
|
||||
name: "test.FooMessage.FooEnum",
|
||||
want: fd.Messages().Get(0).Enums().Get(0),
|
||||
}, {
|
||||
parent: fd.Messages().Get(0),
|
||||
name: "test.FooMessage",
|
||||
want: fd.Messages().Get(0),
|
||||
}, {
|
||||
parent: fd.Messages().Get(0),
|
||||
name: "test.FooMessage.Fizz",
|
||||
want: nil,
|
||||
}, {
|
||||
parent: fd.Messages().Get(0).Messages().Get(0),
|
||||
name: "test.FooMessage.FooMessage",
|
||||
want: fd.Messages().Get(0).Messages().Get(0),
|
||||
}, {
|
||||
parent: fd.Messages().Get(0).Messages().Get(0),
|
||||
name: "test.FooMessage.BarMessage",
|
||||
want: fd.Messages().Get(0).Messages().Get(1),
|
||||
}, {
|
||||
parent: fd.Messages().Get(0).Messages().Get(0),
|
||||
name: "test.BarMessage.FooMessage",
|
||||
want: nil,
|
||||
}, {
|
||||
parent: fd.Messages().Get(0).Messages().Get(0),
|
||||
name: "test.BarMessage",
|
||||
want: fd.Messages().Get(1),
|
||||
}, {
|
||||
parent: fd.Messages().Get(0).Messages().Get(0),
|
||||
name: "test.BarMessageExtra",
|
||||
want: nil,
|
||||
}, {
|
||||
parent: fd.Messages().Get(0).Messages().Get(0),
|
||||
name: "taste.BarMessage",
|
||||
want: nil,
|
||||
}}
|
||||
|
||||
for _, tt := range tests {
|
||||
got := resolveReference(tt.parent, tt.name)
|
||||
if got != tt.want {
|
||||
fullName := func(d pref.Descriptor) string {
|
||||
if d == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return string(d.FullName())
|
||||
}
|
||||
t.Errorf("resolveReference(%v, %v) = %v, want %v", fullName(tt.parent), tt.name, fullName(got), fullName(tt.want))
|
||||
}
|
||||
}
|
||||
}
|
28
reflect/prototype/validate.go
Normal file
28
reflect/prototype/validate.go
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prototype
|
||||
|
||||
import (
|
||||
pref "google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// TODO: This is important to prevent users from creating invalid types,
|
||||
// but is not functionality needed now.
|
||||
|
||||
func validateFile(t pref.FileDescriptor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateMessage(t pref.MessageDescriptor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateExtension(t pref.ExtensionDescriptor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateEnum(t pref.EnumDescriptor) error {
|
||||
return nil
|
||||
}
|
12
test.bash
12
test.bash
@ -29,8 +29,8 @@ fi
|
||||
export PATH=$TEST_DIR/$PROTOBUF_DIR/src:$TEST_DIR/$PROTOBUF_DIR/conformance:$PATH
|
||||
|
||||
# Download each Go toolchain version.
|
||||
GO_LATEST=1.11beta3
|
||||
GO_VERSIONS=(1.9.7 1.10.3 $GO_LATEST)
|
||||
GO_LATEST=1.11rc1
|
||||
GO_VERSIONS=(1.10.3 $GO_LATEST)
|
||||
for GO_VERSION in ${GO_VERSIONS[@]}; do
|
||||
GO_DIR=go$GO_VERSION
|
||||
if [ ! -d $GO_DIR ]; then
|
||||
@ -91,7 +91,13 @@ for I in ${!PIDS[@]}; do
|
||||
fi
|
||||
done
|
||||
|
||||
# TODO: Check for stale generated Go source files.
|
||||
# Check for stale generated source files.
|
||||
GEN_DIFF=$(cd $REPO_ROOT && ${GO_LATEST_BIN} run ./internal/cmd/generate-types 2>&1)
|
||||
if [ ! -z "$GEN_DIFF" ]; then
|
||||
print "go run ./internal/cmd/generate-types"
|
||||
echo "$GEN_DIFF"
|
||||
RET=1
|
||||
fi
|
||||
|
||||
# Check for unformatted Go source files.
|
||||
FMT_DIFF=$(cd $REPO_ROOT && ${GO_LATEST_BIN}fmt -d . 2>&1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user