blob: fc2235c68405542ae3a46c539d94f001845602e4 [file] [log] [blame]
// Copyright 2018 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 fileinit
import (
"bytes"
"fmt"
"reflect"
defval "github.com/golang/protobuf/v2/internal/encoding/defval"
wire "github.com/golang/protobuf/v2/internal/encoding/wire"
pimpl "github.com/golang/protobuf/v2/internal/impl"
pvalue "github.com/golang/protobuf/v2/internal/value"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
ptype "github.com/golang/protobuf/v2/reflect/prototype"
)
func (file *fileDesc) lazyInit() *fileLazy {
file.once.Do(func() {
file.unmarshalFull(file.RawDescriptor)
file.resolveImports()
file.resolveEnums()
file.resolveMessages()
file.resolveExtensions()
file.resolveServices()
file.finishInit()
})
return file.lazy
}
func (file *fileDesc) resolveImports() {
// TODO: Resolve file dependencies.
}
func (file *fileDesc) resolveEnums() {
enumDecls := file.GoTypes[:len(file.allEnums)]
for i := range file.allEnums {
ed := &file.allEnums[i]
// Associate the EnumType with a concrete Go type.
enumCache := map[pref.EnumNumber]pref.Enum{}
ed.lazy.typ = reflect.TypeOf(enumDecls[i])
ed.lazy.new = func(n pref.EnumNumber) pref.Enum {
if v, ok := enumCache[n]; ok {
return v
}
v := reflect.New(ed.lazy.typ).Elem()
v.SetInt(int64(n))
return v.Interface().(pref.Enum)
}
for i := range ed.lazy.values.list {
n := ed.lazy.values.list[i].number
enumCache[n] = ed.lazy.new(n)
}
}
}
func (file *fileDesc) resolveMessages() {
messageDecls := file.GoTypes[len(file.allEnums):]
for i := range file.allMessages {
md := &file.allMessages[i]
// Associate the MessageType with a concrete Go type.
//
// Note that descriptors for map entries, which have no associated
// Go type, also implement the protoreflect.MessageType interface,
// but have a GoType accessor that reports nil. Calling New results
// in a panic, which is sensible behavior.
md.lazy.typ = reflect.TypeOf(messageDecls[i])
md.lazy.new = func() pref.Message {
t := md.lazy.typ.Elem()
return reflect.New(t).Interface().(pref.ProtoMessage).ProtoReflect()
}
// Resolve message field dependencies.
for j := range md.lazy.fields.list {
fd := &md.lazy.fields.list[j]
if fd.isWeak {
continue
}
switch fd.kind {
case pref.EnumKind:
fd.enumType = file.popEnumDependency()
case pref.MessageKind, pref.GroupKind:
fd.messageType = file.popMessageDependency()
}
fd.isMap = file.isMapEntry(fd.messageType)
if !fd.hasPacked && file.lazy.syntax != pref.Proto2 && fd.cardinality == pref.Repeated {
switch fd.kind {
case pref.StringKind, pref.BytesKind, pref.MessageKind, pref.GroupKind:
fd.isPacked = false
default:
fd.isPacked = true
}
}
fd.defVal.lazyInit(fd.kind, file.enumValuesOf(fd.enumType))
}
}
}
func (file *fileDesc) resolveExtensions() {
for i := range file.allExtensions {
xd := &file.allExtensions[i]
// Associate the ExtensionType with a concrete Go type.
var typ reflect.Type
switch xd.lazy.kind {
case pref.EnumKind, pref.MessageKind, pref.GroupKind:
typ = reflect.TypeOf(file.GoTypes[file.DependencyIndexes[0]])
default:
typ = goTypeForPBKind[xd.lazy.kind]
}
switch xd.lazy.cardinality {
case pref.Optional:
switch xd.lazy.kind {
case pref.EnumKind:
xd.lazy.typ = typ
xd.lazy.new = func() pref.Value {
return xd.lazy.defVal.get()
}
xd.lazy.valueOf = func(v interface{}) pref.Value {
ev := v.(pref.Enum)
return pref.ValueOf(ev.Number())
}
xd.lazy.interfaceOf = func(pv pref.Value) interface{} {
return xd.lazy.enumType.New(pv.Enum())
}
case pref.MessageKind, pref.GroupKind:
xd.lazy.typ = typ
xd.lazy.new = func() pref.Value {
return pref.ValueOf(xd.lazy.messageType.New())
}
xd.lazy.valueOf = func(v interface{}) pref.Value {
mv := v.(pref.ProtoMessage).ProtoReflect()
return pref.ValueOf(mv)
}
xd.lazy.interfaceOf = func(pv pref.Value) interface{} {
return pv.Message().Interface()
}
default:
xd.lazy.typ = goTypeForPBKind[xd.lazy.kind]
xd.lazy.new = func() pref.Value {
return xd.lazy.defVal.get()
}
xd.lazy.valueOf = func(v interface{}) pref.Value {
return pref.ValueOf(v)
}
xd.lazy.interfaceOf = func(pv pref.Value) interface{} {
return pv.Interface()
}
}
case pref.Repeated:
c := pvalue.NewConverter(typ, xd.lazy.kind)
xd.lazy.typ = reflect.PtrTo(reflect.SliceOf(typ))
xd.lazy.new = func() pref.Value {
v := reflect.New(xd.lazy.typ.Elem()).Interface()
return pref.ValueOf(pvalue.ListOf(v, c))
}
xd.lazy.valueOf = func(v interface{}) pref.Value {
return pref.ValueOf(pvalue.ListOf(v, c))
}
xd.lazy.interfaceOf = func(pv pref.Value) interface{} {
return pv.List().(pvalue.Unwrapper).ProtoUnwrap()
}
default:
panic(fmt.Sprintf("invalid cardinality: %v", xd.lazy.cardinality))
}
// Resolve extension field dependency.
switch xd.lazy.kind {
case pref.EnumKind:
xd.lazy.enumType = file.popEnumDependency()
case pref.MessageKind, pref.GroupKind:
xd.lazy.messageType = file.popMessageDependency()
}
xd.lazy.defVal.lazyInit(xd.lazy.kind, file.enumValuesOf(xd.lazy.enumType))
}
}
var goTypeForPBKind = map[pref.Kind]reflect.Type{
pref.BoolKind: reflect.TypeOf(bool(false)),
pref.Int32Kind: reflect.TypeOf(int32(0)),
pref.Sint32Kind: reflect.TypeOf(int32(0)),
pref.Sfixed32Kind: reflect.TypeOf(int32(0)),
pref.Int64Kind: reflect.TypeOf(int64(0)),
pref.Sint64Kind: reflect.TypeOf(int64(0)),
pref.Sfixed64Kind: reflect.TypeOf(int64(0)),
pref.Uint32Kind: reflect.TypeOf(uint32(0)),
pref.Fixed32Kind: reflect.TypeOf(uint32(0)),
pref.Uint64Kind: reflect.TypeOf(uint64(0)),
pref.Fixed64Kind: reflect.TypeOf(uint64(0)),
pref.FloatKind: reflect.TypeOf(float32(0)),
pref.DoubleKind: reflect.TypeOf(float64(0)),
pref.StringKind: reflect.TypeOf(string("")),
pref.BytesKind: reflect.TypeOf([]byte(nil)),
}
func (file *fileDesc) resolveServices() {
for i := range file.services.list {
sd := &file.services.list[i]
// Resolve method dependencies.
for j := range sd.lazy.methods.list {
md := &sd.lazy.methods.list[j]
md.inputType = file.popMessageDependency()
md.outputType = file.popMessageDependency()
}
}
}
// isMapEntry reports whether the message is a map entry, being careful to
// avoid calling the IsMapEntry method if the message is declared
// within the same file (which would cause a recursive init deadlock).
func (fd *fileDesc) isMapEntry(md pref.MessageDescriptor) bool {
if md == nil {
return false
}
if md, ok := md.(*messageDesc); ok && md.parentFile == fd {
return md.lazy.isMapEntry
}
return md.IsMapEntry()
}
// enumValuesOf retrieves the list of enum values for the given enum,
// being careful to avoid calling the Values method if the enum is declared
// within the same file (which would cause a recursive init deadlock).
func (fd *fileDesc) enumValuesOf(ed pref.EnumDescriptor) pref.EnumValueDescriptors {
if ed == nil {
return nil
}
if ed, ok := ed.(*enumDesc); ok && ed.parentFile == fd {
return &ed.lazy.values
}
return ed.Values()
}
func (fd *fileDesc) popEnumDependency() pref.EnumType {
depIdx := fd.popDependencyIndex()
if depIdx < len(fd.allEnums)+len(fd.allMessages) {
return &fd.allEnums[depIdx]
} else {
return pimpl.Export{}.EnumTypeOf(fd.GoTypes[depIdx])
}
}
func (fd *fileDesc) popMessageDependency() pref.MessageType {
depIdx := fd.popDependencyIndex()
if depIdx < len(fd.allEnums)+len(fd.allMessages) {
return &fd.allMessages[depIdx-len(fd.allEnums)]
} else {
return pimpl.Export{}.MessageTypeOf(fd.GoTypes[depIdx])
}
}
func (fi *fileInit) popDependencyIndex() int {
depIdx := fi.DependencyIndexes[0]
fi.DependencyIndexes = fi.DependencyIndexes[1:]
return int(depIdx)
}
func (fi *fileInit) finishInit() {
if len(fi.DependencyIndexes) > 0 {
panic("unused dependencies")
}
*fi = fileInit{} // clear fileInit for GC to reclaim resources
}
type defaultValue struct {
has bool
val pref.Value
enum pref.EnumValueDescriptor
check func() // only set for non-empty bytes
}
func (dv *defaultValue) get() pref.Value {
if dv.check != nil {
dv.check()
}
return dv.val
}
func (dv *defaultValue) lazyInit(k pref.Kind, eds pref.EnumValueDescriptors) {
if dv.has {
switch k {
case pref.EnumKind:
// File descriptors always store default enums by name.
dv.enum = eds.ByName(pref.Name(dv.val.String()))
dv.val = pref.ValueOf(dv.enum.Number())
case pref.BytesKind:
// Store a copy of the default bytes, so that we can detect
// accidental mutations of the original value.
b := append([]byte(nil), dv.val.Bytes()...)
dv.check = func() {
if !bytes.Equal(b, dv.val.Bytes()) {
// TODO: Avoid panic if we're running with the race detector
// and instead spawn a goroutine that periodically resets
// this value back to the original to induce a race.
panic("detected mutation on the default bytes")
}
}
}
} else {
switch k {
case pref.BoolKind:
dv.val = pref.ValueOf(false)
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
dv.val = pref.ValueOf(int32(0))
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
dv.val = pref.ValueOf(int64(0))
case pref.Uint32Kind, pref.Fixed32Kind:
dv.val = pref.ValueOf(uint32(0))
case pref.Uint64Kind, pref.Fixed64Kind:
dv.val = pref.ValueOf(uint64(0))
case pref.FloatKind:
dv.val = pref.ValueOf(float32(0))
case pref.DoubleKind:
dv.val = pref.ValueOf(float64(0))
case pref.StringKind:
dv.val = pref.ValueOf(string(""))
case pref.BytesKind:
dv.val = pref.ValueOf([]byte(nil))
case pref.EnumKind:
dv.enum = eds.Get(0)
dv.val = pref.ValueOf(dv.enum.Number())
}
}
}
func (fd *fileDesc) unmarshalFull(b []byte) {
nb := getNameBuilder()
defer putNameBuilder(nb)
var hasSyntax bool
var enumIdx, messageIdx, extensionIdx, serviceIdx int
fd.lazy = &fileLazy{byName: make(map[pref.FullName]pref.Descriptor)}
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case fileDesc_PublicImports:
fd.lazy.imports[v].IsPublic = true
case fileDesc_WeakImports:
fd.lazy.imports[v].IsWeak = true
}
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case fileDesc_Syntax:
hasSyntax = true
switch string(v) {
case "proto2":
fd.lazy.syntax = pref.Proto2
case "proto3":
fd.lazy.syntax = pref.Proto3
default:
panic("invalid syntax")
}
case fileDesc_Imports:
fd.lazy.imports = append(fd.lazy.imports, pref.FileImport{
FileDescriptor: ptype.PlaceholderFile(nb.MakeString(v), ""),
})
case fileDesc_Enums:
fd.enums.list[enumIdx].unmarshalFull(v, nb)
enumIdx++
case fileDesc_Messages:
fd.messages.list[messageIdx].unmarshalFull(v, nb)
messageIdx++
case fileDesc_Extensions:
fd.extensions.list[extensionIdx].unmarshalFull(v, nb)
extensionIdx++
case fileDesc_Services:
fd.services.list[serviceIdx].unmarshalFull(v, nb)
serviceIdx++
case fileDesc_Options:
fd.lazy.options = append(fd.lazy.options, v...)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
// If syntax is missing, it is assumed to be proto2.
if !hasSyntax {
fd.lazy.syntax = pref.Proto2
}
}
func (ed *enumDesc) unmarshalFull(b []byte, nb *nameBuilder) {
var rawValues [][]byte
ed.lazy = new(enumLazy)
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case enumDesc_Values:
rawValues = append(rawValues, v)
case enumDesc_ReservedNames:
ed.lazy.resvNames.list = append(ed.lazy.resvNames.list, pref.Name(nb.MakeString(v)))
case enumDesc_ReservedRanges:
ed.lazy.resvRanges.list = append(ed.lazy.resvRanges.list, unmarshalEnumReservedRange(v))
case enumDesc_Options:
ed.lazy.options = append(ed.lazy.options, v...)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if len(rawValues) > 0 {
ed.lazy.values.list = make([]enumValueDesc, len(rawValues))
for i, b := range rawValues {
ed.lazy.values.list[i].unmarshalFull(b, nb, ed.parentFile, ed, i)
}
}
ed.parentFile.lazy.byName[ed.FullName()] = ed
}
func unmarshalEnumReservedRange(b []byte) (r [2]pref.EnumNumber) {
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case enumReservedRange_Start:
r[0] = pref.EnumNumber(v)
case enumReservedRange_End:
r[1] = pref.EnumNumber(v)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
return r
}
func (vd *enumValueDesc) unmarshalFull(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
vd.parentFile = pf
vd.parent = pd
vd.index = i
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case enumValueDesc_Number:
vd.number = pref.EnumNumber(v)
}
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case enumValueDesc_Name:
vd.fullName = nb.AppendFullName(pd.FullName(), v)
case enumValueDesc_Options:
vd.options = append(vd.options, v...)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
vd.parentFile.lazy.byName[vd.FullName()] = vd
}
func (md *messageDesc) unmarshalFull(b []byte, nb *nameBuilder) {
var rawFields, rawOneofs [][]byte
var enumIdx, messageIdx, extensionIdx int
md.lazy = new(messageLazy)
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case messageDesc_Fields:
rawFields = append(rawFields, v)
case messageDesc_Oneofs:
rawOneofs = append(rawOneofs, v)
case messageDesc_ReservedNames:
md.lazy.resvNames.list = append(md.lazy.resvNames.list, pref.Name(nb.MakeString(v)))
case messageDesc_ReservedRanges:
md.lazy.resvRanges.list = append(md.lazy.resvRanges.list, unmarshalMessageReservedRange(v))
case messageDesc_ExtensionRanges:
r, opts := unmarshalMessageExtensionRange(v)
md.lazy.extRanges.list = append(md.lazy.extRanges.list, r)
md.lazy.extRangeOptions = append(md.lazy.extRangeOptions, opts)
case messageDesc_Enums:
md.enums.list[enumIdx].unmarshalFull(v, nb)
enumIdx++
case messageDesc_Messages:
md.messages.list[messageIdx].unmarshalFull(v, nb)
messageIdx++
case messageDesc_Extensions:
md.extensions.list[extensionIdx].unmarshalFull(v, nb)
extensionIdx++
case messageDesc_Options:
md.unmarshalOptions(v)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if len(rawFields) > 0 || len(rawOneofs) > 0 {
md.lazy.fields.list = make([]fieldDesc, len(rawFields))
md.lazy.oneofs.list = make([]oneofDesc, len(rawOneofs))
for i, b := range rawFields {
fd := &md.lazy.fields.list[i]
fd.unmarshalFull(b, nb, md.parentFile, md, i)
if fd.cardinality == pref.Required {
md.lazy.reqNumbers.list = append(md.lazy.reqNumbers.list, fd.number)
}
}
for i, b := range rawOneofs {
od := &md.lazy.oneofs.list[i]
od.unmarshalFull(b, nb, md.parentFile, md, i)
}
}
md.parentFile.lazy.byName[md.FullName()] = md
}
func (md *messageDesc) unmarshalOptions(b []byte) {
md.lazy.options = append(md.lazy.options, b...)
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case messageOptions_IsMapEntry:
md.lazy.isMapEntry = wire.DecodeBool(v)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func unmarshalMessageReservedRange(b []byte) (r [2]pref.FieldNumber) {
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case messageReservedRange_Start:
r[0] = pref.FieldNumber(v)
case messageReservedRange_End:
r[1] = pref.FieldNumber(v)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
return r
}
func unmarshalMessageExtensionRange(b []byte) (r [2]pref.FieldNumber, opts []byte) {
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case messageExtensionRange_Start:
r[0] = pref.FieldNumber(v)
case messageExtensionRange_End:
r[1] = pref.FieldNumber(v)
}
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case messageExtensionRange_Options:
opts = append(opts, v...)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
return r, opts
}
func (fd *fieldDesc) unmarshalFull(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
fd.parentFile = pf
fd.parent = pd
fd.index = i
var rawDefVal []byte
var rawTypeName []byte
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case fieldDesc_Number:
fd.number = pref.FieldNumber(v)
case fieldDesc_Cardinality:
fd.cardinality = pref.Cardinality(v)
case fieldDesc_Kind:
fd.kind = pref.Kind(v)
case fieldDesc_OneofIndex:
// In messageDesc.UnmarshalFull, we allocate slices for both
// the field and oneof descriptors before unmarshaling either
// of them. This ensures pointers to slice elements are stable.
od := &pd.(*messageDesc).lazy.oneofs.list[v]
od.fields.list = append(od.fields.list, fd)
if fd.oneofType != nil {
panic("oneof type already set")
}
fd.oneofType = od
}
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case fieldDesc_Name:
fd.fullName = nb.AppendFullName(pd.FullName(), v)
case fieldDesc_JSONName:
fd.hasJSONName = true
fd.jsonName = nb.MakeString(v)
case fieldDesc_Default:
fd.defVal.has = true
rawDefVal = v
case fieldDesc_TypeName:
rawTypeName = v
case fieldDesc_Options:
fd.unmarshalOptions(v)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if !fd.hasJSONName {
fd.jsonName = nb.MakeJSONName(fd.Name())
}
if rawDefVal != nil {
var err error
fd.defVal.val, err = defval.Unmarshal(string(rawDefVal), fd.kind, defval.Descriptor)
if err != nil {
panic(err)
}
}
if fd.isWeak {
if len(rawTypeName) == 0 || rawTypeName[0] != '.' {
panic("weak target name must be fully qualified")
}
fd.messageType = ptype.PlaceholderMessage(pref.FullName(rawTypeName[1:]))
}
fd.parentFile.lazy.byName[fd.FullName()] = fd
}
func (fd *fieldDesc) unmarshalOptions(b []byte) {
fd.options = append(fd.options, b...)
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case fieldOptions_IsPacked:
fd.hasPacked = true
fd.isPacked = wire.DecodeBool(v)
case fieldOptions_IsWeak:
fd.isWeak = wire.DecodeBool(v)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func (od *oneofDesc) unmarshalFull(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
od.parentFile = pf
od.parent = pd
od.index = i
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case oneofDesc_Name:
od.fullName = nb.AppendFullName(pd.FullName(), v)
case oneofDesc_Options:
od.options = append(od.options, v...)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
od.parentFile.lazy.byName[od.FullName()] = od
}
func (xd *extensionDesc) unmarshalFull(b []byte, nb *nameBuilder) {
var rawDefVal []byte
xd.lazy = new(extensionLazy)
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case fieldDesc_Cardinality:
xd.lazy.cardinality = pref.Cardinality(v)
case fieldDesc_Kind:
xd.lazy.kind = pref.Kind(v)
}
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case fieldDesc_JSONName:
xd.lazy.hasJSONName = true
xd.lazy.jsonName = nb.MakeString(v)
case fieldDesc_Default:
xd.lazy.defVal.has = true
rawDefVal = v
case fieldDesc_Options:
xd.unmarshalOptions(v)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if rawDefVal != nil {
var err error
xd.lazy.defVal.val, err = defval.Unmarshal(string(rawDefVal), xd.lazy.kind, defval.Descriptor)
if err != nil {
panic(err)
}
}
xd.parentFile.lazy.byName[xd.FullName()] = xd
}
func (xd *extensionDesc) unmarshalOptions(b []byte) {
xd.lazy.options = append(xd.lazy.options, b...)
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case fieldOptions_IsPacked:
xd.lazy.isPacked = wire.DecodeBool(v)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func (sd *serviceDesc) unmarshalFull(b []byte, nb *nameBuilder) {
var rawMethods [][]byte
sd.lazy = new(serviceLazy)
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case serviceDesc_Methods:
rawMethods = append(rawMethods, v)
case serviceDesc_Options:
sd.lazy.options = append(sd.lazy.options, v...)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if len(rawMethods) > 0 {
sd.lazy.methods.list = make([]methodDesc, len(rawMethods))
for i, b := range rawMethods {
sd.lazy.methods.list[i].unmarshalFull(b, nb, sd.parentFile, sd, i)
}
}
sd.parentFile.lazy.byName[sd.FullName()] = sd
}
func (md *methodDesc) unmarshalFull(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
md.parentFile = pf
md.parent = pd
md.index = i
for len(b) > 0 {
num, typ, n := wire.ConsumeTag(b)
b = b[n:]
switch typ {
case wire.VarintType:
v, m := wire.ConsumeVarint(b)
b = b[m:]
switch num {
case methodDesc_IsStreamingClient:
md.isStreamingClient = wire.DecodeBool(v)
case methodDesc_IsStreamingServer:
md.isStreamingServer = wire.DecodeBool(v)
}
case wire.BytesType:
v, m := wire.ConsumeBytes(b)
b = b[m:]
switch num {
case methodDesc_Name:
md.fullName = nb.AppendFullName(pd.FullName(), v)
case methodDesc_Options:
md.options = append(md.options, v...)
}
default:
m := wire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
md.parentFile.lazy.byName[md.FullName()] = md
}