| // Copyright 2019 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 filedesc |
| |
| import ( |
| "bytes" |
| "fmt" |
| "sync" |
| "sync/atomic" |
| |
| "google.golang.org/protobuf/internal/descfmt" |
| "google.golang.org/protobuf/internal/descopts" |
| "google.golang.org/protobuf/internal/encoding/defval" |
| "google.golang.org/protobuf/internal/pragma" |
| "google.golang.org/protobuf/internal/strs" |
| pref "google.golang.org/protobuf/reflect/protoreflect" |
| "google.golang.org/protobuf/reflect/protoregistry" |
| ) |
| |
| // The types in this file may have a suffix: |
| // • L0: Contains fields common to all descriptors (except File) and |
| // must be initialized up front. |
| // • L1: Contains fields specific to a descriptor and |
| // must be initialized up front. |
| // • L2: Contains fields that are lazily initialized when constructing |
| // from the raw file descriptor. When constructing as a literal, the L2 |
| // fields must be initialized up front. |
| // |
| // The types are exported so that packages like reflect/protodesc can |
| // directly construct descriptors. |
| |
| type ( |
| File struct { |
| fileRaw |
| L1 FileL1 |
| |
| once uint32 // atomically set if L2 is valid |
| mu sync.Mutex // protects L2 |
| L2 *FileL2 |
| } |
| FileL1 struct { |
| Syntax pref.Syntax |
| Path string |
| Package pref.FullName |
| |
| Enums Enums |
| Messages Messages |
| Extensions Extensions |
| Services Services |
| } |
| FileL2 struct { |
| Options func() pref.ProtoMessage |
| Imports FileImports |
| Locations SourceLocations |
| } |
| ) |
| |
| func (fd *File) ParentFile() pref.FileDescriptor { return fd } |
| func (fd *File) Parent() pref.Descriptor { return nil } |
| func (fd *File) Index() int { return 0 } |
| func (fd *File) Syntax() pref.Syntax { return fd.L1.Syntax } |
| func (fd *File) Name() pref.Name { return fd.L1.Package.Name() } |
| func (fd *File) FullName() pref.FullName { return fd.L1.Package } |
| func (fd *File) IsPlaceholder() bool { return false } |
| func (fd *File) Options() pref.ProtoMessage { |
| if f := fd.lazyInit().Options; f != nil { |
| return f() |
| } |
| return descopts.File |
| } |
| func (fd *File) Path() string { return fd.L1.Path } |
| func (fd *File) Package() pref.FullName { return fd.L1.Package } |
| func (fd *File) Imports() pref.FileImports { return &fd.lazyInit().Imports } |
| func (fd *File) Enums() pref.EnumDescriptors { return &fd.L1.Enums } |
| func (fd *File) Messages() pref.MessageDescriptors { return &fd.L1.Messages } |
| func (fd *File) Extensions() pref.ExtensionDescriptors { return &fd.L1.Extensions } |
| func (fd *File) Services() pref.ServiceDescriptors { return &fd.L1.Services } |
| func (fd *File) SourceLocations() pref.SourceLocations { return &fd.L2.Locations } |
| func (fd *File) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) } |
| func (fd *File) ProtoType(pref.FileDescriptor) {} |
| func (fd *File) ProtoInternal(pragma.DoNotImplement) {} |
| |
| func (fd *File) lazyInit() *FileL2 { |
| if atomic.LoadUint32(&fd.once) == 0 { |
| fd.lazyInitOnce() |
| } |
| return fd.L2 |
| } |
| |
| func (fd *File) lazyInitOnce() { |
| fd.mu.Lock() |
| if fd.L2 == nil { |
| fd.lazyRawInit() // recursively initializes all L2 structures |
| } |
| atomic.StoreUint32(&fd.once, 1) |
| fd.mu.Unlock() |
| } |
| |
| // ProtoLegacyRawDesc is a pseudo-internal API for allowing the v1 code |
| // to be able to retrieve the raw descriptor. |
| // |
| // WARNING: This method is exempt from the compatibility promise and may be |
| // removed in the future without warning. |
| func (fd *File) ProtoLegacyRawDesc() []byte { |
| return fd.builder.RawDescriptor |
| } |
| |
| // GoPackagePath is a pseudo-internal API for determining the Go package path |
| // that this file descriptor is declared in. |
| // |
| // WARNING: This method is exempt from the compatibility promise and may be |
| // removed in the future without warning. |
| func (fd *File) GoPackagePath() string { |
| return fd.builder.GoPackagePath |
| } |
| |
| type ( |
| Enum struct { |
| Base |
| L1 EnumL1 |
| L2 *EnumL2 // protected by fileDesc.once |
| } |
| EnumL1 struct { |
| eagerValues bool // controls whether EnumL2.Values is already populated |
| } |
| EnumL2 struct { |
| Options func() pref.ProtoMessage |
| Values EnumValues |
| ReservedNames Names |
| ReservedRanges EnumRanges |
| } |
| |
| EnumValue struct { |
| Base |
| L1 EnumValueL1 |
| } |
| EnumValueL1 struct { |
| Options func() pref.ProtoMessage |
| Number pref.EnumNumber |
| } |
| ) |
| |
| func (ed *Enum) Options() pref.ProtoMessage { |
| if f := ed.lazyInit().Options; f != nil { |
| return f() |
| } |
| return descopts.Enum |
| } |
| func (ed *Enum) Values() pref.EnumValueDescriptors { |
| if ed.L1.eagerValues { |
| return &ed.L2.Values |
| } |
| return &ed.lazyInit().Values |
| } |
| func (ed *Enum) ReservedNames() pref.Names { return &ed.lazyInit().ReservedNames } |
| func (ed *Enum) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().ReservedRanges } |
| func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) } |
| func (ed *Enum) ProtoType(pref.EnumDescriptor) {} |
| func (ed *Enum) lazyInit() *EnumL2 { |
| ed.L0.ParentFile.lazyInit() // implicitly initializes L2 |
| return ed.L2 |
| } |
| |
| func (ed *EnumValue) Options() pref.ProtoMessage { |
| if f := ed.L1.Options; f != nil { |
| return f() |
| } |
| return descopts.EnumValue |
| } |
| func (ed *EnumValue) Number() pref.EnumNumber { return ed.L1.Number } |
| func (ed *EnumValue) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) } |
| func (ed *EnumValue) ProtoType(pref.EnumValueDescriptor) {} |
| |
| type ( |
| Message struct { |
| Base |
| L1 MessageL1 |
| L2 *MessageL2 // protected by fileDesc.once |
| } |
| MessageL1 struct { |
| Enums Enums |
| Messages Messages |
| Extensions Extensions |
| IsMapEntry bool // promoted from google.protobuf.MessageOptions |
| IsMessageSet bool // promoted from google.protobuf.MessageOptions |
| } |
| MessageL2 struct { |
| Options func() pref.ProtoMessage |
| Fields Fields |
| Oneofs Oneofs |
| ReservedNames Names |
| ReservedRanges FieldRanges |
| RequiredNumbers FieldNumbers // must be consistent with Fields.Cardinality |
| ExtensionRanges FieldRanges |
| ExtensionRangeOptions []func() pref.ProtoMessage // must be same length as ExtensionRanges |
| } |
| |
| Field struct { |
| Base |
| L1 FieldL1 |
| } |
| FieldL1 struct { |
| Options func() pref.ProtoMessage |
| Number pref.FieldNumber |
| Cardinality pref.Cardinality // must be consistent with Message.RequiredNumbers |
| Kind pref.Kind |
| JSONName jsonName |
| IsWeak bool // promoted from google.protobuf.FieldOptions |
| HasPacked bool // promoted from google.protobuf.FieldOptions |
| IsPacked bool // promoted from google.protobuf.FieldOptions |
| HasEnforceUTF8 bool // promoted from google.protobuf.FieldOptions |
| EnforceUTF8 bool // promoted from google.protobuf.FieldOptions |
| Default defaultValue |
| ContainingOneof pref.OneofDescriptor // must be consistent with Message.Oneofs.Fields |
| Enum pref.EnumDescriptor |
| Message pref.MessageDescriptor |
| } |
| |
| Oneof struct { |
| Base |
| L1 OneofL1 |
| } |
| OneofL1 struct { |
| Options func() pref.ProtoMessage |
| Fields OneofFields // must be consistent with Message.Fields.ContainingOneof |
| } |
| ) |
| |
| func (md *Message) Options() pref.ProtoMessage { |
| if f := md.lazyInit().Options; f != nil { |
| return f() |
| } |
| return descopts.Message |
| } |
| func (md *Message) IsMapEntry() bool { return md.L1.IsMapEntry } |
| func (md *Message) Fields() pref.FieldDescriptors { return &md.lazyInit().Fields } |
| func (md *Message) Oneofs() pref.OneofDescriptors { return &md.lazyInit().Oneofs } |
| func (md *Message) ReservedNames() pref.Names { return &md.lazyInit().ReservedNames } |
| func (md *Message) ReservedRanges() pref.FieldRanges { return &md.lazyInit().ReservedRanges } |
| func (md *Message) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().RequiredNumbers } |
| func (md *Message) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().ExtensionRanges } |
| func (md *Message) ExtensionRangeOptions(i int) pref.ProtoMessage { |
| if f := md.lazyInit().ExtensionRangeOptions[i]; f != nil { |
| return f() |
| } |
| return descopts.ExtensionRange |
| } |
| func (md *Message) Enums() pref.EnumDescriptors { return &md.L1.Enums } |
| func (md *Message) Messages() pref.MessageDescriptors { return &md.L1.Messages } |
| func (md *Message) Extensions() pref.ExtensionDescriptors { return &md.L1.Extensions } |
| func (md *Message) ProtoType(pref.MessageDescriptor) {} |
| func (md *Message) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) } |
| func (md *Message) lazyInit() *MessageL2 { |
| md.L0.ParentFile.lazyInit() // implicitly initializes L2 |
| return md.L2 |
| } |
| |
| // IsMessageSet is a pseudo-internal API for checking whether a message |
| // should serialize in the proto1 message format. |
| // |
| // WARNING: This method is exempt from the compatibility promise and may be |
| // removed in the future without warning. |
| func (md *Message) IsMessageSet() bool { |
| return md.L1.IsMessageSet |
| } |
| |
| func (fd *Field) Options() pref.ProtoMessage { |
| if f := fd.L1.Options; f != nil { |
| return f() |
| } |
| return descopts.Field |
| } |
| func (fd *Field) Number() pref.FieldNumber { return fd.L1.Number } |
| func (fd *Field) Cardinality() pref.Cardinality { return fd.L1.Cardinality } |
| func (fd *Field) Kind() pref.Kind { return fd.L1.Kind } |
| func (fd *Field) HasJSONName() bool { return fd.L1.JSONName.has } |
| func (fd *Field) JSONName() string { return fd.L1.JSONName.get(fd) } |
| func (fd *Field) IsPacked() bool { |
| if !fd.L1.HasPacked && fd.L0.ParentFile.L1.Syntax != pref.Proto2 && fd.L1.Cardinality == pref.Repeated { |
| switch fd.L1.Kind { |
| case pref.StringKind, pref.BytesKind, pref.MessageKind, pref.GroupKind: |
| default: |
| return true |
| } |
| } |
| return fd.L1.IsPacked |
| } |
| func (fd *Field) IsExtension() bool { return false } |
| func (fd *Field) IsWeak() bool { return fd.L1.IsWeak } |
| func (fd *Field) IsList() bool { return fd.Cardinality() == pref.Repeated && !fd.IsMap() } |
| func (fd *Field) IsMap() bool { return fd.Message() != nil && fd.Message().IsMapEntry() } |
| func (fd *Field) MapKey() pref.FieldDescriptor { |
| if !fd.IsMap() { |
| return nil |
| } |
| return fd.Message().Fields().ByNumber(1) |
| } |
| func (fd *Field) MapValue() pref.FieldDescriptor { |
| if !fd.IsMap() { |
| return nil |
| } |
| return fd.Message().Fields().ByNumber(2) |
| } |
| func (fd *Field) HasDefault() bool { return fd.L1.Default.has } |
| func (fd *Field) Default() pref.Value { return fd.L1.Default.get(fd) } |
| func (fd *Field) DefaultEnumValue() pref.EnumValueDescriptor { return fd.L1.Default.enum } |
| func (fd *Field) ContainingOneof() pref.OneofDescriptor { return fd.L1.ContainingOneof } |
| func (fd *Field) ContainingMessage() pref.MessageDescriptor { |
| return fd.L0.Parent.(pref.MessageDescriptor) |
| } |
| func (fd *Field) Enum() pref.EnumDescriptor { |
| return fd.L1.Enum |
| } |
| func (fd *Field) Message() pref.MessageDescriptor { |
| if fd.L1.IsWeak { |
| if d, _ := protoregistry.GlobalFiles.FindDescriptorByName(fd.L1.Message.FullName()); d != nil { |
| return d.(pref.MessageDescriptor) |
| } |
| } |
| return fd.L1.Message |
| } |
| func (fd *Field) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) } |
| func (fd *Field) ProtoType(pref.FieldDescriptor) {} |
| |
| // EnforceUTF8 is a pseudo-internal API to determine whether to enforce UTF-8 |
| // validation for the string field. This exists for Google-internal use only |
| // since proto3 did not enforce UTF-8 validity prior to the open-source release. |
| // If this method does not exist, the default is to enforce valid UTF-8. |
| // |
| // WARNING: This method is exempt from the compatibility promise and may be |
| // removed in the future without warning. |
| func (fd *Field) EnforceUTF8() bool { |
| if fd.L1.HasEnforceUTF8 { |
| return fd.L1.EnforceUTF8 |
| } |
| return fd.L0.ParentFile.L1.Syntax == pref.Proto3 |
| } |
| |
| func (od *Oneof) Options() pref.ProtoMessage { |
| if f := od.L1.Options; f != nil { |
| return f() |
| } |
| return descopts.Oneof |
| } |
| func (od *Oneof) Fields() pref.FieldDescriptors { return &od.L1.Fields } |
| func (od *Oneof) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, od) } |
| func (od *Oneof) ProtoType(pref.OneofDescriptor) {} |
| |
| type ( |
| Extension struct { |
| Base |
| L1 ExtensionL1 |
| L2 *ExtensionL2 // protected by fileDesc.once |
| } |
| ExtensionL1 struct { |
| Number pref.FieldNumber |
| Extendee pref.MessageDescriptor |
| Cardinality pref.Cardinality |
| Kind pref.Kind |
| } |
| ExtensionL2 struct { |
| Options func() pref.ProtoMessage |
| JSONName jsonName |
| IsPacked bool // promoted from google.protobuf.FieldOptions |
| Default defaultValue |
| Enum pref.EnumDescriptor |
| Message pref.MessageDescriptor |
| } |
| ) |
| |
| func (xd *Extension) Options() pref.ProtoMessage { |
| if f := xd.lazyInit().Options; f != nil { |
| return f() |
| } |
| return descopts.Field |
| } |
| func (xd *Extension) Number() pref.FieldNumber { return xd.L1.Number } |
| func (xd *Extension) Cardinality() pref.Cardinality { return xd.L1.Cardinality } |
| func (xd *Extension) Kind() pref.Kind { return xd.L1.Kind } |
| func (xd *Extension) HasJSONName() bool { return xd.lazyInit().JSONName.has } |
| func (xd *Extension) JSONName() string { return xd.lazyInit().JSONName.get(xd) } |
| func (xd *Extension) IsPacked() bool { return xd.lazyInit().IsPacked } |
| func (xd *Extension) IsExtension() bool { return true } |
| func (xd *Extension) IsWeak() bool { return false } |
| func (xd *Extension) IsList() bool { return xd.Cardinality() == pref.Repeated } |
| func (xd *Extension) IsMap() bool { return false } |
| func (xd *Extension) MapKey() pref.FieldDescriptor { return nil } |
| func (xd *Extension) MapValue() pref.FieldDescriptor { return nil } |
| func (xd *Extension) HasDefault() bool { return xd.lazyInit().Default.has } |
| func (xd *Extension) Default() pref.Value { return xd.lazyInit().Default.get(xd) } |
| func (xd *Extension) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().Default.enum } |
| func (xd *Extension) ContainingOneof() pref.OneofDescriptor { return nil } |
| func (xd *Extension) ContainingMessage() pref.MessageDescriptor { return xd.L1.Extendee } |
| func (xd *Extension) Enum() pref.EnumDescriptor { return xd.lazyInit().Enum } |
| func (xd *Extension) Message() pref.MessageDescriptor { return xd.lazyInit().Message } |
| func (xd *Extension) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, xd) } |
| func (xd *Extension) ProtoType(pref.FieldDescriptor) {} |
| func (xd *Extension) ProtoInternal(pragma.DoNotImplement) {} |
| func (xd *Extension) lazyInit() *ExtensionL2 { |
| xd.L0.ParentFile.lazyInit() // implicitly initializes L2 |
| return xd.L2 |
| } |
| |
| type ( |
| Service struct { |
| Base |
| L1 ServiceL1 |
| L2 *ServiceL2 // protected by fileDesc.once |
| } |
| ServiceL1 struct{} |
| ServiceL2 struct { |
| Options func() pref.ProtoMessage |
| Methods Methods |
| } |
| |
| Method struct { |
| Base |
| L1 MethodL1 |
| } |
| MethodL1 struct { |
| Options func() pref.ProtoMessage |
| Input pref.MessageDescriptor |
| Output pref.MessageDescriptor |
| IsStreamingClient bool |
| IsStreamingServer bool |
| } |
| ) |
| |
| func (sd *Service) Options() pref.ProtoMessage { |
| if f := sd.lazyInit().Options; f != nil { |
| return f() |
| } |
| return descopts.Service |
| } |
| func (sd *Service) Methods() pref.MethodDescriptors { return &sd.lazyInit().Methods } |
| func (sd *Service) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, sd) } |
| func (sd *Service) ProtoType(pref.ServiceDescriptor) {} |
| func (sd *Service) ProtoInternal(pragma.DoNotImplement) {} |
| func (sd *Service) lazyInit() *ServiceL2 { |
| sd.L0.ParentFile.lazyInit() // implicitly initializes L2 |
| return sd.L2 |
| } |
| |
| func (md *Method) Options() pref.ProtoMessage { |
| if f := md.L1.Options; f != nil { |
| return f() |
| } |
| return descopts.Method |
| } |
| func (md *Method) Input() pref.MessageDescriptor { return md.L1.Input } |
| func (md *Method) Output() pref.MessageDescriptor { return md.L1.Output } |
| func (md *Method) IsStreamingClient() bool { return md.L1.IsStreamingClient } |
| func (md *Method) IsStreamingServer() bool { return md.L1.IsStreamingServer } |
| func (md *Method) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) } |
| func (md *Method) ProtoType(pref.MethodDescriptor) {} |
| func (md *Method) ProtoInternal(pragma.DoNotImplement) {} |
| |
| // Surrogate files are can be used to create standalone descriptors |
| // where the syntax is only information derived from the parent file. |
| var ( |
| SurrogateProto2 = &File{L1: FileL1{Syntax: pref.Proto2}, L2: &FileL2{}} |
| SurrogateProto3 = &File{L1: FileL1{Syntax: pref.Proto3}, L2: &FileL2{}} |
| ) |
| |
| type ( |
| Base struct { |
| L0 BaseL0 |
| } |
| BaseL0 struct { |
| FullName pref.FullName // must be populated |
| ParentFile *File // must be populated |
| Parent pref.Descriptor |
| Index int |
| } |
| ) |
| |
| func (d *Base) Name() pref.Name { return d.L0.FullName.Name() } |
| func (d *Base) FullName() pref.FullName { return d.L0.FullName } |
| func (d *Base) ParentFile() pref.FileDescriptor { |
| if d.L0.ParentFile == SurrogateProto2 || d.L0.ParentFile == SurrogateProto3 { |
| return nil // surrogate files are not real parents |
| } |
| return d.L0.ParentFile |
| } |
| func (d *Base) Parent() pref.Descriptor { return d.L0.Parent } |
| func (d *Base) Index() int { return d.L0.Index } |
| func (d *Base) Syntax() pref.Syntax { return d.L0.ParentFile.Syntax() } |
| func (d *Base) IsPlaceholder() bool { return false } |
| func (d *Base) ProtoInternal(pragma.DoNotImplement) {} |
| |
| type jsonName struct { |
| has bool |
| once sync.Once |
| name string |
| } |
| |
| // Init initializes the name. It is exported for use by other internal packages. |
| func (js *jsonName) Init(s string) { |
| js.has = true |
| js.name = s |
| } |
| |
| func (js *jsonName) get(fd pref.FieldDescriptor) string { |
| if !js.has { |
| js.once.Do(func() { |
| js.name = strs.JSONCamelCase(string(fd.Name())) |
| }) |
| } |
| return js.name |
| } |
| |
| func DefaultValue(v pref.Value, ev pref.EnumValueDescriptor) defaultValue { |
| dv := defaultValue{has: v.IsValid(), val: v, enum: ev} |
| if b, ok := v.Interface().([]byte); ok { |
| // Store a copy of the default bytes, so that we can detect |
| // accidental mutations of the original value. |
| dv.bytes = append([]byte(nil), b...) |
| } |
| return dv |
| } |
| |
| func unmarshalDefault(b []byte, k pref.Kind, pf *File, ed pref.EnumDescriptor) defaultValue { |
| var evs pref.EnumValueDescriptors |
| if k == pref.EnumKind { |
| // If the enum is declared within the same file, be careful not to |
| // blindly call the Values method, lest we bind ourselves in a deadlock. |
| if e, ok := ed.(*Enum); ok && e.L0.ParentFile == pf { |
| evs = &e.L2.Values |
| } else { |
| evs = ed.Values() |
| } |
| |
| // If we are unable to resolve the enum dependency, use a placeholder |
| // enum value since we will not be able to parse the default value. |
| if ed.IsPlaceholder() && pref.Name(b).IsValid() { |
| v := pref.ValueOfEnum(0) |
| ev := PlaceholderEnumValue(ed.FullName().Parent().Append(pref.Name(b))) |
| return DefaultValue(v, ev) |
| } |
| } |
| |
| v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor) |
| if err != nil { |
| panic(err) |
| } |
| return DefaultValue(v, ev) |
| } |
| |
| type defaultValue struct { |
| has bool |
| val pref.Value |
| enum pref.EnumValueDescriptor |
| bytes []byte |
| } |
| |
| func (dv *defaultValue) get(fd pref.FieldDescriptor) pref.Value { |
| // Return the zero value as the default if unpopulated. |
| if !dv.has { |
| if fd.Cardinality() == pref.Repeated { |
| return pref.Value{} |
| } |
| switch fd.Kind() { |
| case pref.BoolKind: |
| return pref.ValueOfBool(false) |
| case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind: |
| return pref.ValueOfInt32(0) |
| case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind: |
| return pref.ValueOfInt64(0) |
| case pref.Uint32Kind, pref.Fixed32Kind: |
| return pref.ValueOfUint32(0) |
| case pref.Uint64Kind, pref.Fixed64Kind: |
| return pref.ValueOfUint64(0) |
| case pref.FloatKind: |
| return pref.ValueOfFloat32(0) |
| case pref.DoubleKind: |
| return pref.ValueOfFloat64(0) |
| case pref.StringKind: |
| return pref.ValueOfString("") |
| case pref.BytesKind: |
| return pref.ValueOfBytes(nil) |
| case pref.EnumKind: |
| if evs := fd.Enum().Values(); evs.Len() > 0 { |
| return pref.ValueOfEnum(evs.Get(0).Number()) |
| } |
| return pref.ValueOfEnum(0) |
| } |
| } |
| |
| if len(dv.bytes) > 0 && !bytes.Equal(dv.bytes, 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") |
| } |
| return dv.val |
| } |