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