package attributevalue import ( "encoding" "fmt" "reflect" "strconv" "time" "github.com/aws/aws-sdk-go-v2/service/dynamodbstreams/types" ) // An Unmarshaler is an interface to provide custom unmarshaling of // AttributeValues. Use this to provide custom logic determining // how AttributeValues should be unmarshaled. // // type ExampleUnmarshaler struct { // Value int // } // // func (u *ExampleUnmarshaler) UnmarshalDynamoDBStreamsAttributeValue(av types.AttributeValue) error { // avN, ok := av.(*types.AttributeValueMemberN) // if !ok { // return nil // } // // n, err := strconv.ParseInt(avN.Value, 10, 0) // if err != nil { // return err // } // // u.Value = int(n) // return nil // } type Unmarshaler interface { UnmarshalDynamoDBStreamsAttributeValue(types.AttributeValue) error } // Unmarshal will unmarshal AttributeValues to Go value types. // Both generic interface{} and concrete types are valid unmarshal // destination types. // // Unmarshal will allocate maps, slices, and pointers as needed to // unmarshal the AttributeValue into the provided type value. // // When unmarshaling AttributeValues into structs Unmarshal matches // the field names of the struct to the AttributeValue Map keys. // Initially it will look for exact field name matching, but will // fall back to case insensitive if not exact match is found. // // With the exception of omitempty, omitemptyelem, binaryset, numberset // and stringset all struct tags used by Marshal are also used by // Unmarshal. // // When decoding AttributeValues to interfaces Unmarshal will use the // following types. // // []byte, AV Binary (B) // [][]byte, AV Binary Set (BS) // bool, AV Boolean (BOOL) // []interface{}, AV List (L) // map[string]interface{}, AV Map (M) // float64, AV Number (N) // Number, AV Number (N) with UseNumber set // []float64, AV Number Set (NS) // []Number, AV Number Set (NS) with UseNumber set // string, AV String (S) // []string, AV String Set (SS) // // If the Decoder option, UseNumber is set numbers will be unmarshaled // as Number values instead of float64. Use this to maintain the original // string formating of the number as it was represented in the AttributeValue. // In addition provides additional opportunities to parse the number // string based on individual use cases. // // When unmarshaling any error that occurs will halt the unmarshal // and return the error. // // The output value provided must be a non-nil pointer func Unmarshal(av types.AttributeValue, out interface{}) error { return NewDecoder().Decode(av, out) } // UnmarshalWithOptions will unmarshal AttributeValues to Go value types. // Both generic interface{} and concrete types are valid unmarshal // destination types. // // Use the `optsFns` functional options to override the default configuration. // // UnmarshalWithOptions will allocate maps, slices, and pointers as needed to // unmarshal the AttributeValue into the provided type value. // // When unmarshaling AttributeValues into structs Unmarshal matches // the field names of the struct to the AttributeValue Map keys. // Initially it will look for exact field name matching, but will // fall back to case insensitive if not exact match is found. // // With the exception of omitempty, omitemptyelem, binaryset, numberset // and stringset all struct tags used by Marshal are also used by // UnmarshalWithOptions. // // When decoding AttributeValues to interfaces Unmarshal will use the // following types. // // []byte, AV Binary (B) // [][]byte, AV Binary Set (BS) // bool, AV Boolean (BOOL) // []interface{}, AV List (L) // map[string]interface{}, AV Map (M) // float64, AV Number (N) // Number, AV Number (N) with UseNumber set // []float64, AV Number Set (NS) // []Number, AV Number Set (NS) with UseNumber set // string, AV String (S) // []string, AV String Set (SS) // // If the Decoder option, UseNumber is set numbers will be unmarshaled // as Number values instead of float64. Use this to maintain the original // string formating of the number as it was represented in the AttributeValue. // In addition provides additional opportunities to parse the number // string based on individual use cases. // // When unmarshaling any error that occurs will halt the unmarshal // and return the error. // // The output value provided must be a non-nil pointer func UnmarshalWithOptions(av types.AttributeValue, out interface{}, optFns ...func(options *DecoderOptions)) error { return NewDecoder(optFns...).Decode(av, out) } // UnmarshalMap is an alias for Unmarshal which unmarshals from // a map of AttributeValues. // // The output value provided must be a non-nil pointer func UnmarshalMap(m map[string]types.AttributeValue, out interface{}) error { return NewDecoder().Decode(&types.AttributeValueMemberM{Value: m}, out) } // UnmarshalMapWithOptions is an alias for UnmarshalWithOptions which unmarshals from // a map of AttributeValues. // // Use the `optsFns` functional options to override the default configuration. // // The output value provided must be a non-nil pointer func UnmarshalMapWithOptions(m map[string]types.AttributeValue, out interface{}, optFns ...func(options *DecoderOptions)) error { return NewDecoder(optFns...).Decode(&types.AttributeValueMemberM{Value: m}, out) } // UnmarshalList is an alias for Unmarshal func which unmarshals // a slice of AttributeValues. // // The output value provided must be a non-nil pointer func UnmarshalList(l []types.AttributeValue, out interface{}) error { return NewDecoder().Decode(&types.AttributeValueMemberL{Value: l}, out) } // UnmarshalListWithOptions is an alias for UnmarshalWithOptions func which unmarshals // a slice of AttributeValues. // // Use the `optsFns` functional options to override the default configuration. // // The output value provided must be a non-nil pointer func UnmarshalListWithOptions(l []types.AttributeValue, out interface{}, optFns ...func(options *DecoderOptions)) error { return NewDecoder(optFns...).Decode(&types.AttributeValueMemberL{Value: l}, out) } // UnmarshalListOfMaps is an alias for Unmarshal func which unmarshals a // slice of maps of attribute values. // // This is useful for when you need to unmarshal the Items from a Query API // call. // // The output value provided must be a non-nil pointer func UnmarshalListOfMaps(l []map[string]types.AttributeValue, out interface{}) error { items := make([]types.AttributeValue, len(l)) for i, m := range l { items[i] = &types.AttributeValueMemberM{Value: m} } return UnmarshalList(items, out) } // UnmarshalListOfMapsWithOptions is an alias for UnmarshalWithOptions func which unmarshals a // slice of maps of attribute values. // // Use the `optsFns` functional options to override the default configuration. // // This is useful for when you need to unmarshal the Items from a Query API // call. // // The output value provided must be a non-nil pointer func UnmarshalListOfMapsWithOptions(l []map[string]types.AttributeValue, out interface{}, optFns ...func(options *DecoderOptions)) error { items := make([]types.AttributeValue, len(l)) for i, m := range l { items[i] = &types.AttributeValueMemberM{Value: m} } return UnmarshalListWithOptions(items, out, optFns...) } // DecodeTimeAttributes is the set of time decoding functions for different AttributeValues. type DecodeTimeAttributes struct { // Will decode S attribute values and SS attribute value elements into time.Time // // Default string parsing format is time.RFC3339 S func(string) (time.Time, error) // Will decode N attribute values and NS attribute value elements into time.Time // // Default number parsing format is seconds since January 1, 1970 UTC N func(string) (time.Time, error) } // DecoderOptions is a collection of options to configure how the decoder // unmarshals the value. type DecoderOptions struct { // Support other custom struct tag keys, such as `yaml`, `json`, or `toml`. // Note that values provided with a custom TagKey must also be supported // by the (un)marshalers in this package. // // Tag key `dynamodbav` will always be read, but if custom tag key // conflicts with `dynamodbav` the custom tag key value will be used. TagKey string // Instructs the decoder to decode AttributeValue Numbers as // Number type instead of float64 when the destination type // is interface{}. Similar to encoding/json.Number UseNumber bool // Contains the time decoding functions for different AttributeValues // // Default string parsing format is time.RFC3339 // Default number parsing format is seconds since January 1, 1970 UTC DecodeTime DecodeTimeAttributes } // A Decoder provides unmarshaling AttributeValues to Go value types. type Decoder struct { options DecoderOptions } // NewDecoder creates a new Decoder with default configuration. Use // the `opts` functional options to override the default configuration. func NewDecoder(optFns ...func(*DecoderOptions)) *Decoder { options := DecoderOptions{ TagKey: defaultTagKey, DecodeTime: DecodeTimeAttributes{ S: defaultDecodeTimeS, N: defaultDecodeTimeN, }, } for _, fn := range optFns { fn(&options) } if options.DecodeTime.S == nil { options.DecodeTime.S = defaultDecodeTimeS } if options.DecodeTime.N == nil { options.DecodeTime.N = defaultDecodeTimeN } return &Decoder{ options: options, } } // Decode will unmarshal an AttributeValue into a Go value type. An error // will be return if the decoder is unable to unmarshal the AttributeValue // to the provide Go value type. // // The output value provided must be a non-nil pointer func (d *Decoder) Decode(av types.AttributeValue, out interface{}, opts ...func(*Decoder)) error { v := reflect.ValueOf(out) if v.Kind() != reflect.Ptr || v.IsNil() || !v.IsValid() { return &InvalidUnmarshalError{Type: reflect.TypeOf(out)} } return d.decode(av, v, tag{}) } var stringInterfaceMapType = reflect.TypeOf(map[string]interface{}(nil)) var byteSliceType = reflect.TypeOf([]byte(nil)) var byteSliceSliceType = reflect.TypeOf([][]byte(nil)) var timeType = reflect.TypeOf(time.Time{}) func (d *Decoder) decode(av types.AttributeValue, v reflect.Value, fieldTag tag) error { var u Unmarshaler _, isNull := av.(*types.AttributeValueMemberNULL) if av == nil || isNull { u, v = indirect(v, indirectOptions{decodeNull: true}) if u != nil { return u.UnmarshalDynamoDBStreamsAttributeValue(av) } return d.decodeNull(v) } u, v = indirect(v, indirectOptions{}) if u != nil { return u.UnmarshalDynamoDBStreamsAttributeValue(av) } switch tv := av.(type) { case *types.AttributeValueMemberB: return d.decodeBinary(tv.Value, v) case *types.AttributeValueMemberBOOL: return d.decodeBool(tv.Value, v) case *types.AttributeValueMemberBS: return d.decodeBinarySet(tv.Value, v) case *types.AttributeValueMemberL: return d.decodeList(tv.Value, v) case *types.AttributeValueMemberM: return d.decodeMap(tv.Value, v) case *types.AttributeValueMemberN: return d.decodeNumber(tv.Value, v, fieldTag) case *types.AttributeValueMemberNS: return d.decodeNumberSet(tv.Value, v) case *types.AttributeValueMemberS: return d.decodeString(tv.Value, v, fieldTag) case *types.AttributeValueMemberSS: return d.decodeStringSet(tv.Value, v) default: return fmt.Errorf("unsupported AttributeValue type, %T", av) } } func (d *Decoder) decodeBinary(b []byte, v reflect.Value) error { if v.Kind() == reflect.Interface { buf := make([]byte, len(b)) copy(buf, b) v.Set(reflect.ValueOf(buf)) return nil } if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { return &UnmarshalTypeError{Value: "binary", Type: v.Type()} } if v.Type() == byteSliceType { // Optimization for []byte types if v.IsNil() || v.Cap() < len(b) { v.Set(reflect.MakeSlice(byteSliceType, len(b), len(b))) } else if v.Len() != len(b) { v.SetLen(len(b)) } copy(v.Interface().([]byte), b) return nil } switch v.Type().Elem().Kind() { case reflect.Uint8: // Fallback to reflection copy for type aliased of []byte type if v.Kind() != reflect.Array && (v.IsNil() || v.Cap() < len(b)) { v.Set(reflect.MakeSlice(v.Type(), len(b), len(b))) } else if v.Len() != len(b) { v.SetLen(len(b)) } for i := 0; i < len(b); i++ { v.Index(i).SetUint(uint64(b[i])) } default: if v.Kind() == reflect.Array && v.Type().Elem().Kind() == reflect.Uint8 { reflect.Copy(v, reflect.ValueOf(b)) break } return &UnmarshalTypeError{Value: "binary", Type: v.Type()} } return nil } func (d *Decoder) decodeBool(b bool, v reflect.Value) error { switch v.Kind() { case reflect.Bool, reflect.Interface: v.Set(reflect.ValueOf(b).Convert(v.Type())) default: return &UnmarshalTypeError{Value: "bool", Type: v.Type()} } return nil } func (d *Decoder) decodeBinarySet(bs [][]byte, v reflect.Value) error { var isArray bool switch v.Kind() { case reflect.Slice: // Make room for the slice elements if needed if v.IsNil() || v.Cap() < len(bs) { // What about if ignoring nil/empty values? v.Set(reflect.MakeSlice(v.Type(), 0, len(bs))) } case reflect.Array: // Limited to capacity of existing array. isArray = true case reflect.Interface: set := make([][]byte, len(bs)) for i, b := range bs { if err := d.decodeBinary(b, reflect.ValueOf(&set[i]).Elem()); err != nil { return err } } v.Set(reflect.ValueOf(set)) return nil default: return &UnmarshalTypeError{Value: "binary set", Type: v.Type()} } for i := 0; i < v.Cap() && i < len(bs); i++ { if !isArray { v.SetLen(i + 1) } u, elem := indirect(v.Index(i), indirectOptions{}) if u != nil { return u.UnmarshalDynamoDBStreamsAttributeValue(&types.AttributeValueMemberBS{Value: bs}) } if err := d.decodeBinary(bs[i], elem); err != nil { return err } } return nil } func (d *Decoder) decodeNumber(n string, v reflect.Value, fieldTag tag) error { switch v.Kind() { case reflect.Interface: i, err := d.decodeNumberToInterface(n) if err != nil { return err } v.Set(reflect.ValueOf(i)) return nil case reflect.String: if isNumberValueType(v) { v.SetString(n) return nil } v.SetString(n) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: i, err := strconv.ParseInt(n, 10, 64) if err != nil { return err } if v.OverflowInt(i) { return &UnmarshalTypeError{ Value: fmt.Sprintf("number overflow, %s", n), Type: v.Type(), } } v.SetInt(i) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: i, err := strconv.ParseUint(n, 10, 64) if err != nil { return err } if v.OverflowUint(i) { return &UnmarshalTypeError{ Value: fmt.Sprintf("number overflow, %s", n), Type: v.Type(), } } v.SetUint(i) case reflect.Float32, reflect.Float64: i, err := strconv.ParseFloat(n, 64) if err != nil { return err } if v.OverflowFloat(i) { return &UnmarshalTypeError{ Value: fmt.Sprintf("number overflow, %s", n), Type: v.Type(), } } v.SetFloat(i) default: if v.Type().ConvertibleTo(timeType) && fieldTag.AsUnixTime { t, err := decodeUnixTime(n) if err != nil { return err } v.Set(reflect.ValueOf(t).Convert(v.Type())) return nil } if v.Type().ConvertibleTo(timeType) { t, err := d.options.DecodeTime.N(n) if err != nil { return err } v.Set(reflect.ValueOf(t).Convert(v.Type())) return nil } return &UnmarshalTypeError{Value: "number", Type: v.Type()} } return nil } func (d *Decoder) decodeNumberToInterface(n string) (interface{}, error) { if d.options.UseNumber { return Number(n), nil } // Default to float64 for all numbers return strconv.ParseFloat(n, 64) } func (d *Decoder) decodeNumberSet(ns []string, v reflect.Value) error { var isArray bool switch v.Kind() { case reflect.Slice: // Make room for the slice elements if needed if v.IsNil() || v.Cap() < len(ns) { // What about if ignoring nil/empty values? v.Set(reflect.MakeSlice(v.Type(), 0, len(ns))) } case reflect.Array: // Limited to capacity of existing array. isArray = true case reflect.Interface: if d.options.UseNumber { set := make([]Number, len(ns)) for i, n := range ns { if err := d.decodeNumber(n, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil { return err } } v.Set(reflect.ValueOf(set)) } else { set := make([]float64, len(ns)) for i, n := range ns { if err := d.decodeNumber(n, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil { return err } } v.Set(reflect.ValueOf(set)) } return nil default: return &UnmarshalTypeError{Value: "number set", Type: v.Type()} } for i := 0; i < v.Cap() && i < len(ns); i++ { if !isArray { v.SetLen(i + 1) } u, elem := indirect(v.Index(i), indirectOptions{}) if u != nil { return u.UnmarshalDynamoDBStreamsAttributeValue(&types.AttributeValueMemberNS{Value: ns}) } if err := d.decodeNumber(ns[i], elem, tag{}); err != nil { return err } } return nil } func (d *Decoder) decodeList(avList []types.AttributeValue, v reflect.Value) error { var isArray bool switch v.Kind() { case reflect.Slice: // Make room for the slice elements if needed if v.IsNil() || v.Cap() < len(avList) { // What about if ignoring nil/empty values? v.Set(reflect.MakeSlice(v.Type(), 0, len(avList))) } case reflect.Array: // Limited to capacity of existing array. isArray = true case reflect.Interface: s := make([]interface{}, len(avList)) for i, av := range avList { if err := d.decode(av, reflect.ValueOf(&s[i]).Elem(), tag{}); err != nil { return err } } v.Set(reflect.ValueOf(s)) return nil default: return &UnmarshalTypeError{Value: "list", Type: v.Type()} } // If v is not a slice, array for i := 0; i < v.Cap() && i < len(avList); i++ { if !isArray { v.SetLen(i + 1) } if err := d.decode(avList[i], v.Index(i), tag{}); err != nil { return err } } return nil } func (d *Decoder) decodeMap(avMap map[string]types.AttributeValue, v reflect.Value) (err error) { var decodeMapKey func(v string, key reflect.Value, fieldTag tag) error switch v.Kind() { case reflect.Map: decodeMapKey, err = d.getMapKeyDecoder(v.Type().Key()) if err != nil { return err } if v.IsNil() { v.Set(reflect.MakeMap(v.Type())) } case reflect.Struct: case reflect.Interface: v.Set(reflect.MakeMap(stringInterfaceMapType)) decodeMapKey = d.decodeString v = v.Elem() default: return &UnmarshalTypeError{Value: "map", Type: v.Type()} } if v.Kind() == reflect.Map { keyType := v.Type().Key() valueType := v.Type().Elem() for k, av := range avMap { key := reflect.New(keyType).Elem() // handle pointer keys _, indirectKey := indirect(key, indirectOptions{skipUnmarshaler: true}) if err := decodeMapKey(k, indirectKey, tag{}); err != nil { return &UnmarshalTypeError{ Value: fmt.Sprintf("map key %q", k), Type: keyType, Err: err, } } elem := reflect.New(valueType).Elem() if err := d.decode(av, elem, tag{}); err != nil { return err } v.SetMapIndex(key, elem) } } else if v.Kind() == reflect.Struct { fields := unionStructFields(v.Type(), structFieldOptions{ TagKey: d.options.TagKey, }) for k, av := range avMap { if f, ok := fields.FieldByName(k); ok { fv := decoderFieldByIndex(v, f.Index) if err := d.decode(av, fv, f.tag); err != nil { return err } } } } return nil } var numberType = reflect.TypeOf(Number("")) var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() func (d *Decoder) getMapKeyDecoder(keyType reflect.Type) (func(string, reflect.Value, tag) error, error) { // Test the key type to determine if it implements the TextUnmarshaler interface. if reflect.PtrTo(keyType).Implements(textUnmarshalerType) || keyType.Implements(textUnmarshalerType) { return func(v string, k reflect.Value, _ tag) error { if !k.CanAddr() { return fmt.Errorf("cannot take address of map key, %v", k.Type()) } return k.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(v)) }, nil } var decodeMapKey func(v string, key reflect.Value, fieldTag tag) error switch keyType.Kind() { case reflect.Bool: decodeMapKey = func(v string, key reflect.Value, fieldTag tag) error { b, err := strconv.ParseBool(v) if err != nil { return err } return d.decodeBool(b, key) } case reflect.String: // Number type handled as a string decodeMapKey = d.decodeString case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: decodeMapKey = d.decodeNumber default: return nil, &UnmarshalTypeError{ Value: "map key must be string, number, bool, or TextUnmarshaler", Type: keyType, } } return decodeMapKey, nil } func (d *Decoder) decodeNull(v reflect.Value) error { if v.IsValid() && v.CanSet() { v.Set(reflect.Zero(v.Type())) } return nil } func (d *Decoder) decodeString(s string, v reflect.Value, fieldTag tag) error { if fieldTag.AsString { return d.decodeNumber(s, v, fieldTag) } // To maintain backwards compatibility with ConvertFrom family of methods which // converted strings to time.Time structs if v.Type().ConvertibleTo(timeType) { t, err := d.options.DecodeTime.S(s) if err != nil { return err } v.Set(reflect.ValueOf(t).Convert(v.Type())) return nil } switch v.Kind() { case reflect.String: v.SetString(s) case reflect.Interface: // Ensure type aliasing is handled properly v.Set(reflect.ValueOf(s).Convert(v.Type())) default: return &UnmarshalTypeError{Value: "string", Type: v.Type()} } return nil } func (d *Decoder) decodeStringSet(ss []string, v reflect.Value) error { var isArray bool switch v.Kind() { case reflect.Slice: // Make room for the slice elements if needed if v.IsNil() || v.Cap() < len(ss) { v.Set(reflect.MakeSlice(v.Type(), 0, len(ss))) } case reflect.Array: // Limited to capacity of existing array. isArray = true case reflect.Interface: set := make([]string, len(ss)) for i, s := range ss { if err := d.decodeString(s, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil { return err } } v.Set(reflect.ValueOf(set)) return nil default: return &UnmarshalTypeError{Value: "string set", Type: v.Type()} } for i := 0; i < v.Cap() && i < len(ss); i++ { if !isArray { v.SetLen(i + 1) } u, elem := indirect(v.Index(i), indirectOptions{}) if u != nil { return u.UnmarshalDynamoDBStreamsAttributeValue(&types.AttributeValueMemberSS{Value: ss}) } if err := d.decodeString(ss[i], elem, tag{}); err != nil { return err } } return nil } func decodeUnixTime(n string) (time.Time, error) { v, err := strconv.ParseInt(n, 10, 64) if err != nil { return time.Time{}, &UnmarshalError{ Err: err, Value: n, Type: timeType, } } return time.Unix(v, 0), nil } // decoderFieldByIndex finds the field with the provided nested index, allocating // embedded parent structs if needed func decoderFieldByIndex(v reflect.Value, index []int) reflect.Value { for i, x := range index { if i > 0 && v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct { if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() } v = v.Field(x) } return v } type indirectOptions struct { decodeNull bool skipUnmarshaler bool } // indirect will walk a value's interface or pointer value types. Returning // the final value or the value a unmarshaler is defined on. // // Based on the enoding/json type reflect value type indirection in Go Stdlib // https://golang.org/src/encoding/json/decode.go indirect func. func indirect(v reflect.Value, opts indirectOptions) (Unmarshaler, reflect.Value) { // Issue #24153 indicates that it is generally not a guaranteed property // that you may round-trip a reflect.Value by calling Value.Addr().Elem() // and expect the value to still be settable for values derived from // unexported embedded struct fields. // // The logic below effectively does this when it first addresses the value // (to satisfy possible pointer methods) and continues to dereference // subsequent pointers as necessary. // // After the first round-trip, we set v back to the original value to // preserve the original RW flags contained in reflect.Value. v0 := v haveAddr := false // If v is a named type and is addressable, // start with its address, so that if the type has pointer methods, // we find them. if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { haveAddr = true v = v.Addr() } for { // Load value from interface, but only if the result will be // usefully addressable. if v.Kind() == reflect.Interface && !v.IsNil() { e := v.Elem() if e.Kind() == reflect.Ptr && !e.IsNil() && (!opts.decodeNull || e.Elem().Kind() == reflect.Ptr) { haveAddr = false v = e continue } if e.Kind() != reflect.Ptr && e.IsValid() { return nil, e } } if v.Kind() != reflect.Ptr { break } if opts.decodeNull && v.CanSet() { break } // Prevent infinite loop if v is an interface pointing to its own address: // var v interface{} // v = &v if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { v = v.Elem() break } if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } if !opts.skipUnmarshaler && v.Type().NumMethod() > 0 && v.CanInterface() { if u, ok := v.Interface().(Unmarshaler); ok { return u, reflect.Value{} } } if haveAddr { v = v0 // restore original value after round-trip Value.Addr().Elem() haveAddr = false } else { v = v.Elem() } } return nil, v } // A Number represents a Attributevalue number literal. type Number string // Float64 attempts to cast the number to a float64, returning // the result of the case or error if the case failed. func (n Number) Float64() (float64, error) { return strconv.ParseFloat(string(n), 64) } // Int64 attempts to cast the number to a int64, returning // the result of the case or error if the case failed. func (n Number) Int64() (int64, error) { return strconv.ParseInt(string(n), 10, 64) } // Uint64 attempts to cast the number to a uint64, returning // the result of the case or error if the case failed. func (n Number) Uint64() (uint64, error) { return strconv.ParseUint(string(n), 10, 64) } // String returns the raw number represented as a string func (n Number) String() string { return string(n) } // An UnmarshalTypeError is an error type representing a error // unmarshaling the AttributeValue's element to a Go value type. // Includes details about the AttributeValue type and Go value type. type UnmarshalTypeError struct { Value string Type reflect.Type Err error } // Unwrap returns the underlying error if any. func (e *UnmarshalTypeError) Unwrap() error { return e.Err } // Error returns the string representation of the error. // satisfying the error interface func (e *UnmarshalTypeError) Error() string { return fmt.Sprintf("unmarshal failed, cannot unmarshal %s into Go value type %s", e.Value, e.Type.String()) } // An InvalidUnmarshalError is an error type representing an invalid type // encountered while unmarshaling a AttributeValue to a Go value type. type InvalidUnmarshalError struct { Type reflect.Type } // Error returns the string representation of the error. // satisfying the error interface func (e *InvalidUnmarshalError) Error() string { var msg string if e.Type == nil { msg = "cannot unmarshal to nil value" } else if e.Type.Kind() != reflect.Ptr { msg = fmt.Sprintf("cannot unmarshal to non-pointer value, got %s", e.Type.String()) } else { msg = fmt.Sprintf("cannot unmarshal to nil value, %s", e.Type.String()) } return fmt.Sprintf("unmarshal failed, %s", msg) } // An UnmarshalError wraps an error that occurred while unmarshaling a // AttributeValue element into a Go type. This is different from // UnmarshalTypeError in that it wraps the underlying error that occurred. type UnmarshalError struct { Err error Value string Type reflect.Type } func (e *UnmarshalError) Unwrap() error { return e.Err } // Error returns the string representation of the error satisfying the error // interface. func (e *UnmarshalError) Error() string { return fmt.Sprintf("unmarshal failed, cannot unmarshal %q into %s, %v", e.Value, e.Type.String(), e.Err) } func defaultDecodeTimeS(v string) (time.Time, error) { t, err := time.Parse(time.RFC3339, v) if err != nil { return time.Time{}, &UnmarshalError{Err: err, Value: v, Type: timeType} } return t, nil } func defaultDecodeTimeN(v string) (time.Time, error) { return decodeUnixTime(v) }