| // 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" |
| fieldnum "github.com/golang/protobuf/v2/internal/fieldnum" |
| pimpl "github.com/golang/protobuf/v2/internal/impl" |
| ptype "github.com/golang/protobuf/v2/internal/prototype" |
| pvalue "github.com/golang/protobuf/v2/internal/value" |
| pref "github.com/golang/protobuf/v2/reflect/protoreflect" |
| ) |
| |
| 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. |
| if !md.isMapEntry { |
| 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().(pref.EnumType) |
| case pref.MessageKind, pref.GroupKind: |
| xd.lazy.messageType = file.popMessageDependency().(pref.MessageType) |
| } |
| 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.(*messageDescriptor); ok && md.parentFile == fd { |
| return md.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.EnumDescriptor { |
| 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.MessageDescriptor { |
| depIdx := fd.popDependencyIndex() |
| if depIdx < len(fd.allEnums)+len(fd.allMessages) { |
| return fd.allMessages[depIdx-len(fd.allEnums)].asDesc() |
| } 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 fieldnum.FileDescriptorProto_PublicDependency: |
| fd.lazy.imports[v].IsPublic = true |
| case fieldnum.FileDescriptorProto_WeakDependency: |
| fd.lazy.imports[v].IsWeak = true |
| } |
| case wire.BytesType: |
| v, m := wire.ConsumeBytes(b) |
| b = b[m:] |
| switch num { |
| case fieldnum.FileDescriptorProto_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 fieldnum.FileDescriptorProto_Dependency: |
| fd.lazy.imports = append(fd.lazy.imports, pref.FileImport{ |
| FileDescriptor: ptype.PlaceholderFile(nb.MakeString(v), ""), |
| }) |
| case fieldnum.FileDescriptorProto_EnumType: |
| fd.enums.list[enumIdx].unmarshalFull(v, nb) |
| enumIdx++ |
| case fieldnum.FileDescriptorProto_MessageType: |
| fd.messages.list[messageIdx].unmarshalFull(v, nb) |
| messageIdx++ |
| case fieldnum.FileDescriptorProto_Extension: |
| fd.extensions.list[extensionIdx].unmarshalFull(v, nb) |
| extensionIdx++ |
| case fieldnum.FileDescriptorProto_Service: |
| fd.services.list[serviceIdx].unmarshalFull(v, nb) |
| serviceIdx++ |
| case fieldnum.FileDescriptorProto_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 fieldnum.EnumDescriptorProto_Value: |
| rawValues = append(rawValues, v) |
| case fieldnum.EnumDescriptorProto_ReservedName: |
| ed.lazy.resvNames.list = append(ed.lazy.resvNames.list, pref.Name(nb.MakeString(v))) |
| case fieldnum.EnumDescriptorProto_ReservedRange: |
| ed.lazy.resvRanges.list = append(ed.lazy.resvRanges.list, unmarshalEnumReservedRange(v)) |
| case fieldnum.EnumDescriptorProto_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 fieldnum.EnumDescriptorProto_EnumReservedRange_Start: |
| r[0] = pref.EnumNumber(v) |
| case fieldnum.EnumDescriptorProto_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 fieldnum.EnumValueDescriptorProto_Number: |
| vd.number = pref.EnumNumber(v) |
| } |
| case wire.BytesType: |
| v, m := wire.ConsumeBytes(b) |
| b = b[m:] |
| switch num { |
| case fieldnum.EnumValueDescriptorProto_Name: |
| vd.fullName = nb.AppendFullName(pd.FullName(), v) |
| case fieldnum.EnumValueDescriptorProto_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 |
| var isMapEntry bool |
| 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 fieldnum.DescriptorProto_Field: |
| rawFields = append(rawFields, v) |
| case fieldnum.DescriptorProto_OneofDecl: |
| rawOneofs = append(rawOneofs, v) |
| case fieldnum.DescriptorProto_ReservedName: |
| md.lazy.resvNames.list = append(md.lazy.resvNames.list, pref.Name(nb.MakeString(v))) |
| case fieldnum.DescriptorProto_ReservedRange: |
| md.lazy.resvRanges.list = append(md.lazy.resvRanges.list, unmarshalMessageReservedRange(v)) |
| case fieldnum.DescriptorProto_ExtensionRange: |
| r, opts := unmarshalMessageExtensionRange(v) |
| md.lazy.extRanges.list = append(md.lazy.extRanges.list, r) |
| md.lazy.extRangeOptions = append(md.lazy.extRangeOptions, opts) |
| case fieldnum.DescriptorProto_EnumType: |
| md.enums.list[enumIdx].unmarshalFull(v, nb) |
| enumIdx++ |
| case fieldnum.DescriptorProto_NestedType: |
| md.messages.list[messageIdx].unmarshalFull(v, nb) |
| messageIdx++ |
| case fieldnum.DescriptorProto_Extension: |
| md.extensions.list[extensionIdx].unmarshalFull(v, nb) |
| extensionIdx++ |
| case fieldnum.DescriptorProto_Options: |
| md.unmarshalOptions(v, &isMapEntry) |
| } |
| 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.asDesc(), 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.asDesc(), i) |
| } |
| } |
| |
| if isMapEntry != md.isMapEntry { |
| panic("mismatching map entry property") |
| } |
| |
| md.parentFile.lazy.byName[md.FullName()] = md.asDesc() |
| } |
| |
| func (md *messageDesc) unmarshalOptions(b []byte, isMapEntry *bool) { |
| 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 fieldnum.MessageOptions_MapEntry: |
| *isMapEntry = wire.DecodeBool(v) |
| case fieldnum.MessageOptions_MessageSetWireFormat: |
| md.lazy.isMessageSet = 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 fieldnum.DescriptorProto_ReservedRange_Start: |
| r[0] = pref.FieldNumber(v) |
| case fieldnum.DescriptorProto_ReservedRange_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 fieldnum.DescriptorProto_ExtensionRange_Start: |
| r[0] = pref.FieldNumber(v) |
| case fieldnum.DescriptorProto_ExtensionRange_End: |
| r[1] = pref.FieldNumber(v) |
| } |
| case wire.BytesType: |
| v, m := wire.ConsumeBytes(b) |
| b = b[m:] |
| switch num { |
| case fieldnum.DescriptorProto_ExtensionRange_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 fieldnum.FieldDescriptorProto_Number: |
| fd.number = pref.FieldNumber(v) |
| case fieldnum.FieldDescriptorProto_Label: |
| fd.cardinality = pref.Cardinality(v) |
| case fieldnum.FieldDescriptorProto_Type: |
| fd.kind = pref.Kind(v) |
| case fieldnum.FieldDescriptorProto_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.(messageType).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 fieldnum.FieldDescriptorProto_Name: |
| fd.fullName = nb.AppendFullName(pd.FullName(), v) |
| case fieldnum.FieldDescriptorProto_JsonName: |
| fd.hasJSONName = true |
| fd.jsonName = nb.MakeString(v) |
| case fieldnum.FieldDescriptorProto_DefaultValue: |
| fd.defVal.has = true |
| rawDefVal = v |
| case fieldnum.FieldDescriptorProto_TypeName: |
| rawTypeName = v |
| case fieldnum.FieldDescriptorProto_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 fieldnum.FieldOptions_Packed: |
| fd.hasPacked = true |
| fd.isPacked = wire.DecodeBool(v) |
| case fieldnum.FieldOptions_Weak: |
| 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 fieldnum.OneofDescriptorProto_Name: |
| od.fullName = nb.AppendFullName(pd.FullName(), v) |
| case fieldnum.OneofDescriptorProto_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 fieldnum.FieldDescriptorProto_Label: |
| xd.lazy.cardinality = pref.Cardinality(v) |
| case fieldnum.FieldDescriptorProto_Type: |
| xd.lazy.kind = pref.Kind(v) |
| } |
| case wire.BytesType: |
| v, m := wire.ConsumeBytes(b) |
| b = b[m:] |
| switch num { |
| case fieldnum.FieldDescriptorProto_JsonName: |
| xd.lazy.hasJSONName = true |
| xd.lazy.jsonName = nb.MakeString(v) |
| case fieldnum.FieldDescriptorProto_DefaultValue: |
| xd.lazy.defVal.has = true |
| rawDefVal = v |
| case fieldnum.FieldDescriptorProto_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 fieldnum.FieldOptions_Packed: |
| 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 fieldnum.ServiceDescriptorProto_Method: |
| rawMethods = append(rawMethods, v) |
| case fieldnum.ServiceDescriptorProto_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 fieldnum.MethodDescriptorProto_ClientStreaming: |
| md.isStreamingClient = wire.DecodeBool(v) |
| case fieldnum.MethodDescriptorProto_ServerStreaming: |
| md.isStreamingServer = wire.DecodeBool(v) |
| } |
| case wire.BytesType: |
| v, m := wire.ConsumeBytes(b) |
| b = b[m:] |
| switch num { |
| case fieldnum.MethodDescriptorProto_Name: |
| md.fullName = nb.AppendFullName(pd.FullName(), v) |
| case fieldnum.MethodDescriptorProto_Options: |
| md.options = append(md.options, v...) |
| } |
| default: |
| m := wire.ConsumeFieldValue(num, typ, b) |
| b = b[m:] |
| } |
| } |
| |
| md.parentFile.lazy.byName[md.FullName()] = md |
| } |