| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // 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 impl
- import (
- "fmt"
- "reflect"
- "google.golang.org/protobuf/internal/pragma"
- pvalue "google.golang.org/protobuf/internal/value"
- pref "google.golang.org/protobuf/reflect/protoreflect"
- piface "google.golang.org/protobuf/runtime/protoiface"
- )
- // MessageState is a data structure that is nested as the first field in a
- // concrete message. It provides a way to implement the ProtoReflect method
- // in an allocation-free way without needing to have a shadow Go type generated
- // for every message type. This technique only works using unsafe.
- //
- //
- // Example generated code:
- //
- // type M struct {
- // state protoimpl.MessageState
- //
- // Field1 int32
- // Field2 string
- // Field3 *BarMessage
- // ...
- // }
- //
- // func (m *M) ProtoReflect() protoreflect.Message {
- // mi := &file_fizz_buzz_proto_msgInfos[5]
- // if protoimpl.UnsafeEnabled && m != nil {
- // ms := protoimpl.X.MessageStateOf(Pointer(m))
- // if ms.LoadMessageInfo() == nil {
- // ms.StoreMessageInfo(mi)
- // }
- // return ms
- // }
- // return mi.MessageOf(m)
- // }
- //
- // The MessageState type holds a *MessageInfo, which must be atomically set to
- // the message info associated with a given message instance.
- // By unsafely converting a *M into a *MessageState, the MessageState object
- // has access to all the information needed to implement protobuf reflection.
- // It has access to the message info as its first field, and a pointer to the
- // MessageState is identical to a pointer to the concrete message value.
- //
- //
- // Requirements:
- // • The type M must implement protoreflect.ProtoMessage.
- // • The address of m must not be nil.
- // • The address of m and the address of m.state must be equal,
- // even though they are different Go types.
- type MessageState struct {
- pragma.NoUnkeyedLiterals
- pragma.DoNotCompare
- pragma.DoNotCopy
- mi *MessageInfo
- }
- type messageState MessageState
- var (
- _ pref.Message = (*messageState)(nil)
- _ pvalue.Unwrapper = (*messageState)(nil)
- )
- // messageDataType is a tuple of a pointer to the message data and
- // a pointer to the message type. It is a generalized way of providing a
- // reflective view over a message instance. The disadvantage of this approach
- // is the need to allocate this tuple of 16B.
- type messageDataType struct {
- p pointer
- mi *MessageInfo
- }
- type (
- messageIfaceWrapper messageDataType
- messageReflectWrapper messageDataType
- )
- var (
- _ pref.Message = (*messageReflectWrapper)(nil)
- _ pvalue.Unwrapper = (*messageReflectWrapper)(nil)
- _ pref.ProtoMessage = (*messageIfaceWrapper)(nil)
- _ pvalue.Unwrapper = (*messageIfaceWrapper)(nil)
- )
- // MessageOf returns a reflective view over a message. The input must be a
- // pointer to a named Go struct. If the provided type has a ProtoReflect method,
- // it must be implemented by calling this method.
- func (mi *MessageInfo) MessageOf(m interface{}) pref.Message {
- // TODO: Switch the input to be an opaque Pointer.
- if reflect.TypeOf(m) != mi.GoType {
- panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoType))
- }
- p := pointerOfIface(m)
- if p.IsNil() {
- return mi.nilMessage.Init(mi)
- }
- return &messageReflectWrapper{p, mi}
- }
- func (m *messageReflectWrapper) pointer() pointer { return m.p }
- func (m *messageIfaceWrapper) ProtoReflect() pref.Message {
- return (*messageReflectWrapper)(m)
- }
- func (m *messageIfaceWrapper) XXX_Methods() *piface.Methods {
- // TODO: Consider not recreating this on every call.
- m.mi.init()
- return &piface.Methods{
- Flags: piface.MethodFlagDeterministicMarshal,
- MarshalAppend: m.marshalAppend,
- Unmarshal: m.unmarshal,
- Size: m.size,
- IsInitialized: m.isInitialized,
- }
- }
- func (m *messageIfaceWrapper) ProtoUnwrap() interface{} {
- return m.p.AsIfaceOf(m.mi.GoType.Elem())
- }
- func (m *messageIfaceWrapper) marshalAppend(b []byte, _ pref.ProtoMessage, opts piface.MarshalOptions) ([]byte, error) {
- return m.mi.marshalAppendPointer(b, m.p, newMarshalOptions(opts))
- }
- func (m *messageIfaceWrapper) unmarshal(b []byte, _ pref.ProtoMessage, opts piface.UnmarshalOptions) error {
- _, err := m.mi.unmarshalPointer(b, m.p, 0, newUnmarshalOptions(opts))
- return err
- }
- func (m *messageIfaceWrapper) size(msg pref.ProtoMessage) (size int) {
- return m.mi.sizePointer(m.p, 0)
- }
- func (m *messageIfaceWrapper) isInitialized(_ pref.ProtoMessage) error {
- return m.mi.isInitializedPointer(m.p)
- }
- type extensionMap map[int32]ExtensionField
- func (m *extensionMap) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
- if m != nil {
- for _, x := range *m {
- xt := x.GetType()
- if !f(xt, xt.ValueOf(x.GetValue())) {
- return
- }
- }
- }
- }
- func (m *extensionMap) Has(xt pref.ExtensionType) (ok bool) {
- if m != nil {
- _, ok = (*m)[int32(xt.Number())]
- }
- return ok
- }
- func (m *extensionMap) Clear(xt pref.ExtensionType) {
- delete(*m, int32(xt.Number()))
- }
- func (m *extensionMap) Get(xt pref.ExtensionType) pref.Value {
- if m != nil {
- if x, ok := (*m)[int32(xt.Number())]; ok {
- return xt.ValueOf(x.GetValue())
- }
- }
- if !isComposite(xt) {
- return defaultValueOf(xt)
- }
- return frozenValueOf(xt.New())
- }
- func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
- if *m == nil {
- *m = make(map[int32]ExtensionField)
- }
- var x ExtensionField
- x.SetType(xt)
- x.SetEagerValue(xt.InterfaceOf(v))
- (*m)[int32(xt.Number())] = x
- }
- func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
- if !isComposite(xt) {
- panic("invalid Mutable on field with non-composite type")
- }
- if x, ok := (*m)[int32(xt.Number())]; ok {
- return xt.ValueOf(x.GetValue())
- }
- v := xt.New()
- m.Set(xt, v)
- return v
- }
- func isComposite(fd pref.FieldDescriptor) bool {
- return fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind || fd.IsList() || fd.IsMap()
- }
- // checkField verifies that the provided field descriptor is valid.
- // Exactly one of the returned values is populated.
- func (mi *MessageInfo) checkField(fd pref.FieldDescriptor) (*fieldInfo, pref.ExtensionType) {
- if fi := mi.fields[fd.Number()]; fi != nil {
- if fi.fieldDesc != fd {
- panic("mismatching field descriptor")
- }
- return fi, nil
- }
- if fd.IsExtension() {
- if fd.ContainingMessage().FullName() != mi.PBType.FullName() {
- // TODO: Should this be exact containing message descriptor match?
- panic("mismatching containing message")
- }
- if !mi.PBType.ExtensionRanges().Has(fd.Number()) {
- panic("invalid extension field")
- }
- return nil, fd.(pref.ExtensionType)
- }
- panic("invalid field descriptor")
- }
|