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