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