github.com/hoveychen/protoreflect@v1.4.7-0.20221103114119-0b4b3385ec76/desc/builder/field.go (about) 1 package builder 2 3 import ( 4 "fmt" 5 "strings" 6 "unicode" 7 8 "github.com/golang/protobuf/proto" 9 dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" 10 11 "github.com/hoveychen/protoreflect/desc" 12 "github.com/hoveychen/protoreflect/desc/internal" 13 ) 14 15 // FieldBuilder is a builder used to construct a desc.FieldDescriptor. A field 16 // builder is used to create fields and extensions as well as map entry 17 // messages. It is also used to link groups (defined via a message builder) into 18 // an enclosing message, associating it with a group field. A non-extension 19 // field builder *must* be added to a message before calling its Build() method. 20 // 21 // To create a new FieldBuilder, use NewField, NewMapField, NewGroupField, 22 // NewExtension, or NewExtensionImported (depending on the type of field being 23 // built). 24 type FieldBuilder struct { 25 baseBuilder 26 number int32 27 28 // msgType is populated for fields that have a "private" message type that 29 // isn't expected to be referenced elsewhere. This happens for map fields, 30 // where the private message type represents the map entry, and for group 31 // fields. 32 msgType *MessageBuilder 33 fieldType *FieldType 34 35 Options *dpb.FieldOptions 36 Label dpb.FieldDescriptorProto_Label 37 Default string 38 JsonName string 39 40 foreignExtendee *desc.MessageDescriptor 41 localExtendee *MessageBuilder 42 } 43 44 // NewField creates a new FieldBuilder for a non-extension field with the given 45 // name and type. To create a map or group field, see NewMapField or 46 // NewGroupField respectively. 47 // 48 // The new field will be optional. See SetLabel, SetRepeated, and SetRequired 49 // for changing this aspect of the field. The new field's tag will be zero, 50 // which means it will be auto-assigned when the descriptor is built. Use 51 // SetNumber or TrySetNumber to assign an explicit tag number. 52 func NewField(name string, typ *FieldType) *FieldBuilder { 53 flb := &FieldBuilder{ 54 baseBuilder: baseBuilderWithName(name), 55 fieldType: typ, 56 } 57 return flb 58 } 59 60 // NewMapField creates a new FieldBuilder for a non-extension field with the 61 // given name and whose type is a map of the given key and value types. Map keys 62 // can be any of the scalar integer types, booleans, or strings. If any other 63 // type is specified, this function will panic. Map values cannot be groups: if 64 // a group type is specified, this function will panic. 65 // 66 // When this field is added to a message, the associated map entry message type 67 // will also be added. 68 // 69 // The new field's tag will be zero, which means it will be auto-assigned when 70 // the descriptor is built. Use SetNumber or TrySetNumber to assign an explicit 71 // tag number. 72 func NewMapField(name string, keyTyp, valTyp *FieldType) *FieldBuilder { 73 switch keyTyp.fieldType { 74 case dpb.FieldDescriptorProto_TYPE_BOOL, 75 dpb.FieldDescriptorProto_TYPE_STRING, 76 dpb.FieldDescriptorProto_TYPE_INT32, dpb.FieldDescriptorProto_TYPE_INT64, 77 dpb.FieldDescriptorProto_TYPE_SINT32, dpb.FieldDescriptorProto_TYPE_SINT64, 78 dpb.FieldDescriptorProto_TYPE_UINT32, dpb.FieldDescriptorProto_TYPE_UINT64, 79 dpb.FieldDescriptorProto_TYPE_FIXED32, dpb.FieldDescriptorProto_TYPE_FIXED64, 80 dpb.FieldDescriptorProto_TYPE_SFIXED32, dpb.FieldDescriptorProto_TYPE_SFIXED64: 81 // allowed 82 default: 83 panic(fmt.Sprintf("Map types cannot have keys of type %v", keyTyp.fieldType)) 84 } 85 if valTyp.fieldType == dpb.FieldDescriptorProto_TYPE_GROUP { 86 panic(fmt.Sprintf("Map types cannot have values of type %v", valTyp.fieldType)) 87 } 88 entryMsg := NewMessage(entryTypeName(name)) 89 keyFlb := NewField("key", keyTyp) 90 keyFlb.number = 1 91 valFlb := NewField("value", valTyp) 92 valFlb.number = 2 93 entryMsg.AddField(keyFlb) 94 entryMsg.AddField(valFlb) 95 entryMsg.Options = &dpb.MessageOptions{MapEntry: proto.Bool(true)} 96 97 flb := NewField(name, FieldTypeMessage(entryMsg)). 98 SetLabel(dpb.FieldDescriptorProto_LABEL_REPEATED) 99 flb.msgType = entryMsg 100 entryMsg.setParent(flb) 101 return flb 102 } 103 104 // NewGroupField creates a new FieldBuilder for a non-extension field whose type 105 // is a group with the given definition. The given message's name must start 106 // with a capital letter, and the resulting field will have the same name but 107 // converted to all lower-case. If a message is given with a name that starts 108 // with a lower-case letter, this function will panic. 109 // 110 // When this field is added to a message, the associated group message type will 111 // also be added. 112 // 113 // The new field will be optional. See SetLabel, SetRepeated, and SetRequired 114 // for changing this aspect of the field. The new field's tag will be zero, 115 // which means it will be auto-assigned when the descriptor is built. Use 116 // SetNumber or TrySetNumber to assign an explicit tag number. 117 func NewGroupField(mb *MessageBuilder) *FieldBuilder { 118 if !unicode.IsUpper(rune(mb.name[0])) { 119 panic(fmt.Sprintf("group name %s must start with a capital letter", mb.name)) 120 } 121 Unlink(mb) 122 123 ft := &FieldType{ 124 fieldType: dpb.FieldDescriptorProto_TYPE_GROUP, 125 localMsgType: mb, 126 } 127 fieldName := strings.ToLower(mb.GetName()) 128 flb := NewField(fieldName, ft) 129 flb.msgType = mb 130 mb.setParent(flb) 131 return flb 132 } 133 134 // NewExtension creates a new FieldBuilder for an extension field with the given 135 // name, tag, type, and extendee. The extendee given is a message builder. 136 // 137 // The new field will be optional. See SetLabel and SetRepeated for changing 138 // this aspect of the field. 139 func NewExtension(name string, tag int32, typ *FieldType, extendee *MessageBuilder) *FieldBuilder { 140 if extendee == nil { 141 panic("extendee cannot be nil") 142 } 143 flb := NewField(name, typ).SetNumber(tag) 144 flb.localExtendee = extendee 145 return flb 146 } 147 148 // NewExtensionImported creates a new FieldBuilder for an extension field with 149 // the given name, tag, type, and extendee. The extendee given is a message 150 // descriptor. 151 // 152 // The new field will be optional. See SetLabel and SetRepeated for changing 153 // this aspect of the field. 154 func NewExtensionImported(name string, tag int32, typ *FieldType, extendee *desc.MessageDescriptor) *FieldBuilder { 155 if extendee == nil { 156 panic("extendee cannot be nil") 157 } 158 flb := NewField(name, typ).SetNumber(tag) 159 flb.foreignExtendee = extendee 160 return flb 161 } 162 163 // FromField returns a FieldBuilder that is effectively a copy of the given 164 // descriptor. 165 // 166 // Note that it is not just the given field that is copied but its entire file. 167 // So the caller can get the parent element of the returned builder and the 168 // result would be a builder that is effectively a copy of the field 169 // descriptor's parent. 170 // 171 // This means that field builders created from descriptors do not need to be 172 // explicitly assigned to a file in order to preserve the original field's 173 // package name. 174 func FromField(fld *desc.FieldDescriptor) (*FieldBuilder, error) { 175 if fb, err := FromFile(fld.GetFile()); err != nil { 176 return nil, err 177 } else if flb, ok := fb.findFullyQualifiedElement(fld.GetFullyQualifiedName()).(*FieldBuilder); ok { 178 return flb, nil 179 } else { 180 return nil, fmt.Errorf("could not find field %s after converting file %q to builder", fld.GetFullyQualifiedName(), fld.GetFile().GetName()) 181 } 182 } 183 184 func fromField(fld *desc.FieldDescriptor) (*FieldBuilder, error) { 185 ft := fieldTypeFromDescriptor(fld) 186 flb := NewField(fld.GetName(), ft) 187 flb.Options = fld.GetFieldOptions() 188 flb.Label = fld.GetLabel() 189 flb.Default = fld.AsFieldDescriptorProto().GetDefaultValue() 190 flb.JsonName = fld.GetJSONName() 191 setComments(&flb.comments, fld.GetSourceInfo()) 192 193 if fld.IsExtension() { 194 flb.foreignExtendee = fld.GetOwner() 195 } 196 if err := flb.TrySetNumber(fld.GetNumber()); err != nil { 197 return nil, err 198 } 199 return flb, nil 200 } 201 202 // SetName changes this field's name, returning the field builder for method 203 // chaining. If the given new name is not valid (e.g. TrySetName would have 204 // returned an error) then this method will panic. 205 func (flb *FieldBuilder) SetName(newName string) *FieldBuilder { 206 if err := flb.TrySetName(newName); err != nil { 207 panic(err) 208 } 209 return flb 210 } 211 212 // TrySetName changes this field's name. It will return an error if the given 213 // new name is not a valid protobuf identifier or if the parent builder already 214 // has an element with the given name. 215 // 216 // If the field is a non-extension whose parent is a one-of, the one-of's 217 // enclosing message is checked for elements with a conflicting name. Despite 218 // the fact that one-of choices are modeled as children of the one-of builder, 219 // in the protobuf IDL they are actually all defined in the message's namespace. 220 func (flb *FieldBuilder) TrySetName(newName string) error { 221 var oldMsgName string 222 if flb.msgType != nil { 223 if flb.fieldType.fieldType == dpb.FieldDescriptorProto_TYPE_GROUP { 224 return fmt.Errorf("cannot change name of group field %s; change name of group instead", GetFullyQualifiedName(flb)) 225 } else { 226 oldMsgName = flb.msgType.name 227 msgName := entryTypeName(newName) 228 if err := flb.msgType.trySetNameInternal(msgName); err != nil { 229 return err 230 } 231 } 232 } 233 if err := flb.baseBuilder.setName(flb, newName); err != nil { 234 // undo change to map entry name 235 if flb.msgType != nil && flb.fieldType.fieldType != dpb.FieldDescriptorProto_TYPE_GROUP { 236 flb.msgType.setNameInternal(oldMsgName) 237 } 238 return err 239 } 240 return nil 241 } 242 243 func (flb *FieldBuilder) trySetNameInternal(newName string) error { 244 return flb.baseBuilder.setName(flb, newName) 245 } 246 247 func (flb *FieldBuilder) setNameInternal(newName string) { 248 if err := flb.trySetNameInternal(newName); err != nil { 249 panic(err) 250 } 251 } 252 253 // SetComments sets the comments associated with the field. This method returns 254 // the field builder, for method chaining. 255 func (flb *FieldBuilder) SetComments(c Comments) *FieldBuilder { 256 flb.comments = c 257 return flb 258 } 259 260 func (flb *FieldBuilder) setParent(newParent Builder) { 261 flb.baseBuilder.setParent(newParent) 262 } 263 264 // GetChildren returns any builders assigned to this field builder. The only 265 // kind of children a field can have are message types, that correspond to the 266 // field's map entry type or group type (for map and group fields respectively). 267 func (flb *FieldBuilder) GetChildren() []Builder { 268 if flb.msgType != nil { 269 return []Builder{flb.msgType} 270 } 271 return nil 272 } 273 274 func (flb *FieldBuilder) findChild(name string) Builder { 275 if flb.msgType != nil && flb.msgType.name == name { 276 return flb.msgType 277 } 278 return nil 279 } 280 281 func (flb *FieldBuilder) removeChild(b Builder) { 282 if mb, ok := b.(*MessageBuilder); ok && mb == flb.msgType { 283 flb.msgType = nil 284 if p, ok := flb.parent.(*MessageBuilder); ok { 285 delete(p.symbols, mb.GetName()) 286 } 287 } 288 } 289 290 func (flb *FieldBuilder) renamedChild(b Builder, oldName string) error { 291 if flb.msgType != nil { 292 var oldFieldName string 293 if flb.fieldType.fieldType == dpb.FieldDescriptorProto_TYPE_GROUP { 294 if !unicode.IsUpper(rune(b.GetName()[0])) { 295 return fmt.Errorf("group name %s must start with capital letter", b.GetName()) 296 } 297 // change field name to be lower-case form of group name 298 oldFieldName = flb.name 299 fieldName := strings.ToLower(b.GetName()) 300 if err := flb.trySetNameInternal(fieldName); err != nil { 301 return err 302 } 303 } 304 if p, ok := flb.parent.(*MessageBuilder); ok { 305 if err := p.addSymbol(b); err != nil { 306 if flb.fieldType.fieldType == dpb.FieldDescriptorProto_TYPE_GROUP { 307 // revert the field rename 308 flb.setNameInternal(oldFieldName) 309 } 310 return err 311 } 312 } 313 } 314 return nil 315 } 316 317 // GetNumber returns this field's tag number, or zero if the tag number will be 318 // auto-assigned when the field descriptor is built. 319 func (flb *FieldBuilder) GetNumber() int32 { 320 return flb.number 321 } 322 323 // SetNumber changes the numeric tag for this field and then returns the field, 324 // for method chaining. If the given new tag is not valid (e.g. TrySetNumber 325 // would have returned an error) then this method will panic. 326 func (flb *FieldBuilder) SetNumber(tag int32) *FieldBuilder { 327 if err := flb.TrySetNumber(tag); err != nil { 328 panic(err) 329 } 330 return flb 331 } 332 333 // TrySetNumber changes this field's tag number. It will return an error if the 334 // given new tag is out of valid range or (for non-extension fields) if the 335 // enclosing message already includes a field with the given tag. 336 // 337 // Non-extension fields can be set to zero, which means a proper tag number will 338 // be auto-assigned when the descriptor is built. Extension field tags, however, 339 // must be set to a valid non-zero value. 340 func (flb *FieldBuilder) TrySetNumber(tag int32) error { 341 if tag == flb.number { 342 return nil // no change 343 } 344 if tag < 0 { 345 return fmt.Errorf("cannot set tag number for field %s to negative value %d", GetFullyQualifiedName(flb), tag) 346 } 347 if tag == 0 && flb.IsExtension() { 348 return fmt.Errorf("cannot set tag number for extension %s; only regular fields can be auto-assigned", GetFullyQualifiedName(flb)) 349 } 350 if tag >= internal.SpecialReservedStart && tag <= internal.SpecialReservedEnd { 351 return fmt.Errorf("tag for field %s cannot be in special reserved range %d-%d", GetFullyQualifiedName(flb), internal.SpecialReservedStart, internal.SpecialReservedEnd) 352 } 353 if tag > internal.MaxTag { 354 return fmt.Errorf("tag for field %s cannot be above max %d", GetFullyQualifiedName(flb), internal.MaxTag) 355 } 356 oldTag := flb.number 357 flb.number = tag 358 if flb.IsExtension() { 359 // extension tags are not tracked by builders, so no more to do 360 return nil 361 } 362 switch p := flb.parent.(type) { 363 case *OneOfBuilder: 364 m := p.parent() 365 if m != nil { 366 if err := m.addTag(flb); err != nil { 367 flb.number = oldTag 368 return err 369 } 370 delete(m.fieldTags, oldTag) 371 } 372 case *MessageBuilder: 373 if err := p.addTag(flb); err != nil { 374 flb.number = oldTag 375 return err 376 } 377 delete(p.fieldTags, oldTag) 378 } 379 return nil 380 } 381 382 // SetOptions sets the field options for this field and returns the field, for 383 // method chaining. 384 func (flb *FieldBuilder) SetOptions(options *dpb.FieldOptions) *FieldBuilder { 385 flb.Options = options 386 return flb 387 } 388 389 // SetLabel sets the label for this field, which can be optional, repeated, or 390 // required. It returns the field builder, for method chaining. 391 func (flb *FieldBuilder) SetLabel(lbl dpb.FieldDescriptorProto_Label) *FieldBuilder { 392 flb.Label = lbl 393 return flb 394 } 395 396 // SetRepeated sets the label for this field to repeated. It returns the field 397 // builder, for method chaining. 398 func (flb *FieldBuilder) SetRepeated() *FieldBuilder { 399 return flb.SetLabel(dpb.FieldDescriptorProto_LABEL_REPEATED) 400 } 401 402 // SetRequired sets the label for this field to required. It returns the field 403 // builder, for method chaining. 404 func (flb *FieldBuilder) SetRequired() *FieldBuilder { 405 return flb.SetLabel(dpb.FieldDescriptorProto_LABEL_REQUIRED) 406 } 407 408 // SetOptional sets the label for this field to optional. It returns the field 409 // builder, for method chaining. 410 func (flb *FieldBuilder) SetOptional() *FieldBuilder { 411 return flb.SetLabel(dpb.FieldDescriptorProto_LABEL_OPTIONAL) 412 } 413 414 // IsRepeated returns true if this field's label is repeated. Fields created via 415 // NewMapField will be repeated (since map's are represented "under the hood" as 416 // a repeated field of map entry messages). 417 func (flb *FieldBuilder) IsRepeated() bool { 418 return flb.Label == dpb.FieldDescriptorProto_LABEL_REPEATED 419 } 420 421 // IsRequired returns true if this field's label is required. 422 func (flb *FieldBuilder) IsRequired() bool { 423 return flb.Label == dpb.FieldDescriptorProto_LABEL_REQUIRED 424 } 425 426 // IsOptional returns true if this field's label is optional. 427 func (flb *FieldBuilder) IsOptional() bool { 428 return flb.Label == dpb.FieldDescriptorProto_LABEL_OPTIONAL 429 } 430 431 // IsMap returns true if this field is a map field. 432 func (flb *FieldBuilder) IsMap() bool { 433 return flb.IsRepeated() && 434 flb.msgType != nil && 435 flb.fieldType.fieldType != dpb.FieldDescriptorProto_TYPE_GROUP && 436 flb.msgType.Options != nil && 437 flb.msgType.Options.GetMapEntry() 438 } 439 440 // GetType returns the field's type. 441 func (flb *FieldBuilder) GetType() *FieldType { 442 return flb.fieldType 443 } 444 445 // SetType changes the field's type and returns the field builder, for method 446 // chaining. 447 func (flb *FieldBuilder) SetType(ft *FieldType) *FieldBuilder { 448 flb.fieldType = ft 449 if flb.msgType != nil && flb.msgType != ft.localMsgType { 450 Unlink(flb.msgType) 451 } 452 return flb 453 } 454 455 // SetDefaultValue changes the field's type and returns the field builder, for 456 // method chaining. 457 func (flb *FieldBuilder) SetDefaultValue(defValue string) *FieldBuilder { 458 flb.Default = defValue 459 return flb 460 } 461 462 // SetJsonName sets the name used in the field's JSON representation and then 463 // returns the field builder, for method chaining. 464 func (flb *FieldBuilder) SetJsonName(jsonName string) *FieldBuilder { 465 flb.JsonName = jsonName 466 return flb 467 } 468 469 // IsExtension returns true if this is an extension field. 470 func (flb *FieldBuilder) IsExtension() bool { 471 return flb.localExtendee != nil || flb.foreignExtendee != nil 472 } 473 474 // GetExtendeeTypeName returns the fully qualified name of the extended message 475 // or it returns an empty string if this is not an extension field. 476 func (flb *FieldBuilder) GetExtendeeTypeName() string { 477 if flb.foreignExtendee != nil { 478 return flb.foreignExtendee.GetFullyQualifiedName() 479 } else if flb.localExtendee != nil { 480 return GetFullyQualifiedName(flb.localExtendee) 481 } else { 482 return "" 483 } 484 } 485 486 func (flb *FieldBuilder) buildProto(path []int32, sourceInfo *dpb.SourceCodeInfo) (*dpb.FieldDescriptorProto, error) { 487 addCommentsTo(sourceInfo, path, &flb.comments) 488 489 var lbl *dpb.FieldDescriptorProto_Label 490 if int32(flb.Label) != 0 { 491 lbl = flb.Label.Enum() 492 } 493 var typeName *string 494 tn := flb.fieldType.GetTypeName() 495 if tn != "" { 496 typeName = proto.String("." + tn) 497 } 498 var extendee *string 499 if flb.IsExtension() { 500 extendee = proto.String("." + flb.GetExtendeeTypeName()) 501 } 502 jsName := flb.JsonName 503 if jsName == "" { 504 jsName = internal.JsonName(flb.name) 505 } 506 var def *string 507 if flb.Default != "" { 508 def = proto.String(flb.Default) 509 } 510 511 return &dpb.FieldDescriptorProto{ 512 Name: proto.String(flb.name), 513 Number: proto.Int32(flb.number), 514 Options: flb.Options, 515 Label: lbl, 516 Type: flb.fieldType.fieldType.Enum(), 517 TypeName: typeName, 518 JsonName: proto.String(jsName), 519 DefaultValue: def, 520 Extendee: extendee, 521 }, nil 522 } 523 524 // Build constructs a field descriptor based on the contents of this field 525 // builder. If there are any problems constructing the descriptor, including 526 // resolving symbols referenced by the builder or failing to meet certain 527 // validation rules, an error is returned. 528 func (flb *FieldBuilder) Build() (*desc.FieldDescriptor, error) { 529 fld, err := flb.BuildDescriptor() 530 if err != nil { 531 return nil, err 532 } 533 return fld.(*desc.FieldDescriptor), nil 534 } 535 536 // BuildDescriptor constructs a field descriptor based on the contents of this 537 // field builder. Most usages will prefer Build() instead, whose return type is 538 // a concrete descriptor type. This method is present to satisfy the Builder 539 // interface. 540 func (flb *FieldBuilder) BuildDescriptor() (desc.Descriptor, error) { 541 return doBuild(flb, BuilderOptions{}) 542 } 543 544 // OneOfBuilder is a builder used to construct a desc.OneOfDescriptor. A one-of 545 // builder *must* be added to a message before calling its Build() method. 546 // 547 // To create a new OneOfBuilder, use NewOneOf. 548 type OneOfBuilder struct { 549 baseBuilder 550 551 Options *dpb.OneofOptions 552 553 choices []*FieldBuilder 554 symbols map[string]*FieldBuilder 555 } 556 557 // NewOneOf creates a new OneOfBuilder for a one-of with the given name. 558 func NewOneOf(name string) *OneOfBuilder { 559 return &OneOfBuilder{ 560 baseBuilder: baseBuilderWithName(name), 561 symbols: map[string]*FieldBuilder{}, 562 } 563 } 564 565 // FromOneOf returns a OneOfBuilder that is effectively a copy of the given 566 // descriptor. 567 // 568 // Note that it is not just the given one-of that is copied but its entire file. 569 // So the caller can get the parent element of the returned builder and the 570 // result would be a builder that is effectively a copy of the one-of 571 // descriptor's parent message. 572 // 573 // This means that one-of builders created from descriptors do not need to be 574 // explicitly assigned to a file in order to preserve the original one-of's 575 // package name. 576 func FromOneOf(ood *desc.OneOfDescriptor) (*OneOfBuilder, error) { 577 if fb, err := FromFile(ood.GetFile()); err != nil { 578 return nil, err 579 } else if oob, ok := fb.findFullyQualifiedElement(ood.GetFullyQualifiedName()).(*OneOfBuilder); ok { 580 return oob, nil 581 } else { 582 return nil, fmt.Errorf("could not find one-of %s after converting file %q to builder", ood.GetFullyQualifiedName(), ood.GetFile().GetName()) 583 } 584 } 585 586 func fromOneOf(ood *desc.OneOfDescriptor) (*OneOfBuilder, error) { 587 oob := NewOneOf(ood.GetName()) 588 oob.Options = ood.GetOneOfOptions() 589 setComments(&oob.comments, ood.GetSourceInfo()) 590 591 for _, fld := range ood.GetChoices() { 592 if flb, err := fromField(fld); err != nil { 593 return nil, err 594 } else if err := oob.TryAddChoice(flb); err != nil { 595 return nil, err 596 } 597 } 598 599 return oob, nil 600 } 601 602 // SetName changes this one-of's name, returning the one-of builder for method 603 // chaining. If the given new name is not valid (e.g. TrySetName would have 604 // returned an error) then this method will panic. 605 func (oob *OneOfBuilder) SetName(newName string) *OneOfBuilder { 606 if err := oob.TrySetName(newName); err != nil { 607 panic(err) 608 } 609 return oob 610 } 611 612 // TrySetName changes this one-of's name. It will return an error if the given 613 // new name is not a valid protobuf identifier or if the parent message builder 614 // already has an element with the given name. 615 func (oob *OneOfBuilder) TrySetName(newName string) error { 616 return oob.baseBuilder.setName(oob, newName) 617 } 618 619 // SetComments sets the comments associated with the one-of. This method 620 // returns the one-of builder, for method chaining. 621 func (oob *OneOfBuilder) SetComments(c Comments) *OneOfBuilder { 622 oob.comments = c 623 return oob 624 } 625 626 // GetChildren returns any builders assigned to this one-of builder. These will 627 // be choices for the one-of, each of which will be a field builder. 628 func (oob *OneOfBuilder) GetChildren() []Builder { 629 var ch []Builder 630 for _, evb := range oob.choices { 631 ch = append(ch, evb) 632 } 633 return ch 634 } 635 636 func (oob *OneOfBuilder) parent() *MessageBuilder { 637 if oob.baseBuilder.parent == nil { 638 return nil 639 } 640 return oob.baseBuilder.parent.(*MessageBuilder) 641 } 642 643 func (oob *OneOfBuilder) findChild(name string) Builder { 644 // in terms of finding a child by qualified name, fields in the 645 // one-of are considered children of the message, not the one-of 646 return nil 647 } 648 649 func (oob *OneOfBuilder) removeChild(b Builder) { 650 if p, ok := b.GetParent().(*OneOfBuilder); !ok || p != oob { 651 return 652 } 653 654 if oob.parent() != nil { 655 // remove from message's name and tag maps 656 flb := b.(*FieldBuilder) 657 delete(oob.parent().fieldTags, flb.GetNumber()) 658 delete(oob.parent().symbols, flb.GetName()) 659 } 660 661 oob.choices = deleteBuilder(b.GetName(), oob.choices).([]*FieldBuilder) 662 delete(oob.symbols, b.GetName()) 663 b.setParent(nil) 664 } 665 666 func (oob *OneOfBuilder) renamedChild(b Builder, oldName string) error { 667 if p, ok := b.GetParent().(*OneOfBuilder); !ok || p != oob { 668 return nil 669 } 670 671 if err := oob.addSymbol(b.(*FieldBuilder)); err != nil { 672 return err 673 } 674 675 // update message's name map (to make sure new field name doesn't 676 // collide with other kinds of elements in the message) 677 if oob.parent() != nil { 678 if err := oob.parent().addSymbol(b); err != nil { 679 delete(oob.symbols, b.GetName()) 680 return err 681 } 682 delete(oob.parent().symbols, oldName) 683 } 684 685 delete(oob.symbols, oldName) 686 return nil 687 } 688 689 func (oob *OneOfBuilder) addSymbol(b *FieldBuilder) error { 690 if _, ok := oob.symbols[b.GetName()]; ok { 691 return fmt.Errorf("one-of %s already contains field named %q", GetFullyQualifiedName(oob), b.GetName()) 692 } 693 oob.symbols[b.GetName()] = b 694 return nil 695 } 696 697 // GetChoice returns the field with the given name. If no such field exists in 698 // the one-of, nil is returned. 699 func (oob *OneOfBuilder) GetChoice(name string) *FieldBuilder { 700 return oob.symbols[name] 701 } 702 703 // RemoveChoice removes the field with the given name. If no such field exists 704 // in the one-of, this is a no-op. This returns the one-of builder, for method 705 // chaining. 706 func (oob *OneOfBuilder) RemoveChoice(name string) *OneOfBuilder { 707 oob.TryRemoveChoice(name) 708 return oob 709 } 710 711 // TryRemoveChoice removes the field with the given name and returns false if 712 // the one-of has no such field. 713 func (oob *OneOfBuilder) TryRemoveChoice(name string) bool { 714 if flb, ok := oob.symbols[name]; ok { 715 oob.removeChild(flb) 716 return true 717 } 718 return false 719 } 720 721 // AddChoice adds the given field to this one-of. If an error prevents the field 722 // from being added, this method panics. If the given field is an extension, 723 // this method panics. If the given field is a group or map field or if it is 724 // not optional (e.g. it is required or repeated), this method panics. This 725 // returns the one-of builder, for method chaining. 726 func (oob *OneOfBuilder) AddChoice(flb *FieldBuilder) *OneOfBuilder { 727 if err := oob.TryAddChoice(flb); err != nil { 728 panic(err) 729 } 730 return oob 731 } 732 733 // TryAddChoice adds the given field to this one-of, returning any error that 734 // prevents the field from being added (such as a name collision with another 735 // element already added to the enclosing message). An error is returned if the 736 // given field is an extension field, a map or group field, or repeated or 737 // required. 738 func (oob *OneOfBuilder) TryAddChoice(flb *FieldBuilder) error { 739 if flb.IsExtension() { 740 return fmt.Errorf("field %s is an extension, not a regular field", flb.GetName()) 741 } 742 if flb.msgType != nil { 743 return fmt.Errorf("cannot add a group or map field %q to one-of %s", flb.name, GetFullyQualifiedName(oob)) 744 } 745 if flb.IsRepeated() || flb.IsRequired() { 746 return fmt.Errorf("fields in a one-of must be optional, %s is %v", flb.name, flb.Label) 747 } 748 if err := oob.addSymbol(flb); err != nil { 749 return err 750 } 751 mb := oob.parent() 752 if mb != nil { 753 // If we are moving field from a message to a one-of that belongs to the 754 // same message, we have to use different order of operations to prevent 755 // failure (otherwise, it looks like it's being added twice). 756 // (We do similar if moving the other direction, from the one-of into 757 // the message to which one-of belongs.) 758 needToUnlinkFirst := mb.isPresentButNotChild(flb) 759 if needToUnlinkFirst { 760 Unlink(flb) 761 mb.registerField(flb) 762 } else { 763 if err := mb.registerField(flb); err != nil { 764 delete(oob.symbols, flb.GetName()) 765 return err 766 } 767 Unlink(flb) 768 } 769 } 770 flb.setParent(oob) 771 oob.choices = append(oob.choices, flb) 772 return nil 773 } 774 775 // SetOptions sets the one-of options for this one-of and returns the one-of, 776 // for method chaining. 777 func (oob *OneOfBuilder) SetOptions(options *dpb.OneofOptions) *OneOfBuilder { 778 oob.Options = options 779 return oob 780 } 781 782 func (oob *OneOfBuilder) buildProto(path []int32, sourceInfo *dpb.SourceCodeInfo) (*dpb.OneofDescriptorProto, error) { 783 addCommentsTo(sourceInfo, path, &oob.comments) 784 785 for _, flb := range oob.choices { 786 if flb.IsRepeated() || flb.IsRequired() { 787 return nil, fmt.Errorf("fields in a one-of must be optional, %s is %v", GetFullyQualifiedName(flb), flb.Label) 788 } 789 } 790 791 return &dpb.OneofDescriptorProto{ 792 Name: proto.String(oob.name), 793 Options: oob.Options, 794 }, nil 795 } 796 797 // Build constructs a one-of descriptor based on the contents of this one-of 798 // builder. If there are any problems constructing the descriptor, including 799 // resolving symbols referenced by the builder or failing to meet certain 800 // validation rules, an error is returned. 801 func (oob *OneOfBuilder) Build() (*desc.OneOfDescriptor, error) { 802 ood, err := oob.BuildDescriptor() 803 if err != nil { 804 return nil, err 805 } 806 return ood.(*desc.OneOfDescriptor), nil 807 } 808 809 // BuildDescriptor constructs a one-of descriptor based on the contents of this 810 // one-of builder. Most usages will prefer Build() instead, whose return type is 811 // a concrete descriptor type. This method is present to satisfy the Builder 812 // interface. 813 func (oob *OneOfBuilder) BuildDescriptor() (desc.Descriptor, error) { 814 return doBuild(oob, BuilderOptions{}) 815 } 816 817 func entryTypeName(fieldName string) string { 818 return internal.InitCap(internal.JsonName(fieldName)) + "Entry" 819 }