github.com/aavshr/aws-sdk-go@v1.41.3/private/model/api/shape.go (about)

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