| // 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 ( |
| "reflect" |
| "sort" |
| |
| "google.golang.org/protobuf/internal/encoding/wire" |
| pref "google.golang.org/protobuf/reflect/protoreflect" |
| piface "google.golang.org/protobuf/runtime/protoiface" |
| ) |
| |
| // coderMessageInfo contains per-message information used by the fast-path functions. |
| // This is a different type from MessageInfo to keep MessageInfo as general-purpose as |
| // possible. |
| type coderMessageInfo struct { |
| orderedCoderFields []*coderFieldInfo |
| denseCoderFields []*coderFieldInfo |
| coderFields map[wire.Number]*coderFieldInfo |
| sizecacheOffset offset |
| unknownOffset offset |
| extensionOffset offset |
| needsInitCheck bool |
| } |
| |
| type coderFieldInfo struct { |
| funcs pointerCoderFuncs // fast-path per-field functions |
| num pref.FieldNumber // field number |
| offset offset // struct field offset |
| wiretag uint64 // field tag (number + wire type) |
| tagsize int // size of the varint-encoded tag |
| isPointer bool // true if IsNil may be called on the struct field |
| isRequired bool // true if field is required |
| } |
| |
| func (mi *MessageInfo) makeMethods(t reflect.Type, si structInfo) { |
| mi.sizecacheOffset = si.sizecacheOffset |
| mi.unknownOffset = si.unknownOffset |
| mi.extensionOffset = si.extensionOffset |
| |
| mi.coderFields = make(map[wire.Number]*coderFieldInfo) |
| for i := 0; i < mi.PBType.Descriptor().Fields().Len(); i++ { |
| fd := mi.PBType.Descriptor().Fields().Get(i) |
| |
| fs := si.fieldsByNumber[fd.Number()] |
| if fd.ContainingOneof() != nil { |
| fs = si.oneofsByName[fd.ContainingOneof().Name()] |
| } |
| ft := fs.Type |
| var wiretag uint64 |
| if !fd.IsPacked() { |
| wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()]) |
| } else { |
| wiretag = wire.EncodeTag(fd.Number(), wire.BytesType) |
| } |
| var funcs pointerCoderFuncs |
| if fd.ContainingOneof() != nil { |
| funcs = makeOneofFieldCoder(si, fd) |
| } else { |
| funcs = fieldCoder(fd, ft) |
| } |
| cf := &coderFieldInfo{ |
| num: fd.Number(), |
| offset: offsetOf(fs, mi.Exporter), |
| wiretag: wiretag, |
| tagsize: wire.SizeVarint(wiretag), |
| funcs: funcs, |
| isPointer: (fd.Cardinality() == pref.Repeated || |
| fd.Kind() == pref.MessageKind || |
| fd.Kind() == pref.GroupKind || |
| fd.Syntax() != pref.Proto3), |
| isRequired: fd.Cardinality() == pref.Required, |
| } |
| mi.orderedCoderFields = append(mi.orderedCoderFields, cf) |
| mi.coderFields[cf.num] = cf |
| } |
| sort.Slice(mi.orderedCoderFields, func(i, j int) bool { |
| return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num |
| }) |
| |
| var maxDense pref.FieldNumber |
| for _, cf := range mi.orderedCoderFields { |
| if cf.num >= 16 && cf.num >= 2*maxDense { |
| break |
| } |
| maxDense = cf.num |
| } |
| mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1) |
| for _, cf := range mi.orderedCoderFields { |
| if int(cf.num) > len(mi.denseCoderFields) { |
| break |
| } |
| mi.denseCoderFields[cf.num] = cf |
| } |
| |
| mi.needsInitCheck = needsInitCheck(mi.PBType) |
| mi.methods = piface.Methods{ |
| Flags: piface.MethodFlagDeterministicMarshal, |
| MarshalAppend: mi.marshalAppend, |
| Unmarshal: mi.unmarshal, |
| Size: mi.size, |
| IsInitialized: mi.isInitialized, |
| } |
| } |