shape.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. // +build codegen
  2. package api
  3. import (
  4. "bytes"
  5. "fmt"
  6. "path"
  7. "regexp"
  8. "sort"
  9. "strings"
  10. "text/template"
  11. )
  12. // A ShapeRef defines the usage of a shape within the API.
  13. type ShapeRef struct {
  14. API *API `json:"-"`
  15. Shape *Shape `json:"-"`
  16. Documentation string
  17. ShapeName string `json:"shape"`
  18. Location string
  19. LocationName string
  20. QueryName string
  21. Flattened bool
  22. Streaming bool
  23. XMLAttribute bool
  24. // Ignore, if set, will not be sent over the wire
  25. Ignore bool
  26. XMLNamespace XMLInfo
  27. Payload string
  28. IdempotencyToken bool `json:"idempotencyToken"`
  29. JSONValue bool `json:"jsonvalue"`
  30. Deprecated bool `json:"deprecated"`
  31. OrigShapeName string `json:"-"`
  32. GenerateGetter bool
  33. }
  34. // ErrorInfo represents the error block of a shape's structure
  35. type ErrorInfo struct {
  36. Code string
  37. HTTPStatusCode int
  38. }
  39. // A XMLInfo defines URL and prefix for Shapes when rendered as XML
  40. type XMLInfo struct {
  41. Prefix string
  42. URI string
  43. }
  44. // A Shape defines the definition of a shape type
  45. type Shape struct {
  46. API *API `json:"-"`
  47. ShapeName string
  48. Documentation string
  49. MemberRefs map[string]*ShapeRef `json:"members"`
  50. MemberRef ShapeRef `json:"member"`
  51. KeyRef ShapeRef `json:"key"`
  52. ValueRef ShapeRef `json:"value"`
  53. Required []string
  54. Payload string
  55. Type string
  56. Exception bool
  57. Enum []string
  58. EnumConsts []string
  59. Flattened bool
  60. Streaming bool
  61. Location string
  62. LocationName string
  63. IdempotencyToken bool `json:"idempotencyToken"`
  64. XMLNamespace XMLInfo
  65. Min float64 // optional Minimum length (string, list) or value (number)
  66. Max float64 // optional Maximum length (string, list) or value (number)
  67. refs []*ShapeRef // References to this shape
  68. resolvePkg string // use this package in the goType() if present
  69. OrigShapeName string `json:"-"`
  70. // Defines if the shape is a placeholder and should not be used directly
  71. Placeholder bool
  72. Deprecated bool `json:"deprecated"`
  73. Validations ShapeValidations
  74. // Error information that is set if the shape is an error shape.
  75. IsError bool
  76. ErrorInfo ErrorInfo `json:"error"`
  77. }
  78. // ErrorCodeName will return the error shape's name formated for
  79. // error code const.
  80. func (s *Shape) ErrorCodeName() string {
  81. return "ErrCode" + s.ShapeName
  82. }
  83. // ErrorName will return the shape's name or error code if available based
  84. // on the API's protocol. This is the error code string returned by the service.
  85. func (s *Shape) ErrorName() string {
  86. name := s.ShapeName
  87. switch s.API.Metadata.Protocol {
  88. case "query", "ec2query", "rest-xml":
  89. if len(s.ErrorInfo.Code) > 0 {
  90. name = s.ErrorInfo.Code
  91. }
  92. }
  93. return name
  94. }
  95. // GoTags returns the struct tags for a shape.
  96. func (s *Shape) GoTags(root, required bool) string {
  97. ref := &ShapeRef{ShapeName: s.ShapeName, API: s.API, Shape: s}
  98. return ref.GoTags(root, required)
  99. }
  100. // Rename changes the name of the Shape to newName. Also updates
  101. // the associated API's reference to use newName.
  102. func (s *Shape) Rename(newName string) {
  103. for _, r := range s.refs {
  104. r.OrigShapeName = r.ShapeName
  105. r.ShapeName = newName
  106. }
  107. delete(s.API.Shapes, s.ShapeName)
  108. s.OrigShapeName = s.ShapeName
  109. s.API.Shapes[newName] = s
  110. s.ShapeName = newName
  111. }
  112. // MemberNames returns a slice of struct member names.
  113. func (s *Shape) MemberNames() []string {
  114. i, names := 0, make([]string, len(s.MemberRefs))
  115. for n := range s.MemberRefs {
  116. names[i] = n
  117. i++
  118. }
  119. sort.Strings(names)
  120. return names
  121. }
  122. // GoTypeWithPkgName returns a shape's type as a string with the package name in
  123. // <packageName>.<type> format. Package naming only applies to structures.
  124. func (s *Shape) GoTypeWithPkgName() string {
  125. return goType(s, true)
  126. }
  127. func (s *Shape) GoTypeWithPkgNameElem() string {
  128. t := goType(s, true)
  129. if strings.HasPrefix(t, "*") {
  130. return t[1:]
  131. }
  132. return t
  133. }
  134. // GenAccessors returns if the shape's reference should have setters generated.
  135. func (s *ShapeRef) UseIndirection() bool {
  136. switch s.Shape.Type {
  137. case "map", "list", "blob", "structure", "jsonvalue":
  138. return false
  139. }
  140. if s.Streaming || s.Shape.Streaming {
  141. return false
  142. }
  143. if s.JSONValue {
  144. return false
  145. }
  146. return true
  147. }
  148. // GoStructValueType returns the Shape's Go type value instead of a pointer
  149. // for the type.
  150. func (s *Shape) GoStructValueType(name string, ref *ShapeRef) string {
  151. v := s.GoStructType(name, ref)
  152. if ref.UseIndirection() && v[0] == '*' {
  153. return v[1:]
  154. }
  155. return v
  156. }
  157. // GoStructType returns the type of a struct field based on the API
  158. // model definition.
  159. func (s *Shape) GoStructType(name string, ref *ShapeRef) string {
  160. if (ref.Streaming || ref.Shape.Streaming) && s.Payload == name {
  161. rtype := "io.ReadSeeker"
  162. if strings.HasSuffix(s.ShapeName, "Output") {
  163. rtype = "io.ReadCloser"
  164. }
  165. s.API.imports["io"] = true
  166. return rtype
  167. }
  168. if ref.JSONValue {
  169. s.API.imports["github.com/aws/aws-sdk-go/aws"] = true
  170. return "aws.JSONValue"
  171. }
  172. for _, v := range s.Validations {
  173. // TODO move this to shape validation resolution
  174. if (v.Ref.Shape.Type == "map" || v.Ref.Shape.Type == "list") && v.Type == ShapeValidationNested {
  175. s.API.imports["fmt"] = true
  176. }
  177. }
  178. return ref.GoType()
  179. }
  180. // GoType returns a shape's Go type
  181. func (s *Shape) GoType() string {
  182. return goType(s, false)
  183. }
  184. // GoType returns a shape ref's Go type.
  185. func (ref *ShapeRef) GoType() string {
  186. if ref.Shape == nil {
  187. panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
  188. }
  189. return ref.Shape.GoType()
  190. }
  191. // GoTypeWithPkgName returns a shape's type as a string with the package name in
  192. // <packageName>.<type> format. Package naming only applies to structures.
  193. func (ref *ShapeRef) GoTypeWithPkgName() string {
  194. if ref.Shape == nil {
  195. panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
  196. }
  197. return ref.Shape.GoTypeWithPkgName()
  198. }
  199. // Returns a string version of the Shape's type.
  200. // If withPkgName is true, the package name will be added as a prefix
  201. func goType(s *Shape, withPkgName bool) string {
  202. switch s.Type {
  203. case "structure":
  204. if withPkgName || s.resolvePkg != "" {
  205. pkg := s.resolvePkg
  206. if pkg != "" {
  207. s.API.imports[pkg] = true
  208. pkg = path.Base(pkg)
  209. } else {
  210. pkg = s.API.PackageName()
  211. }
  212. return fmt.Sprintf("*%s.%s", pkg, s.ShapeName)
  213. }
  214. return "*" + s.ShapeName
  215. case "map":
  216. return "map[string]" + goType(s.ValueRef.Shape, withPkgName)
  217. case "jsonvalue":
  218. return "aws.JSONValue"
  219. case "list":
  220. return "[]" + goType(s.MemberRef.Shape, withPkgName)
  221. case "boolean":
  222. return "*bool"
  223. case "string", "character":
  224. return "*string"
  225. case "blob":
  226. return "[]byte"
  227. case "integer", "long":
  228. return "*int64"
  229. case "float", "double":
  230. return "*float64"
  231. case "timestamp":
  232. s.API.imports["time"] = true
  233. return "*time.Time"
  234. default:
  235. panic("Unsupported shape type: " + s.Type)
  236. }
  237. }
  238. // GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just
  239. // the type will be returned minus the pointer *.
  240. func (s *Shape) GoTypeElem() string {
  241. t := s.GoType()
  242. if strings.HasPrefix(t, "*") {
  243. return t[1:]
  244. }
  245. return t
  246. }
  247. // GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just
  248. // the type will be returned minus the pointer *.
  249. func (ref *ShapeRef) GoTypeElem() string {
  250. if ref.Shape == nil {
  251. panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
  252. }
  253. return ref.Shape.GoTypeElem()
  254. }
  255. // ShapeTag is a struct tag that will be applied to a shape's generated code
  256. type ShapeTag struct {
  257. Key, Val string
  258. }
  259. // String returns the string representation of the shape tag
  260. func (s ShapeTag) String() string {
  261. return fmt.Sprintf(`%s:"%s"`, s.Key, s.Val)
  262. }
  263. // ShapeTags is a collection of shape tags and provides serialization of the
  264. // tags in an ordered list.
  265. type ShapeTags []ShapeTag
  266. // Join returns an ordered serialization of the shape tags with the provided
  267. // separator.
  268. func (s ShapeTags) Join(sep string) string {
  269. o := &bytes.Buffer{}
  270. for i, t := range s {
  271. o.WriteString(t.String())
  272. if i < len(s)-1 {
  273. o.WriteString(sep)
  274. }
  275. }
  276. return o.String()
  277. }
  278. // String is an alias for Join with the empty space separator.
  279. func (s ShapeTags) String() string {
  280. return s.Join(" ")
  281. }
  282. // GoTags returns the rendered tags string for the ShapeRef
  283. func (ref *ShapeRef) GoTags(toplevel bool, isRequired bool) string {
  284. tags := ShapeTags{}
  285. if ref.Location != "" {
  286. tags = append(tags, ShapeTag{"location", ref.Location})
  287. } else if ref.Shape.Location != "" {
  288. tags = append(tags, ShapeTag{"location", ref.Shape.Location})
  289. }
  290. if ref.LocationName != "" {
  291. tags = append(tags, ShapeTag{"locationName", ref.LocationName})
  292. } else if ref.Shape.LocationName != "" {
  293. tags = append(tags, ShapeTag{"locationName", ref.Shape.LocationName})
  294. }
  295. if ref.QueryName != "" {
  296. tags = append(tags, ShapeTag{"queryName", ref.QueryName})
  297. }
  298. if ref.Shape.MemberRef.LocationName != "" {
  299. tags = append(tags, ShapeTag{"locationNameList", ref.Shape.MemberRef.LocationName})
  300. }
  301. if ref.Shape.KeyRef.LocationName != "" {
  302. tags = append(tags, ShapeTag{"locationNameKey", ref.Shape.KeyRef.LocationName})
  303. }
  304. if ref.Shape.ValueRef.LocationName != "" {
  305. tags = append(tags, ShapeTag{"locationNameValue", ref.Shape.ValueRef.LocationName})
  306. }
  307. if ref.Shape.Min > 0 {
  308. tags = append(tags, ShapeTag{"min", fmt.Sprintf("%v", ref.Shape.Min)})
  309. }
  310. if ref.Deprecated || ref.Shape.Deprecated {
  311. tags = append(tags, ShapeTag{"deprecated", "true"})
  312. }
  313. // All shapes have a type
  314. tags = append(tags, ShapeTag{"type", ref.Shape.Type})
  315. // embed the timestamp type for easier lookups
  316. if ref.Shape.Type == "timestamp" {
  317. t := ShapeTag{Key: "timestampFormat"}
  318. if ref.Location == "header" {
  319. t.Val = "rfc822"
  320. } else {
  321. switch ref.API.Metadata.Protocol {
  322. case "json", "rest-json":
  323. t.Val = "unix"
  324. case "rest-xml", "ec2", "query":
  325. t.Val = "iso8601"
  326. }
  327. }
  328. tags = append(tags, t)
  329. }
  330. if ref.Shape.Flattened || ref.Flattened {
  331. tags = append(tags, ShapeTag{"flattened", "true"})
  332. }
  333. if ref.XMLAttribute {
  334. tags = append(tags, ShapeTag{"xmlAttribute", "true"})
  335. }
  336. if isRequired {
  337. tags = append(tags, ShapeTag{"required", "true"})
  338. }
  339. if ref.Shape.IsEnum() {
  340. tags = append(tags, ShapeTag{"enum", ref.ShapeName})
  341. }
  342. if toplevel {
  343. if ref.Shape.Payload != "" {
  344. tags = append(tags, ShapeTag{"payload", ref.Shape.Payload})
  345. }
  346. }
  347. if ref.XMLNamespace.Prefix != "" {
  348. tags = append(tags, ShapeTag{"xmlPrefix", ref.XMLNamespace.Prefix})
  349. } else if ref.Shape.XMLNamespace.Prefix != "" {
  350. tags = append(tags, ShapeTag{"xmlPrefix", ref.Shape.XMLNamespace.Prefix})
  351. }
  352. if ref.XMLNamespace.URI != "" {
  353. tags = append(tags, ShapeTag{"xmlURI", ref.XMLNamespace.URI})
  354. } else if ref.Shape.XMLNamespace.URI != "" {
  355. tags = append(tags, ShapeTag{"xmlURI", ref.Shape.XMLNamespace.URI})
  356. }
  357. if ref.IdempotencyToken || ref.Shape.IdempotencyToken {
  358. tags = append(tags, ShapeTag{"idempotencyToken", "true"})
  359. }
  360. if ref.Ignore {
  361. tags = append(tags, ShapeTag{"ignore", "true"})
  362. }
  363. return fmt.Sprintf("`%s`", tags)
  364. }
  365. // Docstring returns the godocs formated documentation
  366. func (ref *ShapeRef) Docstring() string {
  367. if ref.Documentation != "" {
  368. return strings.Trim(ref.Documentation, "\n ")
  369. }
  370. return ref.Shape.Docstring()
  371. }
  372. // Docstring returns the godocs formated documentation
  373. func (s *Shape) Docstring() string {
  374. return strings.Trim(s.Documentation, "\n ")
  375. }
  376. // IndentedDocstring is the indented form of the doc string.
  377. func (ref *ShapeRef) IndentedDocstring() string {
  378. doc := ref.Docstring()
  379. return strings.Replace(doc, "// ", "// ", -1)
  380. }
  381. var goCodeStringerTmpl = template.Must(template.New("goCodeStringerTmpl").Parse(`
  382. // String returns the string representation
  383. func (s {{ .ShapeName }}) String() string {
  384. return awsutil.Prettify(s)
  385. }
  386. // GoString returns the string representation
  387. func (s {{ .ShapeName }}) GoString() string {
  388. return s.String()
  389. }
  390. `))
  391. // GoCodeStringers renders the Stringers for API input/output shapes
  392. func (s *Shape) GoCodeStringers() string {
  393. w := bytes.Buffer{}
  394. if err := goCodeStringerTmpl.Execute(&w, s); err != nil {
  395. panic(fmt.Sprintln("Unexpected error executing GoCodeStringers template", err))
  396. }
  397. return w.String()
  398. }
  399. var enumStrip = regexp.MustCompile(`[^a-zA-Z0-9_:\./-]`)
  400. var enumDelims = regexp.MustCompile(`[-_:\./]+`)
  401. var enumCamelCase = regexp.MustCompile(`([a-z])([A-Z])`)
  402. // EnumName returns the Nth enum in the shapes Enum list
  403. func (s *Shape) EnumName(n int) string {
  404. enum := s.Enum[n]
  405. enum = enumStrip.ReplaceAllLiteralString(enum, "")
  406. enum = enumCamelCase.ReplaceAllString(enum, "$1-$2")
  407. parts := enumDelims.Split(enum, -1)
  408. for i, v := range parts {
  409. v = strings.ToLower(v)
  410. parts[i] = ""
  411. if len(v) > 0 {
  412. parts[i] = strings.ToUpper(v[0:1])
  413. }
  414. if len(v) > 1 {
  415. parts[i] += v[1:]
  416. }
  417. }
  418. enum = strings.Join(parts, "")
  419. enum = strings.ToUpper(enum[0:1]) + enum[1:]
  420. return enum
  421. }
  422. // NestedShape returns the shape pointer value for the shape which is nested
  423. // under the current shape. If the shape is not nested nil will be returned.
  424. //
  425. // strucutures, the current shape is returned
  426. // map: the value shape of the map is returned
  427. // list: the element shape of the list is returned
  428. func (s *Shape) NestedShape() *Shape {
  429. var nestedShape *Shape
  430. switch s.Type {
  431. case "structure":
  432. nestedShape = s
  433. case "map":
  434. nestedShape = s.ValueRef.Shape
  435. case "list":
  436. nestedShape = s.MemberRef.Shape
  437. }
  438. return nestedShape
  439. }
  440. var structShapeTmpl = template.Must(template.New("StructShape").Funcs(template.FuncMap{
  441. "GetCrosslinkURL": GetCrosslinkURL,
  442. }).Parse(`
  443. {{ .Docstring }}
  444. {{ if ne $.OrigShapeName "" -}}
  445. {{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.OrigShapeName -}}
  446. {{ if ne $crosslinkURL "" -}}
  447. // Please also see {{ $crosslinkURL }}
  448. {{ end -}}
  449. {{ else -}}
  450. {{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ShapeName -}}
  451. {{ if ne $crosslinkURL "" -}}
  452. // Please also see {{ $crosslinkURL }}
  453. {{ end -}}
  454. {{ end -}}
  455. {{ $context := . -}}
  456. type {{ .ShapeName }} struct {
  457. _ struct{} {{ .GoTags true false }}
  458. {{ range $_, $name := $context.MemberNames -}}
  459. {{ $elem := index $context.MemberRefs $name -}}
  460. {{ $isBlob := $context.WillRefBeBase64Encoded $name -}}
  461. {{ $isRequired := $context.IsRequired $name -}}
  462. {{ $doc := $elem.Docstring -}}
  463. {{ if $doc -}}
  464. {{ $doc }}
  465. {{ end -}}
  466. {{ if $isBlob -}}
  467. {{ if $doc -}}
  468. //
  469. {{ end -}}
  470. // {{ $name }} is automatically base64 encoded/decoded by the SDK.
  471. {{ end -}}
  472. {{ if $isRequired -}}
  473. {{ if or $doc $isBlob -}}
  474. //
  475. {{ end -}}
  476. // {{ $name }} is a required field
  477. {{ end -}}
  478. {{ $name }} {{ $context.GoStructType $name $elem }} {{ $elem.GoTags false $isRequired }}
  479. {{ end }}
  480. }
  481. {{ if not .API.NoStringerMethods }}
  482. {{ .GoCodeStringers }}
  483. {{ end }}
  484. {{ if not .API.NoValidataShapeMethods }}
  485. {{ if .Validations -}}
  486. {{ .Validations.GoCode . }}
  487. {{ end }}
  488. {{ end }}
  489. {{ if not .API.NoGenStructFieldAccessors }}
  490. {{ $builderShapeName := print .ShapeName -}}
  491. {{ range $_, $name := $context.MemberNames -}}
  492. {{ $elem := index $context.MemberRefs $name -}}
  493. // Set{{ $name }} sets the {{ $name }} field's value.
  494. func (s *{{ $builderShapeName }}) Set{{ $name }}(v {{ $context.GoStructValueType $name $elem }}) *{{ $builderShapeName }} {
  495. {{ if $elem.UseIndirection -}}
  496. s.{{ $name }} = &v
  497. {{ else -}}
  498. s.{{ $name }} = v
  499. {{ end -}}
  500. return s
  501. }
  502. {{ if $elem.GenerateGetter -}}
  503. func (s *{{ $builderShapeName }}) get{{ $name }}() (v {{ $context.GoStructValueType $name $elem }}) {
  504. {{ if $elem.UseIndirection -}}
  505. if s.{{ $name }} == nil {
  506. return v
  507. }
  508. return *s.{{ $name }}
  509. {{ else -}}
  510. return s.{{ $name }}
  511. {{ end -}}
  512. }
  513. {{- end }}
  514. {{ end }}
  515. {{ end }}
  516. `))
  517. var enumShapeTmpl = template.Must(template.New("EnumShape").Parse(`
  518. {{ .Docstring }}
  519. const (
  520. {{ $context := . -}}
  521. {{ range $index, $elem := .Enum -}}
  522. {{ $name := index $context.EnumConsts $index -}}
  523. // {{ $name }} is a {{ $context.ShapeName }} enum value
  524. {{ $name }} = "{{ $elem }}"
  525. {{ end }}
  526. )
  527. `))
  528. // GoCode returns the rendered Go code for the Shape.
  529. func (s *Shape) GoCode() string {
  530. b := &bytes.Buffer{}
  531. switch {
  532. case s.Type == "structure":
  533. if err := structShapeTmpl.Execute(b, s); err != nil {
  534. panic(fmt.Sprintf("Failed to generate struct shape %s, %v\n", s.ShapeName, err))
  535. }
  536. case s.IsEnum():
  537. if err := enumShapeTmpl.Execute(b, s); err != nil {
  538. panic(fmt.Sprintf("Failed to generate enum shape %s, %v\n", s.ShapeName, err))
  539. }
  540. default:
  541. panic(fmt.Sprintln("Cannot generate toplevel shape for", s.Type))
  542. }
  543. return b.String()
  544. }
  545. // IsEnum returns whether this shape is an enum list
  546. func (s *Shape) IsEnum() bool {
  547. return s.Type == "string" && len(s.Enum) > 0
  548. }
  549. // IsRequired returns if member is a required field.
  550. func (s *Shape) IsRequired(member string) bool {
  551. for _, n := range s.Required {
  552. if n == member {
  553. return true
  554. }
  555. }
  556. return false
  557. }
  558. // IsInternal returns whether the shape was defined in this package
  559. func (s *Shape) IsInternal() bool {
  560. return s.resolvePkg == ""
  561. }
  562. // removeRef removes a shape reference from the list of references this
  563. // shape is used in.
  564. func (s *Shape) removeRef(ref *ShapeRef) {
  565. r := s.refs
  566. for i := 0; i < len(r); i++ {
  567. if r[i] == ref {
  568. j := i + 1
  569. copy(r[i:], r[j:])
  570. for k, n := len(r)-j+i, len(r); k < n; k++ {
  571. r[k] = nil // free up the end of the list
  572. } // for k
  573. s.refs = r[:len(r)-j+i]
  574. break
  575. }
  576. }
  577. }
  578. func (s *Shape) WillRefBeBase64Encoded(refName string) bool {
  579. payloadRefName := s.Payload
  580. if payloadRefName == refName {
  581. return false
  582. }
  583. ref, ok := s.MemberRefs[refName]
  584. if !ok {
  585. panic(fmt.Sprintf("shape %s does not contain %q refName", s.ShapeName, refName))
  586. }
  587. return ref.Shape.Type == "blob"
  588. }