code.dwrz.net

Go monorepo.
Log | Files | Refs

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 }