1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage impl 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "fmt" 9*1c12ee1eSDan Willemsen "reflect" 10*1c12ee1eSDan Willemsen "sort" 11*1c12ee1eSDan Willemsen 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/encoding/messageset" 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/order" 15*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 16*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoiface" 17*1c12ee1eSDan Willemsen) 18*1c12ee1eSDan Willemsen 19*1c12ee1eSDan Willemsen// coderMessageInfo contains per-message information used by the fast-path functions. 20*1c12ee1eSDan Willemsen// This is a different type from MessageInfo to keep MessageInfo as general-purpose as 21*1c12ee1eSDan Willemsen// possible. 22*1c12ee1eSDan Willemsentype coderMessageInfo struct { 23*1c12ee1eSDan Willemsen methods protoiface.Methods 24*1c12ee1eSDan Willemsen 25*1c12ee1eSDan Willemsen orderedCoderFields []*coderFieldInfo 26*1c12ee1eSDan Willemsen denseCoderFields []*coderFieldInfo 27*1c12ee1eSDan Willemsen coderFields map[protowire.Number]*coderFieldInfo 28*1c12ee1eSDan Willemsen sizecacheOffset offset 29*1c12ee1eSDan Willemsen unknownOffset offset 30*1c12ee1eSDan Willemsen unknownPtrKind bool 31*1c12ee1eSDan Willemsen extensionOffset offset 32*1c12ee1eSDan Willemsen needsInitCheck bool 33*1c12ee1eSDan Willemsen isMessageSet bool 34*1c12ee1eSDan Willemsen numRequiredFields uint8 35*1c12ee1eSDan Willemsen} 36*1c12ee1eSDan Willemsen 37*1c12ee1eSDan Willemsentype coderFieldInfo struct { 38*1c12ee1eSDan Willemsen funcs pointerCoderFuncs // fast-path per-field functions 39*1c12ee1eSDan Willemsen mi *MessageInfo // field's message 40*1c12ee1eSDan Willemsen ft reflect.Type 41*1c12ee1eSDan Willemsen validation validationInfo // information used by message validation 42*1c12ee1eSDan Willemsen num protoreflect.FieldNumber // field number 43*1c12ee1eSDan Willemsen offset offset // struct field offset 44*1c12ee1eSDan Willemsen wiretag uint64 // field tag (number + wire type) 45*1c12ee1eSDan Willemsen tagsize int // size of the varint-encoded tag 46*1c12ee1eSDan Willemsen isPointer bool // true if IsNil may be called on the struct field 47*1c12ee1eSDan Willemsen isRequired bool // true if field is required 48*1c12ee1eSDan Willemsen} 49*1c12ee1eSDan Willemsen 50*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) { 51*1c12ee1eSDan Willemsen mi.sizecacheOffset = invalidOffset 52*1c12ee1eSDan Willemsen mi.unknownOffset = invalidOffset 53*1c12ee1eSDan Willemsen mi.extensionOffset = invalidOffset 54*1c12ee1eSDan Willemsen 55*1c12ee1eSDan Willemsen if si.sizecacheOffset.IsValid() && si.sizecacheType == sizecacheType { 56*1c12ee1eSDan Willemsen mi.sizecacheOffset = si.sizecacheOffset 57*1c12ee1eSDan Willemsen } 58*1c12ee1eSDan Willemsen if si.unknownOffset.IsValid() && (si.unknownType == unknownFieldsAType || si.unknownType == unknownFieldsBType) { 59*1c12ee1eSDan Willemsen mi.unknownOffset = si.unknownOffset 60*1c12ee1eSDan Willemsen mi.unknownPtrKind = si.unknownType.Kind() == reflect.Ptr 61*1c12ee1eSDan Willemsen } 62*1c12ee1eSDan Willemsen if si.extensionOffset.IsValid() && si.extensionType == extensionFieldsType { 63*1c12ee1eSDan Willemsen mi.extensionOffset = si.extensionOffset 64*1c12ee1eSDan Willemsen } 65*1c12ee1eSDan Willemsen 66*1c12ee1eSDan Willemsen mi.coderFields = make(map[protowire.Number]*coderFieldInfo) 67*1c12ee1eSDan Willemsen fields := mi.Desc.Fields() 68*1c12ee1eSDan Willemsen preallocFields := make([]coderFieldInfo, fields.Len()) 69*1c12ee1eSDan Willemsen for i := 0; i < fields.Len(); i++ { 70*1c12ee1eSDan Willemsen fd := fields.Get(i) 71*1c12ee1eSDan Willemsen 72*1c12ee1eSDan Willemsen fs := si.fieldsByNumber[fd.Number()] 73*1c12ee1eSDan Willemsen isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic() 74*1c12ee1eSDan Willemsen if isOneof { 75*1c12ee1eSDan Willemsen fs = si.oneofsByName[fd.ContainingOneof().Name()] 76*1c12ee1eSDan Willemsen } 77*1c12ee1eSDan Willemsen ft := fs.Type 78*1c12ee1eSDan Willemsen var wiretag uint64 79*1c12ee1eSDan Willemsen if !fd.IsPacked() { 80*1c12ee1eSDan Willemsen wiretag = protowire.EncodeTag(fd.Number(), wireTypes[fd.Kind()]) 81*1c12ee1eSDan Willemsen } else { 82*1c12ee1eSDan Willemsen wiretag = protowire.EncodeTag(fd.Number(), protowire.BytesType) 83*1c12ee1eSDan Willemsen } 84*1c12ee1eSDan Willemsen var fieldOffset offset 85*1c12ee1eSDan Willemsen var funcs pointerCoderFuncs 86*1c12ee1eSDan Willemsen var childMessage *MessageInfo 87*1c12ee1eSDan Willemsen switch { 88*1c12ee1eSDan Willemsen case ft == nil: 89*1c12ee1eSDan Willemsen // This never occurs for generated message types. 90*1c12ee1eSDan Willemsen // It implies that a hand-crafted type has missing Go fields 91*1c12ee1eSDan Willemsen // for specific protobuf message fields. 92*1c12ee1eSDan Willemsen funcs = pointerCoderFuncs{ 93*1c12ee1eSDan Willemsen size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int { 94*1c12ee1eSDan Willemsen return 0 95*1c12ee1eSDan Willemsen }, 96*1c12ee1eSDan Willemsen marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) { 97*1c12ee1eSDan Willemsen return nil, nil 98*1c12ee1eSDan Willemsen }, 99*1c12ee1eSDan Willemsen unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) { 100*1c12ee1eSDan Willemsen panic("missing Go struct field for " + string(fd.FullName())) 101*1c12ee1eSDan Willemsen }, 102*1c12ee1eSDan Willemsen isInit: func(p pointer, f *coderFieldInfo) error { 103*1c12ee1eSDan Willemsen panic("missing Go struct field for " + string(fd.FullName())) 104*1c12ee1eSDan Willemsen }, 105*1c12ee1eSDan Willemsen merge: func(dst, src pointer, f *coderFieldInfo, opts mergeOptions) { 106*1c12ee1eSDan Willemsen panic("missing Go struct field for " + string(fd.FullName())) 107*1c12ee1eSDan Willemsen }, 108*1c12ee1eSDan Willemsen } 109*1c12ee1eSDan Willemsen case isOneof: 110*1c12ee1eSDan Willemsen fieldOffset = offsetOf(fs, mi.Exporter) 111*1c12ee1eSDan Willemsen case fd.IsWeak(): 112*1c12ee1eSDan Willemsen fieldOffset = si.weakOffset 113*1c12ee1eSDan Willemsen funcs = makeWeakMessageFieldCoder(fd) 114*1c12ee1eSDan Willemsen default: 115*1c12ee1eSDan Willemsen fieldOffset = offsetOf(fs, mi.Exporter) 116*1c12ee1eSDan Willemsen childMessage, funcs = fieldCoder(fd, ft) 117*1c12ee1eSDan Willemsen } 118*1c12ee1eSDan Willemsen cf := &preallocFields[i] 119*1c12ee1eSDan Willemsen *cf = coderFieldInfo{ 120*1c12ee1eSDan Willemsen num: fd.Number(), 121*1c12ee1eSDan Willemsen offset: fieldOffset, 122*1c12ee1eSDan Willemsen wiretag: wiretag, 123*1c12ee1eSDan Willemsen ft: ft, 124*1c12ee1eSDan Willemsen tagsize: protowire.SizeVarint(wiretag), 125*1c12ee1eSDan Willemsen funcs: funcs, 126*1c12ee1eSDan Willemsen mi: childMessage, 127*1c12ee1eSDan Willemsen validation: newFieldValidationInfo(mi, si, fd, ft), 128*1c12ee1eSDan Willemsen isPointer: fd.Cardinality() == protoreflect.Repeated || fd.HasPresence(), 129*1c12ee1eSDan Willemsen isRequired: fd.Cardinality() == protoreflect.Required, 130*1c12ee1eSDan Willemsen } 131*1c12ee1eSDan Willemsen mi.orderedCoderFields = append(mi.orderedCoderFields, cf) 132*1c12ee1eSDan Willemsen mi.coderFields[cf.num] = cf 133*1c12ee1eSDan Willemsen } 134*1c12ee1eSDan Willemsen for i, oneofs := 0, mi.Desc.Oneofs(); i < oneofs.Len(); i++ { 135*1c12ee1eSDan Willemsen if od := oneofs.Get(i); !od.IsSynthetic() { 136*1c12ee1eSDan Willemsen mi.initOneofFieldCoders(od, si) 137*1c12ee1eSDan Willemsen } 138*1c12ee1eSDan Willemsen } 139*1c12ee1eSDan Willemsen if messageset.IsMessageSet(mi.Desc) { 140*1c12ee1eSDan Willemsen if !mi.extensionOffset.IsValid() { 141*1c12ee1eSDan Willemsen panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.Desc.FullName())) 142*1c12ee1eSDan Willemsen } 143*1c12ee1eSDan Willemsen if !mi.unknownOffset.IsValid() { 144*1c12ee1eSDan Willemsen panic(fmt.Sprintf("%v: MessageSet with no unknown field", mi.Desc.FullName())) 145*1c12ee1eSDan Willemsen } 146*1c12ee1eSDan Willemsen mi.isMessageSet = true 147*1c12ee1eSDan Willemsen } 148*1c12ee1eSDan Willemsen sort.Slice(mi.orderedCoderFields, func(i, j int) bool { 149*1c12ee1eSDan Willemsen return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num 150*1c12ee1eSDan Willemsen }) 151*1c12ee1eSDan Willemsen 152*1c12ee1eSDan Willemsen var maxDense protoreflect.FieldNumber 153*1c12ee1eSDan Willemsen for _, cf := range mi.orderedCoderFields { 154*1c12ee1eSDan Willemsen if cf.num >= 16 && cf.num >= 2*maxDense { 155*1c12ee1eSDan Willemsen break 156*1c12ee1eSDan Willemsen } 157*1c12ee1eSDan Willemsen maxDense = cf.num 158*1c12ee1eSDan Willemsen } 159*1c12ee1eSDan Willemsen mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1) 160*1c12ee1eSDan Willemsen for _, cf := range mi.orderedCoderFields { 161*1c12ee1eSDan Willemsen if int(cf.num) >= len(mi.denseCoderFields) { 162*1c12ee1eSDan Willemsen break 163*1c12ee1eSDan Willemsen } 164*1c12ee1eSDan Willemsen mi.denseCoderFields[cf.num] = cf 165*1c12ee1eSDan Willemsen } 166*1c12ee1eSDan Willemsen 167*1c12ee1eSDan Willemsen // To preserve compatibility with historic wire output, marshal oneofs last. 168*1c12ee1eSDan Willemsen if mi.Desc.Oneofs().Len() > 0 { 169*1c12ee1eSDan Willemsen sort.Slice(mi.orderedCoderFields, func(i, j int) bool { 170*1c12ee1eSDan Willemsen fi := fields.ByNumber(mi.orderedCoderFields[i].num) 171*1c12ee1eSDan Willemsen fj := fields.ByNumber(mi.orderedCoderFields[j].num) 172*1c12ee1eSDan Willemsen return order.LegacyFieldOrder(fi, fj) 173*1c12ee1eSDan Willemsen }) 174*1c12ee1eSDan Willemsen } 175*1c12ee1eSDan Willemsen 176*1c12ee1eSDan Willemsen mi.needsInitCheck = needsInitCheck(mi.Desc) 177*1c12ee1eSDan Willemsen if mi.methods.Marshal == nil && mi.methods.Size == nil { 178*1c12ee1eSDan Willemsen mi.methods.Flags |= protoiface.SupportMarshalDeterministic 179*1c12ee1eSDan Willemsen mi.methods.Marshal = mi.marshal 180*1c12ee1eSDan Willemsen mi.methods.Size = mi.size 181*1c12ee1eSDan Willemsen } 182*1c12ee1eSDan Willemsen if mi.methods.Unmarshal == nil { 183*1c12ee1eSDan Willemsen mi.methods.Flags |= protoiface.SupportUnmarshalDiscardUnknown 184*1c12ee1eSDan Willemsen mi.methods.Unmarshal = mi.unmarshal 185*1c12ee1eSDan Willemsen } 186*1c12ee1eSDan Willemsen if mi.methods.CheckInitialized == nil { 187*1c12ee1eSDan Willemsen mi.methods.CheckInitialized = mi.checkInitialized 188*1c12ee1eSDan Willemsen } 189*1c12ee1eSDan Willemsen if mi.methods.Merge == nil { 190*1c12ee1eSDan Willemsen mi.methods.Merge = mi.merge 191*1c12ee1eSDan Willemsen } 192*1c12ee1eSDan Willemsen} 193*1c12ee1eSDan Willemsen 194*1c12ee1eSDan Willemsen// getUnknownBytes returns a *[]byte for the unknown fields. 195*1c12ee1eSDan Willemsen// It is the caller's responsibility to check whether the pointer is nil. 196*1c12ee1eSDan Willemsen// This function is specially designed to be inlineable. 197*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) getUnknownBytes(p pointer) *[]byte { 198*1c12ee1eSDan Willemsen if mi.unknownPtrKind { 199*1c12ee1eSDan Willemsen return *p.Apply(mi.unknownOffset).BytesPtr() 200*1c12ee1eSDan Willemsen } else { 201*1c12ee1eSDan Willemsen return p.Apply(mi.unknownOffset).Bytes() 202*1c12ee1eSDan Willemsen } 203*1c12ee1eSDan Willemsen} 204*1c12ee1eSDan Willemsen 205*1c12ee1eSDan Willemsen// mutableUnknownBytes returns a *[]byte for the unknown fields. 206*1c12ee1eSDan Willemsen// The returned pointer is guaranteed to not be nil. 207*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) mutableUnknownBytes(p pointer) *[]byte { 208*1c12ee1eSDan Willemsen if mi.unknownPtrKind { 209*1c12ee1eSDan Willemsen bp := p.Apply(mi.unknownOffset).BytesPtr() 210*1c12ee1eSDan Willemsen if *bp == nil { 211*1c12ee1eSDan Willemsen *bp = new([]byte) 212*1c12ee1eSDan Willemsen } 213*1c12ee1eSDan Willemsen return *bp 214*1c12ee1eSDan Willemsen } else { 215*1c12ee1eSDan Willemsen return p.Apply(mi.unknownOffset).Bytes() 216*1c12ee1eSDan Willemsen } 217*1c12ee1eSDan Willemsen} 218