document.go (7423B)
1 package document 2 3 import ( 4 "fmt" 5 "math/big" 6 "strconv" 7 "time" 8 ) 9 10 // Marshaler is an interface for a type that marshals a document to its protocol-specific byte representation and 11 // returns the resulting bytes. A non-nil error will be returned if an error is encountered during marshaling. 12 // 13 // Marshal supports basic scalars (int,uint,float,bool,string), big.Int, and big.Float, maps, slices, and structs. 14 // Anonymous nested types are flattened based on Go anonymous type visibility. 15 // 16 // When defining struct types. the `document` struct tag can be used to control how the value will be 17 // marshaled into the resulting protocol document. 18 // 19 // // Field is ignored 20 // Field int `document:"-"` 21 // 22 // // Field object of key "myName" 23 // Field int `document:"myName"` 24 // 25 // // Field object key of key "myName", and 26 // // Field is omitted if the field is a zero value for the type. 27 // Field int `document:"myName,omitempty"` 28 // 29 // // Field object key of "Field", and 30 // // Field is omitted if the field is a zero value for the type. 31 // Field int `document:",omitempty"` 32 // 33 // All struct fields, including anonymous fields, are marshaled unless the 34 // any of the following conditions are meet. 35 // 36 // - the field is not exported 37 // - document field tag is "-" 38 // - document field tag specifies "omitempty", and is a zero value. 39 // 40 // Pointer and interface values are encoded as the value pointed to or 41 // contained in the interface. A nil value encodes as a null 42 // value unless `omitempty` struct tag is provided. 43 // 44 // Channel, complex, and function values are not encoded and will be skipped 45 // when walking the value to be marshaled. 46 // 47 // time.Time is not supported and will cause the Marshaler to return an error. These values should be represented 48 // by your application as a string or numerical representation. 49 // 50 // Errors that occur when marshaling will stop the marshaler, and return the error. 51 // 52 // Marshal cannot represent cyclic data structures and will not handle them. 53 // Passing cyclic structures to Marshal will result in an infinite recursion. 54 // 55 // Marshaler is not used in schema-serde based services (which are currently 56 // being rolled out) since having an implementation of Marshaler locks a 57 // document into support for a specific serial format. Existing implementations 58 // of Marshaler will continue to encode to JSON as that is effectively the only 59 // serial format supported for Document prior to the introduction of 60 // schema-serde. In schema-serde services it is replaced by [Value]. 61 type Marshaler interface { 62 MarshalSmithyDocument() ([]byte, error) 63 } 64 65 // Unmarshaler is an interface for a type that unmarshals a document from its protocol-specific representation, and 66 // stores the result into the value pointed by v. If v is nil or not a pointer then InvalidUnmarshalError will be 67 // returned. 68 // 69 // Unmarshaler supports the same encodings produced by a document Marshaler. This includes support for the `document` 70 // struct field tag for controlling how struct fields are unmarshaled. 71 // 72 // Both generic interface{} and concrete types are valid unmarshal destination types. When unmarshaling a document 73 // into an empty interface the Unmarshaler will store one of these values: 74 // 75 // bool, for boolean values 76 // document.Number, for arbitrary-precision numbers (int64, float64, big.Int, big.Float) 77 // string, for string values 78 // []interface{}, for array values 79 // map[string]interface{}, for objects 80 // nil, for null values 81 // 82 // When unmarshaling, any error that occurs will halt the unmarshal and return the error. 83 type Unmarshaler interface { 84 UnmarshalSmithyDocument(v interface{}) error 85 } 86 87 // Value is a sealed type representing a Smithy document value. It covers the 88 // full Smithy data model including blob and timestamp. 89 // 90 // The following types implement Value: 91 // - [Null] 92 // - [Boolean] 93 // - [Number] 94 // - [String] 95 // - [Blob] 96 // - [Timestamp] 97 // - [List] 98 // - [Map] 99 // - [Structure] 100 // - [Opaque] 101 type Value interface { 102 isValue() 103 } 104 105 // Null is a document null value. 106 type Null struct{} 107 108 func (Null) isValue() {} 109 110 // Boolean is a document boolean value. 111 type Boolean bool 112 113 func (Boolean) isValue() {} 114 115 // String is a document string value. 116 type String string 117 118 func (String) isValue() {} 119 120 // Blob is a document blob value. 121 type Blob []byte 122 123 func (Blob) isValue() {} 124 125 // Timestamp is a document timestamp value. 126 type Timestamp time.Time 127 128 func (Timestamp) isValue() {} 129 130 // List is a document list value. 131 type List []Value 132 133 func (List) isValue() {} 134 135 // Map is a document map value with string keys. 136 type Map map[string]Value 137 138 func (Map) isValue() {} 139 140 // Structure is a document structure value with an optional discriminator 141 // identifying the shape it represents. 142 type Structure struct { 143 // Discriminator is the absolute shape ID (e.g. 144 // "com.example#MyShape") of the concrete type this structure 145 // represents. It may be empty if the type is unknown. 146 Discriminator string 147 148 // Members maps member names to their document values. 149 Members map[string]Value 150 } 151 152 func (Structure) isValue() {} 153 154 // Opaque wraps an arbitrary Go value for backward compatibility with the 155 // legacy reflection-based document serialization path. 156 type Opaque struct { 157 Value any 158 } 159 160 func (Opaque) isValue() {} 161 162 type noSerde interface { 163 noSmithyDocumentSerde() 164 } 165 166 // NoSerde is a sentinel value to indicate that a given type should not be marshaled or unmarshaled 167 // into a protocol document. 168 type NoSerde struct{} 169 170 func (n NoSerde) noSmithyDocumentSerde() {} 171 172 var _ noSerde = (*NoSerde)(nil) 173 174 // IsNoSerde returns whether the given type implements the no smithy document serde interface. 175 func IsNoSerde(x interface{}) bool { 176 _, ok := x.(noSerde) 177 return ok 178 } 179 180 // Number is an arbitrary precision numerical value 181 type Number string 182 183 func (Number) isValue() {} 184 185 // Int64 returns the number as a string. 186 func (n Number) String() string { 187 return string(n) 188 } 189 190 // Int64 returns the number as an int64. 191 func (n Number) Int64() (int64, error) { 192 return n.intOfBitSize(64) 193 } 194 195 func (n Number) intOfBitSize(bitSize int) (int64, error) { 196 return strconv.ParseInt(string(n), 10, bitSize) 197 } 198 199 // Uint64 returns the number as a uint64. 200 func (n Number) Uint64() (uint64, error) { 201 return n.uintOfBitSize(64) 202 } 203 204 func (n Number) uintOfBitSize(bitSize int) (uint64, error) { 205 return strconv.ParseUint(string(n), 10, bitSize) 206 } 207 208 // Float32 returns the number parsed as a 32-bit float, returns a float64. 209 func (n Number) Float32() (float64, error) { 210 return n.floatOfBitSize(32) 211 } 212 213 // Float64 returns the number as a float64. 214 func (n Number) Float64() (float64, error) { 215 return n.floatOfBitSize(64) 216 } 217 218 // Float64 returns the number as a float64. 219 func (n Number) floatOfBitSize(bitSize int) (float64, error) { 220 return strconv.ParseFloat(string(n), bitSize) 221 } 222 223 // BigFloat attempts to convert the number to a big.Float, returns an error if the operation fails. 224 func (n Number) BigFloat() (*big.Float, error) { 225 f, ok := (&big.Float{}).SetString(string(n)) 226 if !ok { 227 return nil, fmt.Errorf("failed to convert to big.Float") 228 } 229 return f, nil 230 } 231 232 // BigInt attempts to convert the number to a big.Int, returns an error if the operation fails. 233 func (n Number) BigInt() (*big.Int, error) { 234 f, ok := (&big.Int{}).SetString(string(n), 10) 235 if !ok { 236 return nil, fmt.Errorf("failed to convert to big.Float") 237 } 238 return f, nil 239 }