1//go:build codegen 2// +build codegen 3 4package api 5 6import ( 7 "bytes" 8 "fmt" 9 "path" 10 "regexp" 11 "sort" 12 "strings" 13 "text/template" 14 15 "github.com/aws/aws-sdk-go/private/protocol" 16) 17 18// ErrorInfo represents the error block of a shape's structure 19type ErrorInfo struct { 20 Type string 21 Code string 22 HTTPStatusCode int 23} 24 25// A XMLInfo defines URL and prefix for Shapes when rendered as XML 26type XMLInfo struct { 27 Prefix string 28 URI string 29} 30 31// A ShapeRef defines the usage of a shape within the API. 32type ShapeRef struct { 33 API *API `json:"-"` 34 Shape *Shape `json:"-"` 35 Documentation string 36 ShapeName string `json:"shape"` 37 Location string 38 LocationName string 39 QueryName string 40 Flattened bool 41 Streaming bool 42 XMLAttribute bool 43 // Ignore, if set, will not be sent over the wire 44 Ignore bool 45 XMLNamespace XMLInfo 46 Payload string 47 IdempotencyToken bool `json:"idempotencyToken"` 48 TimestampFormat string `json:"timestampFormat"` 49 JSONValue bool `json:"jsonvalue"` 50 Deprecated bool `json:"deprecated"` 51 DeprecatedMsg string `json:"deprecatedMessage"` 52 EndpointDiscoveryID bool `json:"endpointdiscoveryid"` 53 HostLabel bool `json:"hostLabel"` 54 55 OrigShapeName string `json:"-"` 56 57 GenerateGetter bool 58 59 IsEventPayload bool `json:"eventpayload"` 60 IsEventHeader bool `json:"eventheader"` 61 62 // Collection of custom tags the shape reference includes. 63 CustomTags ShapeTags 64 65 // Flags whether the member reference is a endpoint ARN 66 EndpointARN bool 67 68 // Flags whether the member reference is a Outpost ID 69 OutpostIDMember bool 70 71 // Flag whether the member reference is a Account ID when endpoint shape ARN is present 72 AccountIDMemberWithARN bool 73} 74 75// A Shape defines the definition of a shape type 76type Shape struct { 77 API *API `json:"-"` 78 ShapeName string 79 Documentation string 80 MemberRefs map[string]*ShapeRef `json:"members"` 81 MemberRef ShapeRef `json:"member"` // List ref 82 KeyRef ShapeRef `json:"key"` // map key ref 83 ValueRef ShapeRef `json:"value"` // map value ref 84 Required []string 85 Payload string 86 Type string 87 Exception bool 88 Enum []string 89 EnumConsts []string 90 Flattened bool 91 Streaming bool 92 Location string 93 LocationName string 94 IdempotencyToken bool `json:"idempotencyToken"` 95 TimestampFormat string `json:"timestampFormat"` 96 XMLNamespace XMLInfo 97 Min float64 // optional Minimum length (string, list) or value (number) 98 99 OutputEventStreamAPI *EventStreamAPI 100 EventStream *EventStream 101 EventFor map[string]*EventStream `json:"-"` 102 103 IsInputEventStream bool `json:"-"` 104 IsOutputEventStream bool `json:"-"` 105 106 IsEventStream bool `json:"eventstream"` 107 IsEvent bool `json:"event"` 108 109 refs []*ShapeRef // References to this shape 110 resolvePkg string // use this package in the goType() if present 111 112 OrigShapeName string `json:"-"` 113 114 // Defines if the shape is a placeholder and should not be used directly 115 Placeholder bool 116 117 Deprecated bool `json:"deprecated"` 118 DeprecatedMsg string `json:"deprecatedMessage"` 119 120 Validations ShapeValidations 121 122 // Error information that is set if the shape is an error shape. 123 ErrorInfo ErrorInfo `json:"error"` 124 125 // Flags that the shape cannot be rename. Prevents the shape from being 126 // renamed further by the Input/Output. 127 AliasedShapeName bool 128 129 // Sensitive types should not be logged by SDK type loggers. 130 Sensitive bool `json:"sensitive"` 131 132 // Flags that a member of the shape is an EndpointARN 133 HasEndpointARNMember bool 134 135 // Flags that a member of the shape is an OutpostIDMember 136 HasOutpostIDMember bool 137 138 // Flags that the shape has an account id member along with EndpointARN member 139 HasAccountIdMemberWithARN bool 140 141 // Indicates the Shape is used as an operation input 142 UsedAsInput bool 143 144 // Indicates the Shape is used as an operation output 145 UsedAsOutput bool 146} 147 148// CanBeEmpty returns if the shape value can sent request as an empty value. 149// String, blob, list, and map are types must not be empty when the member is 150// serialized to the URI path, or decorated with HostLabel. 151func (ref *ShapeRef) CanBeEmpty() bool { 152 switch ref.Shape.Type { 153 case "string": 154 return !(ref.Location == "uri" || ref.HostLabel) 155 case "blob", "map", "list": 156 return !(ref.Location == "uri") 157 default: 158 return true 159 } 160} 161 162// ErrorCodeName will return the error shape's name formated for 163// error code const. 164func (s *Shape) ErrorCodeName() string { 165 return "ErrCode" + s.ShapeName 166} 167 168// ErrorName will return the shape's name or error code if available based 169// on the API's protocol. This is the error code string returned by the service. 170func (s *Shape) ErrorName() string { 171 name := s.ErrorInfo.Type 172 switch s.API.Metadata.Protocol { 173 case "query", "ec2query", "rest-xml": 174 if len(s.ErrorInfo.Code) > 0 { 175 name = s.ErrorInfo.Code 176 } 177 } 178 179 if len(name) == 0 { 180 name = s.OrigShapeName 181 } 182 if len(name) == 0 { 183 name = s.ShapeName 184 } 185 186 return name 187} 188 189// PayloadRefName returns the payload member of the shape if there is one 190// modeled. If no payload is modeled, empty string will be returned. 191func (s *Shape) PayloadRefName() string { 192 if name := s.Payload; len(name) != 0 { 193 // Root shape 194 return name 195 } 196 197 for name, ref := range s.MemberRefs { 198 if ref.IsEventPayload { 199 return name 200 } 201 } 202 203 return "" 204} 205 206// GoTags returns the struct tags for a shape. 207func (s *Shape) GoTags(root, required bool) string { 208 ref := &ShapeRef{ShapeName: s.ShapeName, API: s.API, Shape: s} 209 return ref.GoTags(root, required) 210} 211 212// Rename changes the name of the Shape to newName. Also updates 213// the associated API's reference to use newName. 214func (s *Shape) Rename(newName string) { 215 if s.AliasedShapeName { 216 panic(fmt.Sprintf("attempted to rename %s, but flagged as aliased", 217 s.ShapeName)) 218 } 219 220 for _, r := range s.refs { 221 r.ShapeName = newName 222 } 223 224 delete(s.API.Shapes, s.ShapeName) 225 s.API.Shapes[newName] = s 226 s.ShapeName = newName 227} 228 229// MemberNames returns a slice of struct member names. 230func (s *Shape) MemberNames() []string { 231 i, names := 0, make([]string, len(s.MemberRefs)) 232 for n := range s.MemberRefs { 233 names[i] = n 234 i++ 235 } 236 sort.Strings(names) 237 return names 238} 239 240// HasMember will return whether or not the shape has a given 241// member by name. 242func (s *Shape) HasMember(name string) bool { 243 _, ok := s.MemberRefs[name] 244 return ok 245} 246 247// GoTypeWithPkgName returns a shape's type as a string with the package name in 248// <packageName>.<type> format. Package naming only applies to structures. 249func (s *Shape) GoTypeWithPkgName() string { 250 return goType(s, true) 251} 252 253// GoTypeWithPkgNameElem returns the shapes type as a string with the "*" 254// removed if there was one preset. 255func (s *Shape) GoTypeWithPkgNameElem() string { 256 t := goType(s, true) 257 if strings.HasPrefix(t, "*") { 258 return t[1:] 259 } 260 return t 261} 262 263// UseIndirection returns if the shape's reference should use indirection or not. 264func (s *ShapeRef) UseIndirection() bool { 265 switch s.Shape.Type { 266 case "map", "list", "blob", "structure", "jsonvalue": 267 return false 268 } 269 270 if s.Streaming || s.Shape.Streaming { 271 return false 272 } 273 274 if s.JSONValue { 275 return false 276 } 277 278 return true 279} 280 281func (s Shape) GetTimestampFormat() string { 282 format := s.TimestampFormat 283 284 if len(format) > 0 && !protocol.IsKnownTimestampFormat(format) { 285 panic(fmt.Sprintf("Unknown timestampFormat %s, for %s", 286 format, s.ShapeName)) 287 } 288 289 return format 290} 291 292func (ref ShapeRef) GetTimestampFormat() string { 293 format := ref.TimestampFormat 294 295 if len(format) == 0 { 296 format = ref.Shape.TimestampFormat 297 } 298 299 if len(format) > 0 && !protocol.IsKnownTimestampFormat(format) { 300 panic(fmt.Sprintf("Unknown timestampFormat %s, for %s", 301 format, ref.ShapeName)) 302 } 303 304 return format 305} 306 307// GoStructValueType returns the Shape's Go type value instead of a pointer 308// for the type. 309func (s *Shape) GoStructValueType(name string, ref *ShapeRef) string { 310 v := s.GoStructType(name, ref) 311 312 if ref.UseIndirection() && v[0] == '*' { 313 return v[1:] 314 } 315 316 return v 317} 318 319// GoStructType returns the type of a struct field based on the API 320// model definition. 321func (s *Shape) GoStructType(name string, ref *ShapeRef) string { 322 if (ref.Streaming || ref.Shape.Streaming) && s.Payload == name { 323 rtype := "io.ReadSeeker" 324 if strings.HasSuffix(s.ShapeName, "Output") { 325 rtype = "io.ReadCloser" 326 } 327 328 s.API.imports["io"] = true 329 return rtype 330 } 331 332 if ref.JSONValue { 333 s.API.AddSDKImport("aws") 334 return "aws.JSONValue" 335 } 336 337 for _, v := range s.Validations { 338 // TODO move this to shape validation resolution 339 if (v.Ref.Shape.Type == "map" || v.Ref.Shape.Type == "list") && v.Type == ShapeValidationNested { 340 s.API.imports["fmt"] = true 341 } 342 } 343 344 return ref.GoType() 345} 346 347// GoType returns a shape's Go type 348func (s *Shape) GoType() string { 349 return goType(s, false) 350} 351 352// GoType returns a shape ref's Go type. 353func (ref *ShapeRef) GoType() string { 354 if ref.Shape == nil { 355 panic(fmt.Errorf("missing shape definition on reference for %#v", ref)) 356 } 357 358 return ref.Shape.GoType() 359} 360 361// GoTypeWithPkgName returns a shape's type as a string with the package name in 362// <packageName>.<type> format. Package naming only applies to structures. 363func (ref *ShapeRef) GoTypeWithPkgName() string { 364 if ref.Shape == nil { 365 panic(fmt.Errorf("missing shape definition on reference for %#v", ref)) 366 } 367 368 return ref.Shape.GoTypeWithPkgName() 369} 370 371// Returns a string version of the Shape's type. 372// If withPkgName is true, the package name will be added as a prefix 373func goType(s *Shape, withPkgName bool) string { 374 switch s.Type { 375 case "structure": 376 if withPkgName || s.resolvePkg != "" { 377 pkg := s.resolvePkg 378 if pkg != "" { 379 s.API.imports[pkg] = true 380 pkg = path.Base(pkg) 381 } else { 382 pkg = s.API.PackageName() 383 } 384 return fmt.Sprintf("*%s.%s", pkg, s.ShapeName) 385 } 386 return "*" + s.ShapeName 387 case "map": 388 return "map[string]" + goType(s.ValueRef.Shape, withPkgName) 389 case "jsonvalue": 390 return "aws.JSONValue" 391 case "list": 392 return "[]" + goType(s.MemberRef.Shape, withPkgName) 393 case "boolean": 394 return "*bool" 395 case "string", "character": 396 return "*string" 397 case "blob": 398 return "[]byte" 399 case "byte", "short", "integer", "long": 400 return "*int64" 401 case "float", "double": 402 return "*float64" 403 case "timestamp": 404 s.API.imports["time"] = true 405 return "*time.Time" 406 default: 407 panic("Unsupported shape type: " + s.Type) 408 } 409} 410 411// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just 412// the type will be returned minus the pointer *. 413func (s *Shape) GoTypeElem() string { 414 t := s.GoType() 415 if strings.HasPrefix(t, "*") { 416 return t[1:] 417 } 418 return t 419} 420 421// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just 422// the type will be returned minus the pointer *. 423func (ref *ShapeRef) GoTypeElem() string { 424 if ref.Shape == nil { 425 panic(fmt.Errorf("missing shape definition on reference for %#v", ref)) 426 } 427 428 return ref.Shape.GoTypeElem() 429} 430 431// ShapeTag is a struct tag that will be applied to a shape's generated code 432type ShapeTag struct { 433 Key, Val string 434} 435 436// String returns the string representation of the shape tag 437func (s ShapeTag) String() string { 438 return fmt.Sprintf(`%s:"%s"`, s.Key, s.Val) 439} 440 441// ShapeTags is a collection of shape tags and provides serialization of the 442// tags in an ordered list. 443type ShapeTags []ShapeTag 444 445// Join returns an ordered serialization of the shape tags with the provided 446// separator. 447func (s ShapeTags) Join(sep string) string { 448 o := &bytes.Buffer{} 449 for i, t := range s { 450 o.WriteString(t.String()) 451 if i < len(s)-1 { 452 o.WriteString(sep) 453 } 454 } 455 456 return o.String() 457} 458 459// String is an alias for Join with the empty space separator. 460func (s ShapeTags) String() string { 461 return s.Join(" ") 462} 463 464// GoTags returns the rendered tags string for the ShapeRef 465func (ref *ShapeRef) GoTags(toplevel bool, isRequired bool) string { 466 tags := append(ShapeTags{}, ref.CustomTags...) 467 468 if ref.Location != "" { 469 tags = append(tags, ShapeTag{"location", ref.Location}) 470 } else if ref.Shape.Location != "" { 471 tags = append(tags, ShapeTag{"location", ref.Shape.Location}) 472 } else if ref.IsEventHeader { 473 tags = append(tags, ShapeTag{"location", "header"}) 474 } 475 476 if ref.LocationName != "" { 477 tags = append(tags, ShapeTag{"locationName", ref.LocationName}) 478 } else if ref.Shape.LocationName != "" { 479 tags = append(tags, ShapeTag{"locationName", ref.Shape.LocationName}) 480 } else if len(ref.Shape.EventFor) != 0 && ref.API.Metadata.Protocol == "rest-xml" { 481 // RPC JSON events need to have location name modeled for round trip testing. 482 tags = append(tags, ShapeTag{"locationName", ref.Shape.OrigShapeName}) 483 } 484 485 if ref.QueryName != "" { 486 tags = append(tags, ShapeTag{"queryName", ref.QueryName}) 487 } 488 if ref.Shape.MemberRef.LocationName != "" { 489 tags = append(tags, ShapeTag{"locationNameList", ref.Shape.MemberRef.LocationName}) 490 } 491 if ref.Shape.KeyRef.LocationName != "" { 492 tags = append(tags, ShapeTag{"locationNameKey", ref.Shape.KeyRef.LocationName}) 493 } 494 if ref.Shape.ValueRef.LocationName != "" { 495 tags = append(tags, ShapeTag{"locationNameValue", ref.Shape.ValueRef.LocationName}) 496 } 497 if ref.Shape.Min > 0 { 498 tags = append(tags, ShapeTag{"min", fmt.Sprintf("%v", ref.Shape.Min)}) 499 } 500 501 if ref.Deprecated || ref.Shape.Deprecated { 502 tags = append(tags, ShapeTag{"deprecated", "true"}) 503 } 504 505 // All shapes have a type 506 tags = append(tags, ShapeTag{"type", ref.Shape.Type}) 507 508 // embed the timestamp type for easier lookups 509 if ref.Shape.Type == "timestamp" { 510 if format := ref.GetTimestampFormat(); len(format) > 0 { 511 tags = append(tags, ShapeTag{ 512 Key: "timestampFormat", 513 Val: format, 514 }) 515 } 516 } 517 518 if ref.Shape.Flattened || ref.Flattened { 519 tags = append(tags, ShapeTag{"flattened", "true"}) 520 } 521 if ref.XMLAttribute { 522 tags = append(tags, ShapeTag{"xmlAttribute", "true"}) 523 } 524 if isRequired { 525 tags = append(tags, ShapeTag{"required", "true"}) 526 } 527 if ref.Shape.IsEnum() { 528 tags = append(tags, ShapeTag{"enum", ref.ShapeName}) 529 } 530 531 if toplevel { 532 if name := ref.Shape.PayloadRefName(); len(name) > 0 { 533 tags = append(tags, ShapeTag{"payload", name}) 534 } 535 } 536 537 if ref.XMLNamespace.Prefix != "" { 538 tags = append(tags, ShapeTag{"xmlPrefix", ref.XMLNamespace.Prefix}) 539 } else if ref.Shape.XMLNamespace.Prefix != "" { 540 tags = append(tags, ShapeTag{"xmlPrefix", ref.Shape.XMLNamespace.Prefix}) 541 } 542 543 if ref.XMLNamespace.URI != "" { 544 tags = append(tags, ShapeTag{"xmlURI", ref.XMLNamespace.URI}) 545 } else if ref.Shape.XMLNamespace.URI != "" { 546 tags = append(tags, ShapeTag{"xmlURI", ref.Shape.XMLNamespace.URI}) 547 } 548 549 if ref.IdempotencyToken || ref.Shape.IdempotencyToken { 550 tags = append(tags, ShapeTag{"idempotencyToken", "true"}) 551 } 552 553 if ref.Ignore { 554 tags = append(tags, ShapeTag{"ignore", "true"}) 555 } 556 557 if ref.Shape.Sensitive { 558 tags = append(tags, ShapeTag{"sensitive", "true"}) 559 } 560 561 return fmt.Sprintf("`%s`", tags) 562} 563 564// Docstring returns the godocs formated documentation 565func (ref *ShapeRef) Docstring() string { 566 if ref.Documentation != "" { 567 return strings.Trim(ref.Documentation, "\n ") 568 } 569 return ref.Shape.Docstring() 570} 571 572// Docstring returns the godocs formated documentation 573func (s *Shape) Docstring() string { 574 return strings.Trim(s.Documentation, "\n ") 575} 576 577// IndentedDocstring is the indented form of the doc string. 578func (ref *ShapeRef) IndentedDocstring() string { 579 doc := ref.Docstring() 580 return strings.Replace(doc, "// ", "// ", -1) 581} 582 583var goCodeStringerTmpl = template.Must(template.New("goCodeStringerTmpl").Parse(` 584// String returns the string representation 585func (s {{ $.ShapeName }}) String() string { 586 return awsutil.Prettify(s) 587} 588// GoString returns the string representation 589func (s {{ $.ShapeName }}) GoString() string { 590 return s.String() 591} 592`)) 593 594// GoCodeStringers renders the Stringers for API input/output shapes 595func (s *Shape) GoCodeStringers() string { 596 w := bytes.Buffer{} 597 if err := goCodeStringerTmpl.Execute(&w, s); err != nil { 598 panic(fmt.Sprintln("Unexpected error executing GoCodeStringers template", err)) 599 } 600 601 return w.String() 602} 603 604var enumStrip = regexp.MustCompile(`[^a-zA-Z0-9_:\./-]`) 605var enumDelims = regexp.MustCompile(`[-_:\./]+`) 606var enumCamelCase = regexp.MustCompile(`([a-z])([A-Z])`) 607 608// EnumName returns the Nth enum in the shapes Enum list 609func (s *Shape) EnumName(n int) string { 610 enum := s.Enum[n] 611 enum = enumStrip.ReplaceAllLiteralString(enum, "") 612 enum = enumCamelCase.ReplaceAllString(enum, "$1-$2") 613 parts := enumDelims.Split(enum, -1) 614 for i, v := range parts { 615 v = strings.ToLower(v) 616 parts[i] = "" 617 if len(v) > 0 { 618 parts[i] = strings.ToUpper(v[0:1]) 619 } 620 if len(v) > 1 { 621 parts[i] += v[1:] 622 } 623 } 624 enum = strings.Join(parts, "") 625 enum = strings.ToUpper(enum[0:1]) + enum[1:] 626 return enum 627} 628 629// NestedShape returns the shape pointer value for the shape which is nested 630// under the current shape. If the shape is not nested nil will be returned. 631// 632// strucutures, the current shape is returned 633// map: the value shape of the map is returned 634// list: the element shape of the list is returned 635func (s *Shape) NestedShape() *Shape { 636 var nestedShape *Shape 637 switch s.Type { 638 case "structure": 639 nestedShape = s 640 case "map": 641 nestedShape = s.ValueRef.Shape 642 case "list": 643 nestedShape = s.MemberRef.Shape 644 } 645 646 return nestedShape 647} 648 649var structShapeTmpl = func() *template.Template { 650 shapeTmpl := template.Must( 651 template.New("structShapeTmpl"). 652 Funcs(template.FuncMap{ 653 "GetDeprecatedMsg": getDeprecatedMessage, 654 "TrimExportedMembers": func(s *Shape) map[string]*ShapeRef { 655 members := map[string]*ShapeRef{} 656 for name, ref := range s.MemberRefs { 657 if ref.Shape.IsEventStream { 658 continue 659 } 660 members[name] = ref 661 } 662 return members 663 }, 664 }). 665 Parse(structShapeTmplDef), 666 ) 667 668 template.Must( 669 shapeTmpl.AddParseTree( 670 "eventStreamEventShapeTmpl", eventStreamEventShapeTmpl.Tree), 671 ) 672 template.Must( 673 shapeTmpl.AddParseTree( 674 "exceptionShapeMethodTmpl", 675 exceptionShapeMethodTmpl.Tree), 676 ) 677 shapeTmpl.Funcs(eventStreamEventShapeTmplFuncs) 678 679 template.Must( 680 shapeTmpl.AddParseTree( 681 "hostLabelsShapeTmpl", 682 hostLabelsShapeTmpl.Tree), 683 ) 684 685 template.Must( 686 shapeTmpl.AddParseTree( 687 "endpointARNShapeTmpl", 688 endpointARNShapeTmpl.Tree), 689 ) 690 691 template.Must( 692 shapeTmpl.AddParseTree( 693 "outpostIDShapeTmpl", 694 outpostIDShapeTmpl.Tree), 695 ) 696 697 template.Must( 698 shapeTmpl.AddParseTree( 699 "accountIDWithARNShapeTmpl", 700 accountIDWithARNShapeTmpl.Tree), 701 ) 702 703 return shapeTmpl 704}() 705 706const structShapeTmplDef = ` 707{{ $.Docstring }} 708{{ if $.Deprecated -}} 709{{ if $.Docstring -}} 710// 711{{ end -}} 712// Deprecated: {{ GetDeprecatedMsg $.DeprecatedMsg $.ShapeName }} 713{{ end -}} 714type {{ $.ShapeName }} struct { 715 _ struct{} {{ $.GoTags true false }} 716 717 {{- if $.Exception }} 718 {{- $_ := $.API.AddSDKImport "private/protocol" }} 719 RespMetadata protocol.ResponseMetadata` + "`json:\"-\" xml:\"-\"`" + ` 720 {{- end }} 721 722 {{- if $.OutputEventStreamAPI }} 723 724 {{ $.OutputEventStreamAPI.OutputMemberName }} *{{ $.OutputEventStreamAPI.Name }} 725 {{- end }} 726 727 {{- range $name, $elem := (TrimExportedMembers $) }} 728 729 {{ $isBlob := $.WillRefBeBase64Encoded $name -}} 730 {{ $isRequired := $.IsRequired $name -}} 731 {{ $doc := $elem.Docstring -}} 732 733 {{ if $doc -}} 734 {{ $doc }} 735 {{ if $elem.Deprecated -}} 736 // 737 // Deprecated: {{ GetDeprecatedMsg $elem.DeprecatedMsg $name }} 738 {{ end -}} 739 {{ end -}} 740 {{ if $isBlob -}} 741 {{ if $doc -}} 742 // 743 {{ end -}} 744 // {{ $name }} is automatically base64 encoded/decoded by the SDK. 745 {{ end -}} 746 {{ if $isRequired -}} 747 {{ if or $doc $isBlob -}} 748 // 749 {{ end -}} 750 // {{ $name }} is a required field 751 {{ end -}} 752 {{ $name }} {{ $.GoStructType $name $elem }} {{ $elem.GoTags false $isRequired }} 753 {{- end }} 754} 755 756{{- if not $.API.NoStringerMethods }} 757 {{ $.GoCodeStringers }} 758{{- end }} 759 760{{- if not (or $.API.NoValidataShapeMethods $.Exception) }} 761 {{- if $.Validations }} 762 {{ $.Validations.GoCode $ }} 763 {{- end }} 764{{- end }} 765 766{{- if not (or $.API.NoGenStructFieldAccessors $.Exception) }} 767 {{- $builderShapeName := print $.ShapeName }} 768 769 {{- range $name, $elem := (TrimExportedMembers $) }} 770 // Set{{ $name }} sets the {{ $name }} field's value. 771 func (s *{{ $builderShapeName }}) Set{{ $name }}(v {{ $.GoStructValueType $name $elem }}) *{{ $builderShapeName }} { 772 {{- if $elem.UseIndirection }} 773 s.{{ $name }} = &v 774 {{- else }} 775 s.{{ $name }} = v 776 {{- end }} 777 return s 778 } 779 780 {{- if $elem.GenerateGetter }} 781 782 func (s *{{ $builderShapeName }}) get{{ $name }}() (v {{ $.GoStructValueType $name $elem }}) { 783 {{- if $elem.UseIndirection }} 784 if s.{{ $name }} == nil { 785 return v 786 } 787 return *s.{{ $name }} 788 {{- else }} 789 return s.{{ $name }} 790 {{- end }} 791 } 792 {{- end }} 793 {{- end }} 794{{- end }} 795 796{{- if $.OutputEventStreamAPI }} 797 {{- $esMemberName := $.OutputEventStreamAPI.OutputMemberName }} 798 {{- if $.OutputEventStreamAPI.Legacy }} 799 func (s *{{ $.ShapeName }}) Set{{ $esMemberName }}(v *{{ $.OutputEventStreamAPI.Name }}) *{{ $.ShapeName }} { 800 s.{{ $esMemberName }} = v 801 return s 802 } 803 func (s *{{ $.ShapeName }}) Get{{ $esMemberName }}() *{{ $.OutputEventStreamAPI.Name }} { 804 return s.{{ $esMemberName }} 805 } 806 {{- end }} 807 808 // GetStream returns the type to interact with the event stream. 809 func (s *{{ $.ShapeName }}) GetStream() *{{ $.OutputEventStreamAPI.Name }} { 810 return s.{{ $esMemberName }} 811 } 812{{- end }} 813 814{{- if $.EventFor }} 815 {{ template "eventStreamEventShapeTmpl" $ }} 816{{- end }} 817 818{{- if and $.Exception (or $.API.WithGeneratedTypedErrors $.EventFor) }} 819 {{ template "exceptionShapeMethodTmpl" $ }} 820{{- end }} 821 822{{- if $.HasHostLabelMembers }} 823 {{ template "hostLabelsShapeTmpl" $ }} 824{{- end }} 825 826{{- if $.HasEndpointARNMember }} 827 {{ template "endpointARNShapeTmpl" $ }} 828{{- end }} 829 830{{- if $.HasOutpostIDMember }} 831 {{ template "outpostIDShapeTmpl" $ }} 832{{- end }} 833 834{{- if $.HasAccountIdMemberWithARN }} 835 {{ template "accountIDWithARNShapeTmpl" $ }} 836{{- end }} 837 838` 839 840var exceptionShapeMethodTmpl = template.Must( 841 template.New("exceptionShapeMethodTmpl").Parse(` 842{{- $_ := $.API.AddImport "fmt" }} 843{{/* TODO allow service custom input to be used */}} 844func newError{{ $.ShapeName }}(v protocol.ResponseMetadata) error { 845 return &{{ $.ShapeName }}{ 846 RespMetadata: v, 847 } 848} 849 850// Code returns the exception type name. 851func (s *{{ $.ShapeName }}) Code() string { 852 return "{{ $.ErrorName }}" 853} 854 855// Message returns the exception's message. 856func (s *{{ $.ShapeName }}) Message() string { 857 {{- if index $.MemberRefs "Message_" }} 858 if s.Message_ != nil { 859 return *s.Message_ 860 } 861 {{ end -}} 862 return "" 863} 864 865// OrigErr always returns nil, satisfies awserr.Error interface. 866func (s *{{ $.ShapeName }}) OrigErr() error { 867 return nil 868} 869 870func (s *{{ $.ShapeName }}) Error() string { 871 {{- if or (and (eq (len $.MemberRefs) 1) (not (index $.MemberRefs "Message_"))) (gt (len $.MemberRefs) 1) }} 872 return fmt.Sprintf("%s: %s\n%s", s.Code(), s.Message(), s.String()) 873 {{- else }} 874 return fmt.Sprintf("%s: %s", s.Code(), s.Message()) 875 {{- end }} 876} 877 878// Status code returns the HTTP status code for the request's response error. 879func (s *{{ $.ShapeName }}) StatusCode() int { 880 return s.RespMetadata.StatusCode 881} 882 883// RequestID returns the service's response RequestID for request. 884func (s *{{ $.ShapeName }}) RequestID() string { 885 return s.RespMetadata.RequestID 886} 887`)) 888 889var enumShapeTmpl = template.Must(template.New("EnumShape").Parse(` 890{{ $.Docstring }} 891const ( 892 {{ range $index, $elem := $.Enum -}} 893 {{ $name := index $.EnumConsts $index -}} 894 // {{ $name }} is a {{ $.ShapeName }} enum value 895 {{ $name }} = "{{ $elem }}" 896 897 {{ end }} 898) 899 900{{/* Enum iterators use non-idomatic _Values suffix to avoid naming collisions with other generated types, and enum values */}} 901// {{ $.ShapeName }}_Values returns all elements of the {{ $.ShapeName }} enum 902func {{ $.ShapeName }}_Values() []string { 903 return []string{ 904 {{ range $index, $elem := $.Enum -}} 905 {{ index $.EnumConsts $index }}, 906 {{ end }} 907 } 908} 909`)) 910 911// GoCode returns the rendered Go code for the Shape. 912func (s *Shape) GoCode() string { 913 w := &bytes.Buffer{} 914 915 switch { 916 case s.IsEventStream: 917 if err := renderEventStreamShape(w, s); err != nil { 918 panic( 919 fmt.Sprintf( 920 "failed to generate eventstream API shape, %s, %v", 921 s.ShapeName, err), 922 ) 923 } 924 case s.Type == "structure": 925 if err := structShapeTmpl.Execute(w, s); err != nil { 926 panic( 927 fmt.Sprintf( 928 "Failed to generate struct shape %s, %v", 929 s.ShapeName, err), 930 ) 931 } 932 case s.IsEnum(): 933 if err := enumShapeTmpl.Execute(w, s); err != nil { 934 panic( 935 fmt.Sprintf( 936 "Failed to generate enum shape %s, %v", 937 s.ShapeName, err), 938 ) 939 } 940 default: 941 panic(fmt.Sprintln("Cannot generate toplevel shape for", s.Type)) 942 } 943 944 return w.String() 945} 946 947// IsEnum returns whether this shape is an enum list 948func (s *Shape) IsEnum() bool { 949 return s.Type == "string" && len(s.Enum) > 0 950} 951 952// IsRequired returns if member is a required field. Required fields are fields 953// marked as required, hostLabels, or location of uri path. 954func (s *Shape) IsRequired(member string) bool { 955 ref, ok := s.MemberRefs[member] 956 if !ok { 957 panic(fmt.Sprintf( 958 "attempted to check required for unknown member, %s.%s", 959 s.ShapeName, member, 960 )) 961 } 962 if ref.IdempotencyToken || ref.Shape.IdempotencyToken { 963 return false 964 } 965 if ref.Location == "uri" || ref.HostLabel { 966 return true 967 } 968 for _, n := range s.Required { 969 if n == member { 970 if ref.Shape.IsEventStream { 971 return false 972 } 973 return true 974 } 975 } 976 return false 977} 978 979// IsInternal returns whether the shape was defined in this package 980func (s *Shape) IsInternal() bool { 981 return s.resolvePkg == "" 982} 983 984// removeRef removes a shape reference from the list of references this 985// shape is used in. 986func (s *Shape) removeRef(ref *ShapeRef) { 987 r := s.refs 988 for i := 0; i < len(r); i++ { 989 if r[i] == ref { 990 j := i + 1 991 copy(r[i:], r[j:]) 992 for k, n := len(r)-j+i, len(r); k < n; k++ { 993 r[k] = nil // free up the end of the list 994 } // for k 995 s.refs = r[:len(r)-j+i] 996 break 997 } 998 } 999} 1000 1001func (s *Shape) WillRefBeBase64Encoded(refName string) bool { 1002 payloadRefName := s.Payload 1003 if payloadRefName == refName { 1004 return false 1005 } 1006 1007 ref, ok := s.MemberRefs[refName] 1008 if !ok { 1009 panic(fmt.Sprintf("shape %s does not contain %q refName", s.ShapeName, refName)) 1010 } 1011 1012 return ref.Shape.Type == "blob" 1013} 1014 1015// Clone returns a cloned version of the shape with all references clones. 1016// 1017// Does not clone EventStream or Validate related values. 1018func (s *Shape) Clone(newName string) *Shape { 1019 if s.AliasedShapeName { 1020 panic(fmt.Sprintf("attempted to clone and rename %s, but flagged as aliased", 1021 s.ShapeName)) 1022 } 1023 1024 n := new(Shape) 1025 *n = *s 1026 1027 debugLogger.Logln("cloning", s.ShapeName, "to", newName) 1028 1029 n.MemberRefs = map[string]*ShapeRef{} 1030 for k, r := range s.MemberRefs { 1031 nr := new(ShapeRef) 1032 *nr = *r 1033 nr.Shape.refs = append(nr.Shape.refs, nr) 1034 n.MemberRefs[k] = nr 1035 } 1036 1037 if n.MemberRef.Shape != nil { 1038 n.MemberRef.Shape.refs = append(n.MemberRef.Shape.refs, &n.MemberRef) 1039 } 1040 if n.KeyRef.Shape != nil { 1041 n.KeyRef.Shape.refs = append(n.KeyRef.Shape.refs, &n.KeyRef) 1042 } 1043 if n.ValueRef.Shape != nil { 1044 n.ValueRef.Shape.refs = append(n.ValueRef.Shape.refs, &n.ValueRef) 1045 } 1046 1047 n.refs = []*ShapeRef{} 1048 1049 n.Required = append([]string{}, n.Required...) 1050 n.Enum = append([]string{}, n.Enum...) 1051 n.EnumConsts = append([]string{}, n.EnumConsts...) 1052 1053 n.API.Shapes[newName] = n 1054 n.ShapeName = newName 1055 n.OrigShapeName = s.OrigShapeName 1056 1057 return n 1058} 1059