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