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