| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- // Copyright 2019 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 constructors for protoreflect.EnumType,
- // protoreflect.MessageType, and protoreflect.ExtensionType.
- package prototype
- import (
- "fmt"
- "reflect"
- "sync"
- "google.golang.org/protobuf/internal/descfmt"
- "google.golang.org/protobuf/internal/value"
- "google.golang.org/protobuf/reflect/protoreflect"
- )
- // Enum is a protoreflect.EnumType which combines a
- // protoreflect.EnumDescriptor with a constructor function.
- //
- // Both EnumDescriptor and NewEnum must be populated.
- // Once constructed, the exported fields must not be modified.
- type Enum struct {
- protoreflect.EnumDescriptor
- // NewEnum constructs a new protoreflect.Enum representing the provided
- // enum number. The returned Go type must be identical for every call.
- NewEnum func(protoreflect.EnumNumber) protoreflect.Enum
- once sync.Once
- goType reflect.Type
- }
- func (t *Enum) New(n protoreflect.EnumNumber) protoreflect.Enum {
- e := t.NewEnum(n)
- t.once.Do(func() {
- t.goType = reflect.TypeOf(e)
- if e.Descriptor() != t.Descriptor() {
- panic(fmt.Sprintf("mismatching enum descriptor: got %v, want %v", e.Descriptor(), t.Descriptor()))
- }
- if e.Descriptor().IsPlaceholder() {
- panic("enum descriptor must not be a placeholder")
- }
- })
- if t.goType != reflect.TypeOf(e) {
- panic(fmt.Sprintf("mismatching types for enum: got %T, want %v", e, t.goType))
- }
- return e
- }
- func (t *Enum) GoType() reflect.Type {
- t.New(0) // initialize t.typ
- return t.goType
- }
- func (t *Enum) Descriptor() protoreflect.EnumDescriptor {
- return t.EnumDescriptor
- }
- func (t *Enum) Format(s fmt.State, r rune) {
- descfmt.FormatDesc(s, r, t)
- }
- // Message is a protoreflect.MessageType which combines a
- // protoreflect.MessageDescriptor with a constructor function.
- //
- // Both MessageDescriptor and NewMessage must be populated.
- // Once constructed, the exported fields must not be modified.
- type Message struct {
- protoreflect.MessageDescriptor
- // NewMessage constructs an empty, newly allocated protoreflect.Message.
- // The returned Go type must be identical for every call.
- NewMessage func() protoreflect.Message
- once sync.Once
- goType reflect.Type
- }
- func (t *Message) New() protoreflect.Message {
- m := t.NewMessage()
- mi := m.Interface()
- t.once.Do(func() {
- t.goType = reflect.TypeOf(mi)
- if m.Descriptor() != t.Descriptor() {
- panic(fmt.Sprintf("mismatching message descriptor: got %v, want %v", m.Descriptor(), t.Descriptor()))
- }
- if m.Descriptor().IsPlaceholder() {
- panic("message descriptor must not be a placeholder")
- }
- })
- if t.goType != reflect.TypeOf(mi) {
- panic(fmt.Sprintf("mismatching types for message: got %T, want %v", mi, t.goType))
- }
- return m
- }
- func (t *Message) GoType() reflect.Type {
- t.New() // initialize t.goType
- return t.goType
- }
- func (t *Message) Descriptor() protoreflect.MessageDescriptor {
- return t.MessageDescriptor
- }
- func (t *Message) Format(s fmt.State, r rune) {
- descfmt.FormatDesc(s, r, t)
- }
- // Extension is a protoreflect.ExtensionType which combines a
- // protoreflect.ExtensionDescriptor with a constructor function.
- //
- // ExtensionDescriptor must be populated, while NewEnum or NewMessage must
- // populated depending on the kind of the extension field.
- // Once constructed, the exported fields must not be modified.
- type Extension struct {
- protoreflect.ExtensionDescriptor
- // NewEnum constructs a new enum (see Enum.NewEnum).
- // This must be populated if and only if ExtensionDescriptor.Kind
- // is a protoreflect.EnumKind.
- NewEnum func(protoreflect.EnumNumber) protoreflect.Enum
- // NewMessage constructs a new message (see Enum.NewMessage).
- // This must be populated if and only if ExtensionDescriptor.Kind
- // is a protoreflect.MessageKind or protoreflect.GroupKind.
- NewMessage func() protoreflect.Message
- // TODO: Allow users to manually set new, valueOf, and interfaceOf.
- // This allows users to implement custom composite types (e.g., List) or
- // custom Go types for primitives (e.g., int32).
- once sync.Once
- goType reflect.Type
- new func() protoreflect.Value
- valueOf func(v interface{}) protoreflect.Value
- interfaceOf func(v protoreflect.Value) interface{}
- }
- func (t *Extension) New() protoreflect.Value {
- t.lazyInit()
- pv := t.new()
- v := t.interfaceOf(pv)
- if reflect.TypeOf(v) != t.goType {
- panic(fmt.Sprintf("invalid type: got %T, want %v", v, t.goType))
- }
- return pv
- }
- func (t *Extension) ValueOf(v interface{}) protoreflect.Value {
- t.lazyInit()
- if reflect.TypeOf(v) != t.goType {
- panic(fmt.Sprintf("invalid type: got %T, want %v", v, t.goType))
- }
- return t.valueOf(v)
- }
- func (t *Extension) InterfaceOf(v protoreflect.Value) interface{} {
- t.lazyInit()
- vi := t.interfaceOf(v)
- if reflect.TypeOf(vi) != t.goType {
- panic(fmt.Sprintf("invalid type: got %T, want %v", vi, t.goType))
- }
- return vi
- }
- // GoType is the type of the extension field.
- // The type is T for scalars and *[]T for lists (maps are not allowed).
- // The type T is determined as follows:
- //
- // +------------+-------------------------------------+
- // | Go type | Protobuf kind |
- // +------------+-------------------------------------+
- // | bool | BoolKind |
- // | int32 | Int32Kind, Sint32Kind, Sfixed32Kind |
- // | int64 | Int64Kind, Sint64Kind, Sfixed64Kind |
- // | uint32 | Uint32Kind, Fixed32Kind |
- // | uint64 | Uint64Kind, Fixed64Kind |
- // | float32 | FloatKind |
- // | float64 | DoubleKind |
- // | string | StringKind |
- // | []byte | BytesKind |
- // | E | EnumKind |
- // | M | MessageKind, GroupKind |
- // +------------+-------------------------------------+
- //
- // The type E is the concrete enum type returned by NewEnum,
- // which is often, but not required to be, a named int32 type.
- // The type M is the concrete message type returned by NewMessage,
- // which is often, but not required to be, a pointer to a named struct type.
- func (t *Extension) GoType() reflect.Type {
- t.lazyInit()
- return t.goType
- }
- func (t *Extension) Descriptor() protoreflect.ExtensionDescriptor {
- return t.ExtensionDescriptor
- }
- func (t *Extension) Format(s fmt.State, r rune) {
- descfmt.FormatDesc(s, r, t)
- }
- func (t *Extension) lazyInit() {
- t.once.Do(func() {
- switch t.Kind() {
- case protoreflect.EnumKind:
- if t.NewEnum == nil || t.NewMessage != nil {
- panic("NewEnum alone must be set")
- }
- e := t.NewEnum(0)
- if e.Descriptor() != t.Enum() {
- panic(fmt.Sprintf("mismatching enum descriptor: got %v, want %v", e.Descriptor(), t.Enum()))
- }
- t.goType = reflect.TypeOf(e)
- case protoreflect.MessageKind, protoreflect.GroupKind:
- if t.NewEnum != nil || t.NewMessage == nil {
- panic("NewMessage alone must be set")
- }
- m := t.NewMessage()
- if m.Descriptor() != t.Message() {
- panic(fmt.Sprintf("mismatching message descriptor: got %v, want %v", m.Descriptor(), t.Message()))
- }
- t.goType = reflect.TypeOf(m.Interface())
- default:
- if t.NewEnum != nil || t.NewMessage != nil {
- panic("neither NewEnum nor NewMessage may be set")
- }
- t.goType = goTypeForPBKind[t.Kind()]
- }
- switch t.Cardinality() {
- case protoreflect.Optional:
- switch t.Kind() {
- case protoreflect.EnumKind:
- t.new = func() protoreflect.Value {
- return t.Default()
- }
- t.valueOf = func(v interface{}) protoreflect.Value {
- ev := v.(protoreflect.Enum)
- return protoreflect.ValueOf(ev.Number())
- }
- t.interfaceOf = func(v protoreflect.Value) interface{} {
- return t.NewEnum(v.Enum())
- }
- case protoreflect.MessageKind, protoreflect.GroupKind:
- t.new = func() protoreflect.Value {
- return protoreflect.ValueOf(t.NewMessage())
- }
- t.valueOf = func(v interface{}) protoreflect.Value {
- mv := v.(protoreflect.ProtoMessage).ProtoReflect()
- return protoreflect.ValueOf(mv)
- }
- t.interfaceOf = func(v protoreflect.Value) interface{} {
- return v.Message().Interface()
- }
- default:
- t.new = func() protoreflect.Value {
- v := t.Default()
- if t.Kind() == protoreflect.BytesKind {
- // Copy default bytes to avoid aliasing the original.
- v = protoreflect.ValueOf(append([]byte(nil), v.Bytes()...))
- }
- return v
- }
- t.valueOf = func(v interface{}) protoreflect.Value {
- return protoreflect.ValueOf(v)
- }
- t.interfaceOf = func(v protoreflect.Value) interface{} {
- return v.Interface()
- }
- }
- case protoreflect.Repeated:
- var conv value.Converter
- elemType := t.goType
- switch t.Kind() {
- case protoreflect.EnumKind:
- conv = value.Converter{
- PBValueOf: func(v reflect.Value) protoreflect.Value {
- if v.Type() != elemType {
- panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), elemType))
- }
- e := v.Interface().(protoreflect.Enum)
- return protoreflect.ValueOf(e.Number())
- },
- GoValueOf: func(v protoreflect.Value) reflect.Value {
- rv := reflect.ValueOf(t.NewEnum(v.Enum()))
- if rv.Type() != elemType {
- panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), elemType))
- }
- return rv
- },
- NewEnum: t.NewEnum,
- }
- case protoreflect.MessageKind, protoreflect.GroupKind:
- conv = value.Converter{
- PBValueOf: func(v reflect.Value) protoreflect.Value {
- if v.Type() != elemType {
- panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), elemType))
- }
- m := v.Interface().(protoreflect.ProtoMessage).ProtoReflect()
- return protoreflect.ValueOf(m)
- },
- GoValueOf: func(v protoreflect.Value) reflect.Value {
- rv := reflect.ValueOf(v.Message().Interface())
- if rv.Type() != elemType {
- panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), elemType))
- }
- return rv
- },
- NewMessage: t.NewMessage,
- }
- default:
- conv = value.NewConverter(elemType, t.Kind())
- }
- t.goType = reflect.PtrTo(reflect.SliceOf(elemType))
- t.new = func() protoreflect.Value {
- v := reflect.New(t.goType.Elem()).Interface()
- return protoreflect.ValueOf(value.ListOf(v, conv))
- }
- t.valueOf = func(v interface{}) protoreflect.Value {
- return protoreflect.ValueOf(value.ListOf(v, conv))
- }
- t.interfaceOf = func(v protoreflect.Value) interface{} {
- return v.List().(value.Unwrapper).ProtoUnwrap()
- }
- default:
- panic(fmt.Sprintf("invalid cardinality: %v", t.Cardinality()))
- }
- })
- }
- var goTypeForPBKind = map[protoreflect.Kind]reflect.Type{
- protoreflect.BoolKind: reflect.TypeOf(bool(false)),
- protoreflect.Int32Kind: reflect.TypeOf(int32(0)),
- protoreflect.Sint32Kind: reflect.TypeOf(int32(0)),
- protoreflect.Sfixed32Kind: reflect.TypeOf(int32(0)),
- protoreflect.Int64Kind: reflect.TypeOf(int64(0)),
- protoreflect.Sint64Kind: reflect.TypeOf(int64(0)),
- protoreflect.Sfixed64Kind: reflect.TypeOf(int64(0)),
- protoreflect.Uint32Kind: reflect.TypeOf(uint32(0)),
- protoreflect.Fixed32Kind: reflect.TypeOf(uint32(0)),
- protoreflect.Uint64Kind: reflect.TypeOf(uint64(0)),
- protoreflect.Fixed64Kind: reflect.TypeOf(uint64(0)),
- protoreflect.FloatKind: reflect.TypeOf(float32(0)),
- protoreflect.DoubleKind: reflect.TypeOf(float64(0)),
- protoreflect.StringKind: reflect.TypeOf(string("")),
- protoreflect.BytesKind: reflect.TypeOf([]byte(nil)),
- }
- var (
- _ protoreflect.EnumType = (*Enum)(nil)
- _ protoreflect.MessageType = (*Message)(nil)
- _ protoreflect.ExtensionType = (*Extension)(nil)
- )
|