shape.go 23 KB

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