1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package filedesc 6 7import ( 8 "bytes" 9 "fmt" 10 "sync" 11 "sync/atomic" 12 13 "google.golang.org/protobuf/internal/descfmt" 14 "google.golang.org/protobuf/internal/descopts" 15 "google.golang.org/protobuf/internal/encoding/defval" 16 "google.golang.org/protobuf/internal/encoding/messageset" 17 "google.golang.org/protobuf/internal/genid" 18 "google.golang.org/protobuf/internal/pragma" 19 "google.golang.org/protobuf/internal/strs" 20 pref "google.golang.org/protobuf/reflect/protoreflect" 21 "google.golang.org/protobuf/reflect/protoregistry" 22) 23 24// The types in this file may have a suffix: 25// • L0: Contains fields common to all descriptors (except File) and 26// must be initialized up front. 27// • L1: Contains fields specific to a descriptor and 28// must be initialized up front. 29// • L2: Contains fields that are lazily initialized when constructing 30// from the raw file descriptor. When constructing as a literal, the L2 31// fields must be initialized up front. 32// 33// The types are exported so that packages like reflect/protodesc can 34// directly construct descriptors. 35 36type ( 37 File struct { 38 fileRaw 39 L1 FileL1 40 41 once uint32 // atomically set if L2 is valid 42 mu sync.Mutex // protects L2 43 L2 *FileL2 44 } 45 FileL1 struct { 46 Syntax pref.Syntax 47 Path string 48 Package pref.FullName 49 50 Enums Enums 51 Messages Messages 52 Extensions Extensions 53 Services Services 54 } 55 FileL2 struct { 56 Options func() pref.ProtoMessage 57 Imports FileImports 58 Locations SourceLocations 59 } 60) 61 62func (fd *File) ParentFile() pref.FileDescriptor { return fd } 63func (fd *File) Parent() pref.Descriptor { return nil } 64func (fd *File) Index() int { return 0 } 65func (fd *File) Syntax() pref.Syntax { return fd.L1.Syntax } 66func (fd *File) Name() pref.Name { return fd.L1.Package.Name() } 67func (fd *File) FullName() pref.FullName { return fd.L1.Package } 68func (fd *File) IsPlaceholder() bool { return false } 69func (fd *File) Options() pref.ProtoMessage { 70 if f := fd.lazyInit().Options; f != nil { 71 return f() 72 } 73 return descopts.File 74} 75func (fd *File) Path() string { return fd.L1.Path } 76func (fd *File) Package() pref.FullName { return fd.L1.Package } 77func (fd *File) Imports() pref.FileImports { return &fd.lazyInit().Imports } 78func (fd *File) Enums() pref.EnumDescriptors { return &fd.L1.Enums } 79func (fd *File) Messages() pref.MessageDescriptors { return &fd.L1.Messages } 80func (fd *File) Extensions() pref.ExtensionDescriptors { return &fd.L1.Extensions } 81func (fd *File) Services() pref.ServiceDescriptors { return &fd.L1.Services } 82func (fd *File) SourceLocations() pref.SourceLocations { return &fd.lazyInit().Locations } 83func (fd *File) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) } 84func (fd *File) ProtoType(pref.FileDescriptor) {} 85func (fd *File) ProtoInternal(pragma.DoNotImplement) {} 86 87func (fd *File) lazyInit() *FileL2 { 88 if atomic.LoadUint32(&fd.once) == 0 { 89 fd.lazyInitOnce() 90 } 91 return fd.L2 92} 93 94func (fd *File) lazyInitOnce() { 95 fd.mu.Lock() 96 if fd.L2 == nil { 97 fd.lazyRawInit() // recursively initializes all L2 structures 98 } 99 atomic.StoreUint32(&fd.once, 1) 100 fd.mu.Unlock() 101} 102 103// GoPackagePath is a pseudo-internal API for determining the Go package path 104// that this file descriptor is declared in. 105// 106// WARNING: This method is exempt from the compatibility promise and may be 107// removed in the future without warning. 108func (fd *File) GoPackagePath() string { 109 return fd.builder.GoPackagePath 110} 111 112type ( 113 Enum struct { 114 Base 115 L1 EnumL1 116 L2 *EnumL2 // protected by fileDesc.once 117 } 118 EnumL1 struct { 119 eagerValues bool // controls whether EnumL2.Values is already populated 120 } 121 EnumL2 struct { 122 Options func() pref.ProtoMessage 123 Values EnumValues 124 ReservedNames Names 125 ReservedRanges EnumRanges 126 } 127 128 EnumValue struct { 129 Base 130 L1 EnumValueL1 131 } 132 EnumValueL1 struct { 133 Options func() pref.ProtoMessage 134 Number pref.EnumNumber 135 } 136) 137 138func (ed *Enum) Options() pref.ProtoMessage { 139 if f := ed.lazyInit().Options; f != nil { 140 return f() 141 } 142 return descopts.Enum 143} 144func (ed *Enum) Values() pref.EnumValueDescriptors { 145 if ed.L1.eagerValues { 146 return &ed.L2.Values 147 } 148 return &ed.lazyInit().Values 149} 150func (ed *Enum) ReservedNames() pref.Names { return &ed.lazyInit().ReservedNames } 151func (ed *Enum) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().ReservedRanges } 152func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) } 153func (ed *Enum) ProtoType(pref.EnumDescriptor) {} 154func (ed *Enum) lazyInit() *EnumL2 { 155 ed.L0.ParentFile.lazyInit() // implicitly initializes L2 156 return ed.L2 157} 158 159func (ed *EnumValue) Options() pref.ProtoMessage { 160 if f := ed.L1.Options; f != nil { 161 return f() 162 } 163 return descopts.EnumValue 164} 165func (ed *EnumValue) Number() pref.EnumNumber { return ed.L1.Number } 166func (ed *EnumValue) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) } 167func (ed *EnumValue) ProtoType(pref.EnumValueDescriptor) {} 168 169type ( 170 Message struct { 171 Base 172 L1 MessageL1 173 L2 *MessageL2 // protected by fileDesc.once 174 } 175 MessageL1 struct { 176 Enums Enums 177 Messages Messages 178 Extensions Extensions 179 IsMapEntry bool // promoted from google.protobuf.MessageOptions 180 IsMessageSet bool // promoted from google.protobuf.MessageOptions 181 } 182 MessageL2 struct { 183 Options func() pref.ProtoMessage 184 Fields Fields 185 Oneofs Oneofs 186 ReservedNames Names 187 ReservedRanges FieldRanges 188 RequiredNumbers FieldNumbers // must be consistent with Fields.Cardinality 189 ExtensionRanges FieldRanges 190 ExtensionRangeOptions []func() pref.ProtoMessage // must be same length as ExtensionRanges 191 } 192 193 Field struct { 194 Base 195 L1 FieldL1 196 } 197 FieldL1 struct { 198 Options func() pref.ProtoMessage 199 Number pref.FieldNumber 200 Cardinality pref.Cardinality // must be consistent with Message.RequiredNumbers 201 Kind pref.Kind 202 StringName stringName 203 IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto 204 IsWeak bool // promoted from google.protobuf.FieldOptions 205 HasPacked bool // promoted from google.protobuf.FieldOptions 206 IsPacked bool // promoted from google.protobuf.FieldOptions 207 HasEnforceUTF8 bool // promoted from google.protobuf.FieldOptions 208 EnforceUTF8 bool // promoted from google.protobuf.FieldOptions 209 Default defaultValue 210 ContainingOneof pref.OneofDescriptor // must be consistent with Message.Oneofs.Fields 211 Enum pref.EnumDescriptor 212 Message pref.MessageDescriptor 213 } 214 215 Oneof struct { 216 Base 217 L1 OneofL1 218 } 219 OneofL1 struct { 220 Options func() pref.ProtoMessage 221 Fields OneofFields // must be consistent with Message.Fields.ContainingOneof 222 } 223) 224 225func (md *Message) Options() pref.ProtoMessage { 226 if f := md.lazyInit().Options; f != nil { 227 return f() 228 } 229 return descopts.Message 230} 231func (md *Message) IsMapEntry() bool { return md.L1.IsMapEntry } 232func (md *Message) Fields() pref.FieldDescriptors { return &md.lazyInit().Fields } 233func (md *Message) Oneofs() pref.OneofDescriptors { return &md.lazyInit().Oneofs } 234func (md *Message) ReservedNames() pref.Names { return &md.lazyInit().ReservedNames } 235func (md *Message) ReservedRanges() pref.FieldRanges { return &md.lazyInit().ReservedRanges } 236func (md *Message) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().RequiredNumbers } 237func (md *Message) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().ExtensionRanges } 238func (md *Message) ExtensionRangeOptions(i int) pref.ProtoMessage { 239 if f := md.lazyInit().ExtensionRangeOptions[i]; f != nil { 240 return f() 241 } 242 return descopts.ExtensionRange 243} 244func (md *Message) Enums() pref.EnumDescriptors { return &md.L1.Enums } 245func (md *Message) Messages() pref.MessageDescriptors { return &md.L1.Messages } 246func (md *Message) Extensions() pref.ExtensionDescriptors { return &md.L1.Extensions } 247func (md *Message) ProtoType(pref.MessageDescriptor) {} 248func (md *Message) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) } 249func (md *Message) lazyInit() *MessageL2 { 250 md.L0.ParentFile.lazyInit() // implicitly initializes L2 251 return md.L2 252} 253 254// IsMessageSet is a pseudo-internal API for checking whether a message 255// should serialize in the proto1 message format. 256// 257// WARNING: This method is exempt from the compatibility promise and may be 258// removed in the future without warning. 259func (md *Message) IsMessageSet() bool { 260 return md.L1.IsMessageSet 261} 262 263func (fd *Field) Options() pref.ProtoMessage { 264 if f := fd.L1.Options; f != nil { 265 return f() 266 } 267 return descopts.Field 268} 269func (fd *Field) Number() pref.FieldNumber { return fd.L1.Number } 270func (fd *Field) Cardinality() pref.Cardinality { return fd.L1.Cardinality } 271func (fd *Field) Kind() pref.Kind { return fd.L1.Kind } 272func (fd *Field) HasJSONName() bool { return fd.L1.StringName.hasJSON } 273func (fd *Field) JSONName() string { return fd.L1.StringName.getJSON(fd) } 274func (fd *Field) TextName() string { return fd.L1.StringName.getText(fd) } 275func (fd *Field) HasPresence() bool { 276 return fd.L1.Cardinality != pref.Repeated && (fd.L0.ParentFile.L1.Syntax == pref.Proto2 || fd.L1.Message != nil || fd.L1.ContainingOneof != nil) 277} 278func (fd *Field) HasOptionalKeyword() bool { 279 return (fd.L0.ParentFile.L1.Syntax == pref.Proto2 && fd.L1.Cardinality == pref.Optional && fd.L1.ContainingOneof == nil) || fd.L1.IsProto3Optional 280} 281func (fd *Field) IsPacked() bool { 282 if !fd.L1.HasPacked && fd.L0.ParentFile.L1.Syntax != pref.Proto2 && fd.L1.Cardinality == pref.Repeated { 283 switch fd.L1.Kind { 284 case pref.StringKind, pref.BytesKind, pref.MessageKind, pref.GroupKind: 285 default: 286 return true 287 } 288 } 289 return fd.L1.IsPacked 290} 291func (fd *Field) IsExtension() bool { return false } 292func (fd *Field) IsWeak() bool { return fd.L1.IsWeak } 293func (fd *Field) IsList() bool { return fd.Cardinality() == pref.Repeated && !fd.IsMap() } 294func (fd *Field) IsMap() bool { return fd.Message() != nil && fd.Message().IsMapEntry() } 295func (fd *Field) MapKey() pref.FieldDescriptor { 296 if !fd.IsMap() { 297 return nil 298 } 299 return fd.Message().Fields().ByNumber(genid.MapEntry_Key_field_number) 300} 301func (fd *Field) MapValue() pref.FieldDescriptor { 302 if !fd.IsMap() { 303 return nil 304 } 305 return fd.Message().Fields().ByNumber(genid.MapEntry_Value_field_number) 306} 307func (fd *Field) HasDefault() bool { return fd.L1.Default.has } 308func (fd *Field) Default() pref.Value { return fd.L1.Default.get(fd) } 309func (fd *Field) DefaultEnumValue() pref.EnumValueDescriptor { return fd.L1.Default.enum } 310func (fd *Field) ContainingOneof() pref.OneofDescriptor { return fd.L1.ContainingOneof } 311func (fd *Field) ContainingMessage() pref.MessageDescriptor { 312 return fd.L0.Parent.(pref.MessageDescriptor) 313} 314func (fd *Field) Enum() pref.EnumDescriptor { 315 return fd.L1.Enum 316} 317func (fd *Field) Message() pref.MessageDescriptor { 318 if fd.L1.IsWeak { 319 if d, _ := protoregistry.GlobalFiles.FindDescriptorByName(fd.L1.Message.FullName()); d != nil { 320 return d.(pref.MessageDescriptor) 321 } 322 } 323 return fd.L1.Message 324} 325func (fd *Field) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) } 326func (fd *Field) ProtoType(pref.FieldDescriptor) {} 327 328// EnforceUTF8 is a pseudo-internal API to determine whether to enforce UTF-8 329// validation for the string field. This exists for Google-internal use only 330// since proto3 did not enforce UTF-8 validity prior to the open-source release. 331// If this method does not exist, the default is to enforce valid UTF-8. 332// 333// WARNING: This method is exempt from the compatibility promise and may be 334// removed in the future without warning. 335func (fd *Field) EnforceUTF8() bool { 336 if fd.L1.HasEnforceUTF8 { 337 return fd.L1.EnforceUTF8 338 } 339 return fd.L0.ParentFile.L1.Syntax == pref.Proto3 340} 341 342func (od *Oneof) IsSynthetic() bool { 343 return od.L0.ParentFile.L1.Syntax == pref.Proto3 && len(od.L1.Fields.List) == 1 && od.L1.Fields.List[0].HasOptionalKeyword() 344} 345func (od *Oneof) Options() pref.ProtoMessage { 346 if f := od.L1.Options; f != nil { 347 return f() 348 } 349 return descopts.Oneof 350} 351func (od *Oneof) Fields() pref.FieldDescriptors { return &od.L1.Fields } 352func (od *Oneof) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, od) } 353func (od *Oneof) ProtoType(pref.OneofDescriptor) {} 354 355type ( 356 Extension struct { 357 Base 358 L1 ExtensionL1 359 L2 *ExtensionL2 // protected by fileDesc.once 360 } 361 ExtensionL1 struct { 362 Number pref.FieldNumber 363 Extendee pref.MessageDescriptor 364 Cardinality pref.Cardinality 365 Kind pref.Kind 366 } 367 ExtensionL2 struct { 368 Options func() pref.ProtoMessage 369 StringName stringName 370 IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto 371 IsPacked bool // promoted from google.protobuf.FieldOptions 372 Default defaultValue 373 Enum pref.EnumDescriptor 374 Message pref.MessageDescriptor 375 } 376) 377 378func (xd *Extension) Options() pref.ProtoMessage { 379 if f := xd.lazyInit().Options; f != nil { 380 return f() 381 } 382 return descopts.Field 383} 384func (xd *Extension) Number() pref.FieldNumber { return xd.L1.Number } 385func (xd *Extension) Cardinality() pref.Cardinality { return xd.L1.Cardinality } 386func (xd *Extension) Kind() pref.Kind { return xd.L1.Kind } 387func (xd *Extension) HasJSONName() bool { return xd.lazyInit().StringName.hasJSON } 388func (xd *Extension) JSONName() string { return xd.lazyInit().StringName.getJSON(xd) } 389func (xd *Extension) TextName() string { return xd.lazyInit().StringName.getText(xd) } 390func (xd *Extension) HasPresence() bool { return xd.L1.Cardinality != pref.Repeated } 391func (xd *Extension) HasOptionalKeyword() bool { 392 return (xd.L0.ParentFile.L1.Syntax == pref.Proto2 && xd.L1.Cardinality == pref.Optional) || xd.lazyInit().IsProto3Optional 393} 394func (xd *Extension) IsPacked() bool { return xd.lazyInit().IsPacked } 395func (xd *Extension) IsExtension() bool { return true } 396func (xd *Extension) IsWeak() bool { return false } 397func (xd *Extension) IsList() bool { return xd.Cardinality() == pref.Repeated } 398func (xd *Extension) IsMap() bool { return false } 399func (xd *Extension) MapKey() pref.FieldDescriptor { return nil } 400func (xd *Extension) MapValue() pref.FieldDescriptor { return nil } 401func (xd *Extension) HasDefault() bool { return xd.lazyInit().Default.has } 402func (xd *Extension) Default() pref.Value { return xd.lazyInit().Default.get(xd) } 403func (xd *Extension) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().Default.enum } 404func (xd *Extension) ContainingOneof() pref.OneofDescriptor { return nil } 405func (xd *Extension) ContainingMessage() pref.MessageDescriptor { return xd.L1.Extendee } 406func (xd *Extension) Enum() pref.EnumDescriptor { return xd.lazyInit().Enum } 407func (xd *Extension) Message() pref.MessageDescriptor { return xd.lazyInit().Message } 408func (xd *Extension) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, xd) } 409func (xd *Extension) ProtoType(pref.FieldDescriptor) {} 410func (xd *Extension) ProtoInternal(pragma.DoNotImplement) {} 411func (xd *Extension) lazyInit() *ExtensionL2 { 412 xd.L0.ParentFile.lazyInit() // implicitly initializes L2 413 return xd.L2 414} 415 416type ( 417 Service struct { 418 Base 419 L1 ServiceL1 420 L2 *ServiceL2 // protected by fileDesc.once 421 } 422 ServiceL1 struct{} 423 ServiceL2 struct { 424 Options func() pref.ProtoMessage 425 Methods Methods 426 } 427 428 Method struct { 429 Base 430 L1 MethodL1 431 } 432 MethodL1 struct { 433 Options func() pref.ProtoMessage 434 Input pref.MessageDescriptor 435 Output pref.MessageDescriptor 436 IsStreamingClient bool 437 IsStreamingServer bool 438 } 439) 440 441func (sd *Service) Options() pref.ProtoMessage { 442 if f := sd.lazyInit().Options; f != nil { 443 return f() 444 } 445 return descopts.Service 446} 447func (sd *Service) Methods() pref.MethodDescriptors { return &sd.lazyInit().Methods } 448func (sd *Service) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, sd) } 449func (sd *Service) ProtoType(pref.ServiceDescriptor) {} 450func (sd *Service) ProtoInternal(pragma.DoNotImplement) {} 451func (sd *Service) lazyInit() *ServiceL2 { 452 sd.L0.ParentFile.lazyInit() // implicitly initializes L2 453 return sd.L2 454} 455 456func (md *Method) Options() pref.ProtoMessage { 457 if f := md.L1.Options; f != nil { 458 return f() 459 } 460 return descopts.Method 461} 462func (md *Method) Input() pref.MessageDescriptor { return md.L1.Input } 463func (md *Method) Output() pref.MessageDescriptor { return md.L1.Output } 464func (md *Method) IsStreamingClient() bool { return md.L1.IsStreamingClient } 465func (md *Method) IsStreamingServer() bool { return md.L1.IsStreamingServer } 466func (md *Method) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) } 467func (md *Method) ProtoType(pref.MethodDescriptor) {} 468func (md *Method) ProtoInternal(pragma.DoNotImplement) {} 469 470// Surrogate files are can be used to create standalone descriptors 471// where the syntax is only information derived from the parent file. 472var ( 473 SurrogateProto2 = &File{L1: FileL1{Syntax: pref.Proto2}, L2: &FileL2{}} 474 SurrogateProto3 = &File{L1: FileL1{Syntax: pref.Proto3}, L2: &FileL2{}} 475) 476 477type ( 478 Base struct { 479 L0 BaseL0 480 } 481 BaseL0 struct { 482 FullName pref.FullName // must be populated 483 ParentFile *File // must be populated 484 Parent pref.Descriptor 485 Index int 486 } 487) 488 489func (d *Base) Name() pref.Name { return d.L0.FullName.Name() } 490func (d *Base) FullName() pref.FullName { return d.L0.FullName } 491func (d *Base) ParentFile() pref.FileDescriptor { 492 if d.L0.ParentFile == SurrogateProto2 || d.L0.ParentFile == SurrogateProto3 { 493 return nil // surrogate files are not real parents 494 } 495 return d.L0.ParentFile 496} 497func (d *Base) Parent() pref.Descriptor { return d.L0.Parent } 498func (d *Base) Index() int { return d.L0.Index } 499func (d *Base) Syntax() pref.Syntax { return d.L0.ParentFile.Syntax() } 500func (d *Base) IsPlaceholder() bool { return false } 501func (d *Base) ProtoInternal(pragma.DoNotImplement) {} 502 503type stringName struct { 504 hasJSON bool 505 once sync.Once 506 nameJSON string 507 nameText string 508} 509 510// InitJSON initializes the name. It is exported for use by other internal packages. 511func (s *stringName) InitJSON(name string) { 512 s.hasJSON = true 513 s.nameJSON = name 514} 515 516func (s *stringName) lazyInit(fd pref.FieldDescriptor) *stringName { 517 s.once.Do(func() { 518 if fd.IsExtension() { 519 // For extensions, JSON and text are formatted the same way. 520 var name string 521 if messageset.IsMessageSetExtension(fd) { 522 name = string("[" + fd.FullName().Parent() + "]") 523 } else { 524 name = string("[" + fd.FullName() + "]") 525 } 526 s.nameJSON = name 527 s.nameText = name 528 } else { 529 // Format the JSON name. 530 if !s.hasJSON { 531 s.nameJSON = strs.JSONCamelCase(string(fd.Name())) 532 } 533 534 // Format the text name. 535 s.nameText = string(fd.Name()) 536 if fd.Kind() == pref.GroupKind { 537 s.nameText = string(fd.Message().Name()) 538 } 539 } 540 }) 541 return s 542} 543 544func (s *stringName) getJSON(fd pref.FieldDescriptor) string { return s.lazyInit(fd).nameJSON } 545func (s *stringName) getText(fd pref.FieldDescriptor) string { return s.lazyInit(fd).nameText } 546 547func DefaultValue(v pref.Value, ev pref.EnumValueDescriptor) defaultValue { 548 dv := defaultValue{has: v.IsValid(), val: v, enum: ev} 549 if b, ok := v.Interface().([]byte); ok { 550 // Store a copy of the default bytes, so that we can detect 551 // accidental mutations of the original value. 552 dv.bytes = append([]byte(nil), b...) 553 } 554 return dv 555} 556 557func unmarshalDefault(b []byte, k pref.Kind, pf *File, ed pref.EnumDescriptor) defaultValue { 558 var evs pref.EnumValueDescriptors 559 if k == pref.EnumKind { 560 // If the enum is declared within the same file, be careful not to 561 // blindly call the Values method, lest we bind ourselves in a deadlock. 562 if e, ok := ed.(*Enum); ok && e.L0.ParentFile == pf { 563 evs = &e.L2.Values 564 } else { 565 evs = ed.Values() 566 } 567 568 // If we are unable to resolve the enum dependency, use a placeholder 569 // enum value since we will not be able to parse the default value. 570 if ed.IsPlaceholder() && pref.Name(b).IsValid() { 571 v := pref.ValueOfEnum(0) 572 ev := PlaceholderEnumValue(ed.FullName().Parent().Append(pref.Name(b))) 573 return DefaultValue(v, ev) 574 } 575 } 576 577 v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor) 578 if err != nil { 579 panic(err) 580 } 581 return DefaultValue(v, ev) 582} 583 584type defaultValue struct { 585 has bool 586 val pref.Value 587 enum pref.EnumValueDescriptor 588 bytes []byte 589} 590 591func (dv *defaultValue) get(fd pref.FieldDescriptor) pref.Value { 592 // Return the zero value as the default if unpopulated. 593 if !dv.has { 594 if fd.Cardinality() == pref.Repeated { 595 return pref.Value{} 596 } 597 switch fd.Kind() { 598 case pref.BoolKind: 599 return pref.ValueOfBool(false) 600 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind: 601 return pref.ValueOfInt32(0) 602 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind: 603 return pref.ValueOfInt64(0) 604 case pref.Uint32Kind, pref.Fixed32Kind: 605 return pref.ValueOfUint32(0) 606 case pref.Uint64Kind, pref.Fixed64Kind: 607 return pref.ValueOfUint64(0) 608 case pref.FloatKind: 609 return pref.ValueOfFloat32(0) 610 case pref.DoubleKind: 611 return pref.ValueOfFloat64(0) 612 case pref.StringKind: 613 return pref.ValueOfString("") 614 case pref.BytesKind: 615 return pref.ValueOfBytes(nil) 616 case pref.EnumKind: 617 if evs := fd.Enum().Values(); evs.Len() > 0 { 618 return pref.ValueOfEnum(evs.Get(0).Number()) 619 } 620 return pref.ValueOfEnum(0) 621 } 622 } 623 624 if len(dv.bytes) > 0 && !bytes.Equal(dv.bytes, dv.val.Bytes()) { 625 // TODO: Avoid panic if we're running with the race detector 626 // and instead spawn a goroutine that periodically resets 627 // this value back to the original to induce a race. 628 panic(fmt.Sprintf("detected mutation on the default bytes for %v", fd.FullName())) 629 } 630 return dv.val 631} 632