| // 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 prototype |
| |
| import ( |
| "bytes" |
| "fmt" |
| "strings" |
| "sync" |
| |
| pragma "github.com/golang/protobuf/v2/internal/pragma" |
| pfmt "github.com/golang/protobuf/v2/internal/typefmt" |
| pref "github.com/golang/protobuf/v2/reflect/protoreflect" |
| ) |
| |
| // inheritedMeta is information inherited from the parent. |
| type inheritedMeta struct { |
| parent pref.Descriptor |
| index int |
| syntax pref.Syntax |
| fullName pref.FullName |
| } |
| |
| func (m *inheritedMeta) init(nb *nameBuilder, parent pref.Descriptor, index int, name pref.Name, child bool) { |
| // Most descriptors are namespaced as a child of their parent. |
| // However, EnumValues are the exception in that they are namespaced |
| // as a sibling of the parent Enum type. |
| prefix := parent.FullName() |
| if child { |
| prefix = prefix.Parent() |
| } |
| |
| m.parent = parent |
| m.index = index |
| m.syntax = parent.Syntax() |
| m.fullName = nb.Append(prefix, name) |
| } |
| |
| type fileMeta struct { |
| ms messagesMeta |
| es enumsMeta |
| xs extensionsMeta |
| ss servicesMeta |
| ds descriptorsMeta |
| } |
| type fileDesc struct{ f *File } |
| |
| // altOptions returns m as is if it is non-nil. Otherwise, it returns alt. |
| func altOptions(m, alt pref.OptionsMessage) pref.OptionsMessage { |
| if m != nil { |
| return m |
| } |
| return alt |
| } |
| |
| func newFile(f *File) fileDesc { |
| if f.fileMeta != nil { |
| panic("already initialized") |
| } |
| f.fileMeta = new(fileMeta) |
| return fileDesc{f} |
| } |
| func (t fileDesc) Parent() (pref.Descriptor, bool) { return nil, false } |
| func (t fileDesc) Index() int { return 0 } |
| func (t fileDesc) Syntax() pref.Syntax { return t.f.Syntax } |
| func (t fileDesc) Name() pref.Name { return t.f.Package.Name() } |
| func (t fileDesc) FullName() pref.FullName { return t.f.Package } |
| func (t fileDesc) IsPlaceholder() bool { return false } |
| func (t fileDesc) Options() pref.OptionsMessage { return altOptions(t.f.Options, optionTypes.File) } |
| func (t fileDesc) Path() string { return t.f.Path } |
| func (t fileDesc) Package() pref.FullName { return t.f.Package } |
| func (t fileDesc) Imports() pref.FileImports { return (*fileImports)(&t.f.Imports) } |
| func (t fileDesc) Enums() pref.EnumDescriptors { return t.f.es.lazyInit(t, t.f.Enums) } |
| func (t fileDesc) Messages() pref.MessageDescriptors { return t.f.ms.lazyInit(t, t.f.Messages) } |
| func (t fileDesc) Extensions() pref.ExtensionDescriptors { return t.f.xs.lazyInit(t, t.f.Extensions) } |
| func (t fileDesc) Services() pref.ServiceDescriptors { return t.f.ss.lazyInit(t, t.f.Services) } |
| func (t fileDesc) DescriptorByName(s pref.FullName) pref.Descriptor { return t.f.ds.lookup(t, s) } |
| func (t fileDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t fileDesc) ProtoType(pref.FileDescriptor) {} |
| func (t fileDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| // descriptorsMeta is a lazily initialized map of all descriptors declared in |
| // the file by full name. |
| type descriptorsMeta struct { |
| once sync.Once |
| m map[pref.FullName]pref.Descriptor |
| } |
| |
| func (m *descriptorsMeta) lookup(fd pref.FileDescriptor, s pref.FullName) pref.Descriptor { |
| m.once.Do(func() { |
| m.m = make(map[pref.FullName]pref.Descriptor) |
| m.initMap(fd) |
| delete(m.m, fd.Package()) // avoid registering the file descriptor itself |
| }) |
| return m.m[s] |
| } |
| func (m *descriptorsMeta) initMap(d pref.Descriptor) { |
| m.m[d.FullName()] = d |
| if ds, ok := d.(interface { |
| Enums() pref.EnumDescriptors |
| }); ok { |
| for i := 0; i < ds.Enums().Len(); i++ { |
| m.initMap(ds.Enums().Get(i)) |
| } |
| } |
| if ds, ok := d.(interface { |
| Values() pref.EnumValueDescriptors |
| }); ok { |
| for i := 0; i < ds.Values().Len(); i++ { |
| m.initMap(ds.Values().Get(i)) |
| } |
| } |
| if ds, ok := d.(interface { |
| Messages() pref.MessageDescriptors |
| }); ok { |
| for i := 0; i < ds.Messages().Len(); i++ { |
| m.initMap(ds.Messages().Get(i)) |
| } |
| } |
| if ds, ok := d.(interface { |
| Fields() pref.FieldDescriptors |
| }); ok { |
| for i := 0; i < ds.Fields().Len(); i++ { |
| m.initMap(ds.Fields().Get(i)) |
| } |
| } |
| if ds, ok := d.(interface { |
| Oneofs() pref.OneofDescriptors |
| }); ok { |
| for i := 0; i < ds.Oneofs().Len(); i++ { |
| m.initMap(ds.Oneofs().Get(i)) |
| } |
| } |
| if ds, ok := d.(interface { |
| Extensions() pref.ExtensionDescriptors |
| }); ok { |
| for i := 0; i < ds.Extensions().Len(); i++ { |
| m.initMap(ds.Extensions().Get(i)) |
| } |
| } |
| if ds, ok := d.(interface { |
| Services() pref.ServiceDescriptors |
| }); ok { |
| for i := 0; i < ds.Services().Len(); i++ { |
| m.initMap(ds.Services().Get(i)) |
| } |
| } |
| if ds, ok := d.(interface { |
| Methods() pref.MethodDescriptors |
| }); ok { |
| for i := 0; i < ds.Methods().Len(); i++ { |
| m.initMap(ds.Methods().Get(i)) |
| } |
| } |
| } |
| |
| type messageMeta struct { |
| inheritedMeta |
| |
| fs fieldsMeta |
| os oneofsMeta |
| ns numbersMeta |
| ms messagesMeta |
| es enumsMeta |
| xs extensionsMeta |
| } |
| type messageDesc struct{ m *Message } |
| |
| func (t messageDesc) Parent() (pref.Descriptor, bool) { return t.m.parent, true } |
| func (t messageDesc) Index() int { return t.m.index } |
| func (t messageDesc) Syntax() pref.Syntax { return t.m.syntax } |
| func (t messageDesc) Name() pref.Name { return t.m.Name } |
| func (t messageDesc) FullName() pref.FullName { return t.m.fullName } |
| func (t messageDesc) IsPlaceholder() bool { return false } |
| func (t messageDesc) Options() pref.OptionsMessage { |
| return altOptions(t.m.Options, optionTypes.Message) |
| } |
| func (t messageDesc) IsMapEntry() bool { return t.m.IsMapEntry } |
| func (t messageDesc) Fields() pref.FieldDescriptors { return t.m.fs.lazyInit(t, t.m.Fields) } |
| func (t messageDesc) Oneofs() pref.OneofDescriptors { return t.m.os.lazyInit(t, t.m.Oneofs) } |
| func (t messageDesc) ReservedNames() pref.Names { return (*names)(&t.m.ReservedNames) } |
| func (t messageDesc) ReservedRanges() pref.FieldRanges { return (*fieldRanges)(&t.m.ReservedRanges) } |
| func (t messageDesc) RequiredNumbers() pref.FieldNumbers { return t.m.ns.lazyInit(t.m.Fields) } |
| func (t messageDesc) ExtensionRanges() pref.FieldRanges { return (*fieldRanges)(&t.m.ExtensionRanges) } |
| func (t messageDesc) ExtensionRangeOptions(i int) pref.OptionsMessage { |
| return extensionRangeOptions(i, len(t.m.ExtensionRanges), t.m.ExtensionRangeOptions) |
| } |
| func (t messageDesc) Enums() pref.EnumDescriptors { return t.m.es.lazyInit(t, t.m.Enums) } |
| func (t messageDesc) Messages() pref.MessageDescriptors { return t.m.ms.lazyInit(t, t.m.Messages) } |
| func (t messageDesc) Extensions() pref.ExtensionDescriptors { return t.m.xs.lazyInit(t, t.m.Extensions) } |
| func (t messageDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t messageDesc) ProtoType(pref.MessageDescriptor) {} |
| func (t messageDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| func extensionRangeOptions(i, n int, ms []pref.OptionsMessage) pref.OptionsMessage { |
| if i < 0 || i >= n { |
| panic("out of bounds") |
| } |
| var m pref.OptionsMessage |
| if i < len(ms) { |
| m = ms[i] |
| } |
| if m == nil { |
| m = optionTypes.ExtensionRange |
| } |
| return m |
| } |
| |
| type fieldMeta struct { |
| inheritedMeta |
| |
| js jsonName |
| dv defaultValue |
| ot oneofReference |
| mt messageReference |
| et enumReference |
| } |
| type fieldDesc struct{ f *Field } |
| |
| func (t fieldDesc) Parent() (pref.Descriptor, bool) { return t.f.parent, true } |
| func (t fieldDesc) Index() int { return t.f.index } |
| func (t fieldDesc) Syntax() pref.Syntax { return t.f.syntax } |
| func (t fieldDesc) Name() pref.Name { return t.f.Name } |
| func (t fieldDesc) FullName() pref.FullName { return t.f.fullName } |
| func (t fieldDesc) IsPlaceholder() bool { return false } |
| func (t fieldDesc) Options() pref.OptionsMessage { return altOptions(t.f.Options, optionTypes.Field) } |
| func (t fieldDesc) Number() pref.FieldNumber { return t.f.Number } |
| func (t fieldDesc) Cardinality() pref.Cardinality { return t.f.Cardinality } |
| func (t fieldDesc) Kind() pref.Kind { return t.f.Kind } |
| func (t fieldDesc) HasJSONName() bool { return t.f.JSONName != "" } |
| func (t fieldDesc) JSONName() string { return t.f.js.lazyInit(t.f) } |
| func (t fieldDesc) IsPacked() bool { |
| return isPacked(t.f.IsPacked, t.f.syntax, t.f.Cardinality, t.f.Kind) |
| } |
| func (t fieldDesc) IsWeak() bool { return t.f.IsWeak } |
| func (t fieldDesc) IsMap() bool { |
| mt := t.MessageType() |
| return mt != nil && mt.IsMapEntry() |
| } |
| func (t fieldDesc) HasDefault() bool { return t.f.Default.IsValid() } |
| func (t fieldDesc) Default() pref.Value { return t.f.dv.value(t, t.f.Default) } |
| func (t fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.f.dv.enum(t, t.f.Default) } |
| func (t fieldDesc) OneofType() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) } |
| func (t fieldDesc) ExtendedType() pref.MessageDescriptor { return nil } |
| func (t fieldDesc) MessageType() pref.MessageDescriptor { return t.f.mt.lazyInit(t, &t.f.MessageType) } |
| func (t fieldDesc) EnumType() pref.EnumDescriptor { return t.f.et.lazyInit(t, &t.f.EnumType) } |
| func (t fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t fieldDesc) ProtoType(pref.FieldDescriptor) {} |
| func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| func isPacked(packed OptionalBool, s pref.Syntax, c pref.Cardinality, k pref.Kind) bool { |
| if packed == False || (packed == DefaultBool && s == pref.Proto2) { |
| return false |
| } |
| if c != pref.Repeated { |
| return false |
| } |
| switch k { |
| case pref.StringKind, pref.BytesKind, pref.MessageKind, pref.GroupKind: |
| return false |
| } |
| return true |
| } |
| |
| type jsonName struct { |
| once sync.Once |
| name string |
| } |
| |
| func (p *jsonName) lazyInit(f *Field) string { |
| p.once.Do(func() { |
| // TODO: We may need to share this logic with jsonpb for implementation |
| // of the FieldMask well-known type. |
| if f.JSONName != "" { |
| p.name = f.JSONName |
| return |
| } |
| var b []byte |
| var wasUnderscore bool |
| for i := 0; i < len(f.Name); i++ { // proto identifiers are always ASCII |
| c := f.Name[i] |
| if c != '_' { |
| isLower := 'a' <= c && c <= 'z' |
| if wasUnderscore && isLower { |
| c -= 'a' - 'A' |
| } |
| b = append(b, c) |
| } |
| wasUnderscore = c == '_' |
| } |
| p.name = string(b) |
| }) |
| return p.name |
| } |
| |
| // oneofReference resolves the name of a oneof by searching the parent |
| // message for the matching OneofDescriptor declaration. |
| type oneofReference struct { |
| once sync.Once |
| otyp pref.OneofDescriptor |
| } |
| |
| func (p *oneofReference) lazyInit(parent pref.Descriptor, name pref.Name) pref.OneofDescriptor { |
| p.once.Do(func() { |
| if name != "" { |
| mtyp, _ := parent.Parent() |
| p.otyp = mtyp.(pref.MessageDescriptor).Oneofs().ByName(name) |
| // TODO: We need validate to detect this mismatch. |
| } |
| }) |
| return p.otyp |
| } |
| |
| type oneofMeta struct { |
| inheritedMeta |
| |
| fs oneofFieldsMeta |
| } |
| type oneofDesc struct{ o *Oneof } |
| |
| func (t oneofDesc) Parent() (pref.Descriptor, bool) { return t.o.parent, true } |
| func (t oneofDesc) Index() int { return t.o.index } |
| func (t oneofDesc) Syntax() pref.Syntax { return t.o.syntax } |
| func (t oneofDesc) Name() pref.Name { return t.o.Name } |
| func (t oneofDesc) FullName() pref.FullName { return t.o.fullName } |
| func (t oneofDesc) IsPlaceholder() bool { return false } |
| func (t oneofDesc) Options() pref.OptionsMessage { return altOptions(t.o.Options, optionTypes.Oneof) } |
| func (t oneofDesc) Fields() pref.FieldDescriptors { return t.o.fs.lazyInit(t) } |
| func (t oneofDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t oneofDesc) ProtoType(pref.OneofDescriptor) {} |
| func (t oneofDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| type extensionMeta struct { |
| inheritedMeta |
| |
| dv defaultValue |
| xt messageReference |
| mt messageReference |
| et enumReference |
| } |
| type extensionDesc struct{ x *Extension } |
| |
| func (t extensionDesc) Parent() (pref.Descriptor, bool) { return t.x.parent, true } |
| func (t extensionDesc) Syntax() pref.Syntax { return t.x.syntax } |
| func (t extensionDesc) Index() int { return t.x.index } |
| func (t extensionDesc) Name() pref.Name { return t.x.Name } |
| func (t extensionDesc) FullName() pref.FullName { return t.x.fullName } |
| func (t extensionDesc) IsPlaceholder() bool { return false } |
| func (t extensionDesc) Options() pref.OptionsMessage { |
| return altOptions(t.x.Options, optionTypes.Field) |
| } |
| func (t extensionDesc) Number() pref.FieldNumber { return t.x.Number } |
| func (t extensionDesc) Cardinality() pref.Cardinality { return t.x.Cardinality } |
| func (t extensionDesc) Kind() pref.Kind { return t.x.Kind } |
| func (t extensionDesc) HasJSONName() bool { return false } |
| func (t extensionDesc) JSONName() string { return "" } |
| func (t extensionDesc) IsPacked() bool { |
| // Extensions always use proto2 defaults for packing. |
| return isPacked(t.x.IsPacked, pref.Proto2, t.x.Cardinality, t.x.Kind) |
| } |
| func (t extensionDesc) IsWeak() bool { return false } |
| func (t extensionDesc) IsMap() bool { return false } |
| func (t extensionDesc) HasDefault() bool { return t.x.Default.IsValid() } |
| func (t extensionDesc) Default() pref.Value { return t.x.dv.value(t, t.x.Default) } |
| func (t extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.x.dv.enum(t, t.x.Default) } |
| func (t extensionDesc) OneofType() pref.OneofDescriptor { return nil } |
| func (t extensionDesc) ExtendedType() pref.MessageDescriptor { |
| return t.x.xt.lazyInit(t, &t.x.ExtendedType) |
| } |
| func (t extensionDesc) MessageType() pref.MessageDescriptor { |
| return t.x.mt.lazyInit(t, &t.x.MessageType) |
| } |
| func (t extensionDesc) EnumType() pref.EnumDescriptor { return t.x.et.lazyInit(t, &t.x.EnumType) } |
| func (t extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t extensionDesc) ProtoType(pref.FieldDescriptor) {} |
| func (t extensionDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| type enumMeta struct { |
| inheritedMeta |
| |
| vs enumValuesMeta |
| } |
| type enumDesc struct{ e *Enum } |
| |
| func (t enumDesc) Parent() (pref.Descriptor, bool) { return t.e.parent, true } |
| func (t enumDesc) Index() int { return t.e.index } |
| func (t enumDesc) Syntax() pref.Syntax { return t.e.syntax } |
| func (t enumDesc) Name() pref.Name { return t.e.Name } |
| func (t enumDesc) FullName() pref.FullName { return t.e.fullName } |
| func (t enumDesc) IsPlaceholder() bool { return false } |
| func (t enumDesc) Options() pref.OptionsMessage { return altOptions(t.e.Options, optionTypes.Enum) } |
| func (t enumDesc) Values() pref.EnumValueDescriptors { return t.e.vs.lazyInit(t, t.e.Values) } |
| func (t enumDesc) ReservedNames() pref.Names { return (*names)(&t.e.ReservedNames) } |
| func (t enumDesc) ReservedRanges() pref.EnumRanges { return (*enumRanges)(&t.e.ReservedRanges) } |
| func (t enumDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t enumDesc) ProtoType(pref.EnumDescriptor) {} |
| func (t enumDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| type enumValueMeta struct { |
| inheritedMeta |
| } |
| type enumValueDesc struct{ v *EnumValue } |
| |
| func (t enumValueDesc) Parent() (pref.Descriptor, bool) { return t.v.parent, true } |
| func (t enumValueDesc) Index() int { return t.v.index } |
| func (t enumValueDesc) Syntax() pref.Syntax { return t.v.syntax } |
| func (t enumValueDesc) Name() pref.Name { return t.v.Name } |
| func (t enumValueDesc) FullName() pref.FullName { return t.v.fullName } |
| func (t enumValueDesc) IsPlaceholder() bool { return false } |
| func (t enumValueDesc) Options() pref.OptionsMessage { |
| return altOptions(t.v.Options, optionTypes.EnumValue) |
| } |
| func (t enumValueDesc) Number() pref.EnumNumber { return t.v.Number } |
| func (t enumValueDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t enumValueDesc) ProtoType(pref.EnumValueDescriptor) {} |
| func (t enumValueDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| type serviceMeta struct { |
| inheritedMeta |
| |
| ms methodsMeta |
| } |
| type serviceDesc struct{ s *Service } |
| |
| func (t serviceDesc) Parent() (pref.Descriptor, bool) { return t.s.parent, true } |
| func (t serviceDesc) Index() int { return t.s.index } |
| func (t serviceDesc) Syntax() pref.Syntax { return t.s.syntax } |
| func (t serviceDesc) Name() pref.Name { return t.s.Name } |
| func (t serviceDesc) FullName() pref.FullName { return t.s.fullName } |
| func (t serviceDesc) IsPlaceholder() bool { return false } |
| func (t serviceDesc) Options() pref.OptionsMessage { |
| return altOptions(t.s.Options, optionTypes.Service) |
| } |
| func (t serviceDesc) Methods() pref.MethodDescriptors { return t.s.ms.lazyInit(t, t.s.Methods) } |
| func (t serviceDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t serviceDesc) ProtoType(pref.ServiceDescriptor) {} |
| func (t serviceDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| type methodMeta struct { |
| inheritedMeta |
| |
| mit messageReference |
| mot messageReference |
| } |
| type methodDesc struct{ m *Method } |
| |
| func (t methodDesc) Parent() (pref.Descriptor, bool) { return t.m.parent, true } |
| func (t methodDesc) Index() int { return t.m.index } |
| func (t methodDesc) Syntax() pref.Syntax { return t.m.syntax } |
| func (t methodDesc) Name() pref.Name { return t.m.Name } |
| func (t methodDesc) FullName() pref.FullName { return t.m.fullName } |
| func (t methodDesc) IsPlaceholder() bool { return false } |
| func (t methodDesc) Options() pref.OptionsMessage { return altOptions(t.m.Options, optionTypes.Method) } |
| func (t methodDesc) InputType() pref.MessageDescriptor { return t.m.mit.lazyInit(t, &t.m.InputType) } |
| func (t methodDesc) OutputType() pref.MessageDescriptor { return t.m.mot.lazyInit(t, &t.m.OutputType) } |
| func (t methodDesc) IsStreamingClient() bool { return t.m.IsStreamingClient } |
| func (t methodDesc) IsStreamingServer() bool { return t.m.IsStreamingServer } |
| func (t methodDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) } |
| func (t methodDesc) ProtoType(pref.MethodDescriptor) {} |
| func (t methodDesc) ProtoInternal(pragma.DoNotImplement) {} |
| |
| type defaultValue struct { |
| once sync.Once |
| val pref.Value |
| eval pref.EnumValueDescriptor |
| buf []byte |
| } |
| |
| var ( |
| zeroBool = pref.ValueOf(false) |
| zeroInt32 = pref.ValueOf(int32(0)) |
| zeroInt64 = pref.ValueOf(int64(0)) |
| zeroUint32 = pref.ValueOf(uint32(0)) |
| zeroUint64 = pref.ValueOf(uint64(0)) |
| zeroFloat32 = pref.ValueOf(float32(0)) |
| zeroFloat64 = pref.ValueOf(float64(0)) |
| zeroString = pref.ValueOf(string("")) |
| zeroBytes = pref.ValueOf([]byte(nil)) |
| zeroEnum = pref.ValueOf(pref.EnumNumber(0)) |
| ) |
| |
| func (p *defaultValue) lazyInit(t pref.FieldDescriptor, v pref.Value) { |
| p.once.Do(func() { |
| p.val = v |
| if v.IsValid() { |
| switch t.Kind() { |
| case pref.EnumKind: |
| // Treat a string value as an identifier referencing some enum |
| // value by name and extract the enum number. |
| // If this fails, validateMessage will later detect that the |
| // default value for an enum value is the wrong type. |
| switch v := v.Interface().(type) { |
| case string: |
| if ev := t.EnumType().Values().ByName(pref.Name(v)); ev != nil { |
| p.eval = ev |
| p.val = pref.ValueOf(p.eval.Number()) |
| } |
| case pref.EnumNumber: |
| p.eval = t.EnumType().Values().ByNumber(v) |
| } |
| case pref.BytesKind: |
| // Store a copy of the default bytes, so that we can detect |
| // accidental mutations of the original value. |
| if b, ok := v.Interface().([]byte); ok && len(b) > 0 { |
| p.buf = append([]byte(nil), b...) |
| } |
| } |
| return |
| } |
| switch t.Kind() { |
| case pref.BoolKind: |
| p.val = zeroBool |
| case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind: |
| p.val = zeroInt32 |
| case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind: |
| p.val = zeroInt64 |
| case pref.Uint32Kind, pref.Fixed32Kind: |
| p.val = zeroUint32 |
| case pref.Uint64Kind, pref.Fixed64Kind: |
| p.val = zeroUint64 |
| case pref.FloatKind: |
| p.val = zeroFloat32 |
| case pref.DoubleKind: |
| p.val = zeroFloat64 |
| case pref.StringKind: |
| p.val = zeroString |
| case pref.BytesKind: |
| p.val = zeroBytes |
| case pref.EnumKind: |
| p.val = zeroEnum |
| if t.Syntax() == pref.Proto2 { |
| if et := t.EnumType(); et != nil { |
| if vs := et.Values(); vs.Len() > 0 { |
| p.val = pref.ValueOf(vs.Get(0).Number()) |
| } |
| } |
| } |
| } |
| }) |
| if len(p.buf) > 0 && !bytes.Equal(p.buf, p.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 that can be detected by the detector. |
| panic(fmt.Sprintf("proto: detected mutation on the default bytes for %v", t.FullName())) |
| } |
| } |
| |
| func (p *defaultValue) value(t pref.FieldDescriptor, v pref.Value) pref.Value { |
| p.lazyInit(t, v) |
| return p.val |
| } |
| |
| func (p *defaultValue) enum(t pref.FieldDescriptor, v pref.Value) pref.EnumValueDescriptor { |
| p.lazyInit(t, v) |
| return p.eval |
| } |
| |
| // messageReference resolves PlaceholderMessages that reference declarations |
| // within the FileDescriptor tree that parent is a member of. |
| type messageReference struct{ once sync.Once } |
| |
| func (p *messageReference) lazyInit(parent pref.Descriptor, pt *pref.MessageDescriptor) pref.MessageDescriptor { |
| p.once.Do(func() { |
| if t := *pt; t != nil && t.IsPlaceholder() { |
| if d, ok := resolveReference(parent, t.FullName()).(pref.MessageDescriptor); ok { |
| *pt = d |
| } |
| } |
| }) |
| return *pt |
| } |
| |
| // enumReference resolves PlaceholderEnums that reference declarations |
| // within the FileDescriptor tree that parent is a member of. |
| type enumReference struct{ once sync.Once } |
| |
| func (p *enumReference) lazyInit(parent pref.Descriptor, pt *pref.EnumDescriptor) pref.EnumDescriptor { |
| p.once.Do(func() { |
| if t := *pt; t != nil && t.IsPlaceholder() { |
| if d, ok := resolveReference(parent, t.FullName()).(pref.EnumDescriptor); ok { |
| *pt = d |
| } |
| } |
| }) |
| return *pt |
| } |
| |
| // resolveReference searches parent for the MessageDescriptor or EnumDescriptor |
| // declaration identified by refName. This returns nil if not found. |
| func resolveReference(parent pref.Descriptor, refName pref.FullName) pref.Descriptor { |
| // Ascend upwards until a prefix match is found. |
| cur := parent |
| for cur != nil { |
| curName := cur.FullName() |
| if strings.HasPrefix(string(refName), string(curName)) { |
| if len(refName) == len(curName) { |
| refName = refName[len(curName):] |
| break // e.g., refName: foo.firetruck, curName: foo.firetruck |
| } else if refName[len(curName)] == '.' { |
| refName = refName[len(curName)+len("."):] |
| break // e.g., refName: foo.firetruck.driver, curName: foo.firetruck |
| } else if len(curName) == 0 { |
| break // FileDescriptor has no package name |
| } |
| // No match. (e.g., refName: foo.firetruck, curName: foo.fire) |
| } |
| cur, _ = cur.Parent() // nil after ascending above FileDescriptor |
| } |
| |
| // Descend downwards to resolve all relative names. |
| for cur != nil && len(refName) > 0 { |
| var head pref.Name |
| head, refName = pref.Name(refName), "" |
| if i := strings.IndexByte(string(head), '.'); i >= 0 { |
| head, refName = head[:i], pref.FullName(head[i+len("."):]) |
| } |
| |
| // Search the current descriptor for the nested declaration. |
| var next pref.Descriptor |
| if t, ok := cur.(interface { |
| Messages() pref.MessageDescriptors |
| }); ok && next == nil { |
| if d := t.Messages().ByName(head); d != nil { |
| next = d |
| } |
| } |
| if t, ok := cur.(interface { |
| Enums() pref.EnumDescriptors |
| }); ok && next == nil { |
| if d := t.Enums().ByName(head); d != nil { |
| next = d |
| } |
| } |
| cur = next // nil if not found |
| } |
| return cur |
| } |