codec_message_opaque.go

  1// Copyright 2024 The Go Authors. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5package impl
  6
  7import (
  8	"fmt"
  9	"reflect"
 10	"sort"
 11
 12	"google.golang.org/protobuf/encoding/protowire"
 13	"google.golang.org/protobuf/internal/encoding/messageset"
 14	"google.golang.org/protobuf/internal/order"
 15	"google.golang.org/protobuf/reflect/protoreflect"
 16	piface "google.golang.org/protobuf/runtime/protoiface"
 17)
 18
 19func (mi *MessageInfo) makeOpaqueCoderMethods(t reflect.Type, si opaqueStructInfo) {
 20	mi.sizecacheOffset = si.sizecacheOffset
 21	mi.unknownOffset = si.unknownOffset
 22	mi.unknownPtrKind = si.unknownType.Kind() == reflect.Ptr
 23	mi.extensionOffset = si.extensionOffset
 24	mi.lazyOffset = si.lazyOffset
 25	mi.presenceOffset = si.presenceOffset
 26
 27	mi.coderFields = make(map[protowire.Number]*coderFieldInfo)
 28	fields := mi.Desc.Fields()
 29	for i := 0; i < fields.Len(); i++ {
 30		fd := fields.Get(i)
 31
 32		fs := si.fieldsByNumber[fd.Number()]
 33		if fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic() {
 34			fs = si.oneofsByName[fd.ContainingOneof().Name()]
 35		}
 36		ft := fs.Type
 37		var wiretag uint64
 38		if !fd.IsPacked() {
 39			wiretag = protowire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
 40		} else {
 41			wiretag = protowire.EncodeTag(fd.Number(), protowire.BytesType)
 42		}
 43		var fieldOffset offset
 44		var funcs pointerCoderFuncs
 45		var childMessage *MessageInfo
 46		switch {
 47		case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
 48			fieldOffset = offsetOf(fs)
 49		case fd.Message() != nil && !fd.IsMap():
 50			fieldOffset = offsetOf(fs)
 51			if fd.IsList() {
 52				childMessage, funcs = makeOpaqueRepeatedMessageFieldCoder(fd, ft)
 53			} else {
 54				childMessage, funcs = makeOpaqueMessageFieldCoder(fd, ft)
 55			}
 56		default:
 57			fieldOffset = offsetOf(fs)
 58			childMessage, funcs = fieldCoder(fd, ft)
 59		}
 60		cf := &coderFieldInfo{
 61			num:        fd.Number(),
 62			offset:     fieldOffset,
 63			wiretag:    wiretag,
 64			ft:         ft,
 65			tagsize:    protowire.SizeVarint(wiretag),
 66			funcs:      funcs,
 67			mi:         childMessage,
 68			validation: newFieldValidationInfo(mi, si.structInfo, fd, ft),
 69			isPointer: (fd.Cardinality() == protoreflect.Repeated ||
 70				fd.Kind() == protoreflect.MessageKind ||
 71				fd.Kind() == protoreflect.GroupKind),
 72			isRequired:    fd.Cardinality() == protoreflect.Required,
 73			presenceIndex: noPresence,
 74		}
 75
 76		// TODO: Use presence for all fields.
 77		//
 78		// In some cases, such as maps, presence means only "might be set" rather
 79		// than "is definitely set", but every field should have a presence bit to
 80		// permit us to skip over definitely-unset fields at marshal time.
 81
 82		var hasPresence bool
 83		hasPresence, cf.isLazy = usePresenceForField(si, fd)
 84
 85		if hasPresence {
 86			cf.presenceIndex, mi.presenceSize = presenceIndex(mi.Desc, fd)
 87		}
 88
 89		mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
 90		mi.coderFields[cf.num] = cf
 91	}
 92	for i, oneofs := 0, mi.Desc.Oneofs(); i < oneofs.Len(); i++ {
 93		if od := oneofs.Get(i); !od.IsSynthetic() {
 94			mi.initOneofFieldCoders(od, si.structInfo)
 95		}
 96	}
 97	if messageset.IsMessageSet(mi.Desc) {
 98		if !mi.extensionOffset.IsValid() {
 99			panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.Desc.FullName()))
100		}
101		if !mi.unknownOffset.IsValid() {
102			panic(fmt.Sprintf("%v: MessageSet with no unknown field", mi.Desc.FullName()))
103		}
104		mi.isMessageSet = true
105	}
106	sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
107		return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
108	})
109
110	var maxDense protoreflect.FieldNumber
111	for _, cf := range mi.orderedCoderFields {
112		if cf.num >= 16 && cf.num >= 2*maxDense {
113			break
114		}
115		maxDense = cf.num
116	}
117	mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1)
118	for _, cf := range mi.orderedCoderFields {
119		if int(cf.num) > len(mi.denseCoderFields) {
120			break
121		}
122		mi.denseCoderFields[cf.num] = cf
123	}
124
125	// To preserve compatibility with historic wire output, marshal oneofs last.
126	if mi.Desc.Oneofs().Len() > 0 {
127		sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
128			fi := fields.ByNumber(mi.orderedCoderFields[i].num)
129			fj := fields.ByNumber(mi.orderedCoderFields[j].num)
130			return order.LegacyFieldOrder(fi, fj)
131		})
132	}
133
134	mi.needsInitCheck = needsInitCheck(mi.Desc)
135	if mi.methods.Marshal == nil && mi.methods.Size == nil {
136		mi.methods.Flags |= piface.SupportMarshalDeterministic
137		mi.methods.Marshal = mi.marshal
138		mi.methods.Size = mi.size
139	}
140	if mi.methods.Unmarshal == nil {
141		mi.methods.Flags |= piface.SupportUnmarshalDiscardUnknown
142		mi.methods.Unmarshal = mi.unmarshal
143	}
144	if mi.methods.CheckInitialized == nil {
145		mi.methods.CheckInitialized = mi.checkInitialized
146	}
147	if mi.methods.Merge == nil {
148		mi.methods.Merge = mi.merge
149	}
150	if mi.methods.Equal == nil {
151		mi.methods.Equal = equal
152	}
153}