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