document.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package document
  2. import (
  3. "fmt"
  4. "math/big"
  5. "strconv"
  6. )
  7. // Marshaler is an interface for a type that marshals a document to its protocol-specific byte representation and
  8. // returns the resulting bytes. A non-nil error will be returned if an error is encountered during marshaling.
  9. //
  10. // Marshal supports basic scalars (int,uint,float,bool,string), big.Int, and big.Float, maps, slices, and structs.
  11. // Anonymous nested types are flattened based on Go anonymous type visibility.
  12. //
  13. // When defining struct types. the `document` struct tag can be used to control how the value will be
  14. // marshaled into the resulting protocol document.
  15. //
  16. // // Field is ignored
  17. // Field int `document:"-"`
  18. //
  19. // // Field object of key "myName"
  20. // Field int `document:"myName"`
  21. //
  22. // // Field object key of key "myName", and
  23. // // Field is omitted if the field is a zero value for the type.
  24. // Field int `document:"myName,omitempty"`
  25. //
  26. // // Field object key of "Field", and
  27. // // Field is omitted if the field is a zero value for the type.
  28. // Field int `document:",omitempty"`
  29. //
  30. // All struct fields, including anonymous fields, are marshaled unless the
  31. // any of the following conditions are meet.
  32. //
  33. // - the field is not exported
  34. // - document field tag is "-"
  35. // - document field tag specifies "omitempty", and is a zero value.
  36. //
  37. // Pointer and interface values are encoded as the value pointed to or
  38. // contained in the interface. A nil value encodes as a null
  39. // value unless `omitempty` struct tag is provided.
  40. //
  41. // Channel, complex, and function values are not encoded and will be skipped
  42. // when walking the value to be marshaled.
  43. //
  44. // time.Time is not supported and will cause the Marshaler to return an error. These values should be represented
  45. // by your application as a string or numerical representation.
  46. //
  47. // Errors that occur when marshaling will stop the marshaler, and return the error.
  48. //
  49. // Marshal cannot represent cyclic data structures and will not handle them.
  50. // Passing cyclic structures to Marshal will result in an infinite recursion.
  51. type Marshaler interface {
  52. MarshalSmithyDocument() ([]byte, error)
  53. }
  54. // Unmarshaler is an interface for a type that unmarshals a document from its protocol-specific representation, and
  55. // stores the result into the value pointed by v. If v is nil or not a pointer then InvalidUnmarshalError will be
  56. // returned.
  57. //
  58. // Unmarshaler supports the same encodings produced by a document Marshaler. This includes support for the `document`
  59. // struct field tag for controlling how struct fields are unmarshaled.
  60. //
  61. // Both generic interface{} and concrete types are valid unmarshal destination types. When unmarshaling a document
  62. // into an empty interface the Unmarshaler will store one of these values:
  63. // bool, for boolean values
  64. // document.Number, for arbitrary-precision numbers (int64, float64, big.Int, big.Float)
  65. // string, for string values
  66. // []interface{}, for array values
  67. // map[string]interface{}, for objects
  68. // nil, for null values
  69. //
  70. // When unmarshaling, any error that occurs will halt the unmarshal and return the error.
  71. type Unmarshaler interface {
  72. UnmarshalSmithyDocument(v interface{}) error
  73. }
  74. type noSerde interface {
  75. noSmithyDocumentSerde()
  76. }
  77. // NoSerde is a sentinel value to indicate that a given type should not be marshaled or unmarshaled
  78. // into a protocol document.
  79. type NoSerde struct{}
  80. func (n NoSerde) noSmithyDocumentSerde() {}
  81. var _ noSerde = (*NoSerde)(nil)
  82. // IsNoSerde returns whether the given type implements the no smithy document serde interface.
  83. func IsNoSerde(x interface{}) bool {
  84. _, ok := x.(noSerde)
  85. return ok
  86. }
  87. // Number is an arbitrary precision numerical value
  88. type Number string
  89. // Int64 returns the number as a string.
  90. func (n Number) String() string {
  91. return string(n)
  92. }
  93. // Int64 returns the number as an int64.
  94. func (n Number) Int64() (int64, error) {
  95. return n.intOfBitSize(64)
  96. }
  97. func (n Number) intOfBitSize(bitSize int) (int64, error) {
  98. return strconv.ParseInt(string(n), 10, bitSize)
  99. }
  100. // Uint64 returns the number as a uint64.
  101. func (n Number) Uint64() (uint64, error) {
  102. return n.uintOfBitSize(64)
  103. }
  104. func (n Number) uintOfBitSize(bitSize int) (uint64, error) {
  105. return strconv.ParseUint(string(n), 10, bitSize)
  106. }
  107. // Float32 returns the number parsed as a 32-bit float, returns a float64.
  108. func (n Number) Float32() (float64, error) {
  109. return n.floatOfBitSize(32)
  110. }
  111. // Float64 returns the number as a float64.
  112. func (n Number) Float64() (float64, error) {
  113. return n.floatOfBitSize(64)
  114. }
  115. // Float64 returns the number as a float64.
  116. func (n Number) floatOfBitSize(bitSize int) (float64, error) {
  117. return strconv.ParseFloat(string(n), bitSize)
  118. }
  119. // BigFloat attempts to convert the number to a big.Float, returns an error if the operation fails.
  120. func (n Number) BigFloat() (*big.Float, error) {
  121. f, ok := (&big.Float{}).SetString(string(n))
  122. if !ok {
  123. return nil, fmt.Errorf("failed to convert to big.Float")
  124. }
  125. return f, nil
  126. }
  127. // BigInt attempts to convert the number to a big.Int, returns an error if the operation fails.
  128. func (n Number) BigInt() (*big.Int, error) {
  129. f, ok := (&big.Int{}).SetString(string(n), 10)
  130. if !ok {
  131. return nil, fmt.Errorf("failed to convert to big.Float")
  132. }
  133. return f, nil
  134. }