package impl
import (
"fmt"
"reflect"
"sort"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/order"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoiface"
)
type coderMessageInfo struct {
methods protoiface .Methods
orderedCoderFields []*coderFieldInfo
denseCoderFields []*coderFieldInfo
coderFields map [protowire .Number ]*coderFieldInfo
sizecacheOffset offset
unknownOffset offset
unknownPtrKind bool
extensionOffset offset
needsInitCheck bool
isMessageSet bool
numRequiredFields uint8
lazyOffset offset
presenceOffset offset
presenceSize presenceSize
}
type coderFieldInfo struct {
funcs pointerCoderFuncs
mi *MessageInfo
ft reflect .Type
validation validationInfo
num protoreflect .FieldNumber
offset offset
wiretag uint64
tagsize int
isPointer bool
isRequired bool
isLazy bool
presenceIndex uint32
}
const noPresence = 0xffffffff
func (mi *MessageInfo ) makeCoderMethods (t reflect .Type , si structInfo ) {
mi .sizecacheOffset = invalidOffset
mi .unknownOffset = invalidOffset
mi .extensionOffset = invalidOffset
mi .lazyOffset = invalidOffset
mi .presenceOffset = si .presenceOffset
if si .sizecacheOffset .IsValid () && si .sizecacheType == sizecacheType {
mi .sizecacheOffset = si .sizecacheOffset
}
if si .unknownOffset .IsValid () && (si .unknownType == unknownFieldsAType || si .unknownType == unknownFieldsBType ) {
mi .unknownOffset = si .unknownOffset
mi .unknownPtrKind = si .unknownType .Kind () == reflect .Ptr
}
if si .extensionOffset .IsValid () && si .extensionType == extensionFieldsType {
mi .extensionOffset = si .extensionOffset
}
mi .coderFields = make (map [protowire .Number ]*coderFieldInfo )
fields := mi .Desc .Fields ()
preallocFields := make ([]coderFieldInfo , fields .Len ())
for i := 0 ; i < fields .Len (); i ++ {
fd := fields .Get (i )
fs := si .fieldsByNumber [fd .Number ()]
isOneof := fd .ContainingOneof () != nil && !fd .ContainingOneof ().IsSynthetic ()
if isOneof {
fs = si .oneofsByName [fd .ContainingOneof ().Name ()]
}
ft := fs .Type
var wiretag uint64
if !fd .IsPacked () {
wiretag = protowire .EncodeTag (fd .Number (), wireTypes [fd .Kind ()])
} else {
wiretag = protowire .EncodeTag (fd .Number (), protowire .BytesType )
}
var fieldOffset offset
var funcs pointerCoderFuncs
var childMessage *MessageInfo
switch {
case ft == nil :
funcs = pointerCoderFuncs {
size : func (p pointer , f *coderFieldInfo , opts marshalOptions ) int {
return 0
},
marshal : func (b []byte , p pointer , f *coderFieldInfo , opts marshalOptions ) ([]byte , error ) {
return nil , nil
},
unmarshal : func (b []byte , p pointer , wtyp protowire .Type , f *coderFieldInfo , opts unmarshalOptions ) (unmarshalOutput , error ) {
panic ("missing Go struct field for " + string (fd .FullName ()))
},
isInit : func (p pointer , f *coderFieldInfo ) error {
panic ("missing Go struct field for " + string (fd .FullName ()))
},
merge : func (dst , src pointer , f *coderFieldInfo , opts mergeOptions ) {
panic ("missing Go struct field for " + string (fd .FullName ()))
},
}
case isOneof :
fieldOffset = offsetOf (fs )
default :
fieldOffset = offsetOf (fs )
childMessage , funcs = fieldCoder (fd , ft )
}
cf := &preallocFields [i ]
*cf = coderFieldInfo {
num : fd .Number (),
offset : fieldOffset ,
wiretag : wiretag ,
ft : ft ,
tagsize : protowire .SizeVarint (wiretag ),
funcs : funcs ,
mi : childMessage ,
validation : newFieldValidationInfo (mi , si , fd , ft ),
isPointer : fd .Cardinality () == protoreflect .Repeated || fd .HasPresence (),
isRequired : fd .Cardinality () == protoreflect .Required ,
presenceIndex : noPresence ,
}
mi .orderedCoderFields = append (mi .orderedCoderFields , cf )
mi .coderFields [cf .num ] = cf
}
for i , oneofs := 0 , mi .Desc .Oneofs (); i < oneofs .Len (); i ++ {
if od := oneofs .Get (i ); !od .IsSynthetic () {
mi .initOneofFieldCoders (od , si )
}
}
if messageset .IsMessageSet (mi .Desc ) {
if !mi .extensionOffset .IsValid () {
panic (fmt .Sprintf ("%v: MessageSet with no extensions field" , mi .Desc .FullName ()))
}
if !mi .unknownOffset .IsValid () {
panic (fmt .Sprintf ("%v: MessageSet with no unknown field" , mi .Desc .FullName ()))
}
mi .isMessageSet = true
}
sort .Slice (mi .orderedCoderFields , func (i , j int ) bool {
return mi .orderedCoderFields [i ].num < mi .orderedCoderFields [j ].num
})
var maxDense protoreflect .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
}
if mi .Desc .Oneofs ().Len () > 0 {
sort .Slice (mi .orderedCoderFields , func (i , j int ) bool {
fi := fields .ByNumber (mi .orderedCoderFields [i ].num )
fj := fields .ByNumber (mi .orderedCoderFields [j ].num )
return order .LegacyFieldOrder (fi , fj )
})
}
mi .needsInitCheck = needsInitCheck (mi .Desc )
if mi .methods .Marshal == nil && mi .methods .Size == nil {
mi .methods .Flags |= protoiface .SupportMarshalDeterministic
mi .methods .Marshal = mi .marshal
mi .methods .Size = mi .size
}
if mi .methods .Unmarshal == nil {
mi .methods .Flags |= protoiface .SupportUnmarshalDiscardUnknown
mi .methods .Unmarshal = mi .unmarshal
}
if mi .methods .CheckInitialized == nil {
mi .methods .CheckInitialized = mi .checkInitialized
}
if mi .methods .Merge == nil {
mi .methods .Merge = mi .merge
}
if mi .methods .Equal == nil {
mi .methods .Equal = equal
}
}
func (mi *MessageInfo ) getUnknownBytes (p pointer ) *[]byte {
if mi .unknownPtrKind {
return *p .Apply (mi .unknownOffset ).BytesPtr ()
} else {
return p .Apply (mi .unknownOffset ).Bytes ()
}
}
func (mi *MessageInfo ) mutableUnknownBytes (p pointer ) *[]byte {
if mi .unknownPtrKind {
bp := p .Apply (mi .unknownOffset ).BytesPtr ()
if *bp == nil {
*bp = new ([]byte )
}
return *bp
} else {
return p .Apply (mi .unknownOffset ).Bytes ()
}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .