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 }
154