1package dynamodbattribute
2
3import (
4	"encoding/base64"
5	"fmt"
6	"reflect"
7	"strconv"
8	"time"
9
10	"github.com/aws/aws-sdk-go/aws"
11	"github.com/aws/aws-sdk-go/service/dynamodb"
12)
13
14// An Unmarshaler is an interface to provide custom unmarshaling of
15// AttributeValues. Use this to provide custom logic determining
16// how AttributeValues should be unmarshaled.
17// 		type ExampleUnmarshaler struct {
18// 			Value int
19// 		}
20//
21// 		func (u *ExampleUnmarshaler) UnmarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
22// 			if av.N == nil {
23// 				return nil
24// 			}
25//
26// 			n, err := strconv.ParseInt(*av.N, 10, 0)
27// 			if err != nil {
28// 				return err
29// 			}
30//
31// 			u.Value = int(n)
32// 			return nil
33// 		}
34type Unmarshaler interface {
35	UnmarshalDynamoDBAttributeValue(*dynamodb.AttributeValue) error
36}
37
38// Unmarshal will unmarshal DynamoDB AttributeValues to Go value types.
39// Both generic interface{} and concrete types are valid unmarshal
40// destination types.
41//
42// Unmarshal will allocate maps, slices, and pointers as needed to
43// unmarshal the AttributeValue into the provided type value.
44//
45// When unmarshaling AttributeValues into structs Unmarshal matches
46// the field names of the struct to the AttributeValue Map keys.
47// Initially it will look for exact field name matching, but will
48// fall back to case insensitive if not exact match is found.
49//
50// With the exception of omitempty, omitemptyelem, binaryset, numberset
51// and stringset all struct tags used by Marshal are also used by
52// Unmarshal.
53//
54// When decoding AttributeValues to interfaces Unmarshal will use the
55// following types.
56//
57//		[]byte,                 AV Binary (B)
58//		[][]byte,               AV Binary Set (BS)
59//		bool,                   AV Boolean (BOOL)
60//		[]interface{},          AV List (L)
61//		map[string]interface{}, AV Map (M)
62//		float64,                AV Number (N)
63//		Number,                 AV Number (N) with UseNumber set
64//		[]float64,              AV Number Set (NS)
65//		[]Number,               AV Number Set (NS) with UseNumber set
66//		string,                 AV String (S)
67//		[]string,               AV String Set (SS)
68//
69// If the Decoder option, UseNumber is set numbers will be unmarshaled
70// as Number values instead of float64. Use this to maintain the original
71// string formating of the number as it was represented in the AttributeValue.
72// In addition provides additional opportunities to parse the number
73// string based on individual use cases.
74//
75// When unmarshaling any error that occurs will halt the unmarshal
76// and return the error.
77//
78// The output value provided must be a non-nil pointer
79func Unmarshal(av *dynamodb.AttributeValue, out interface{}) error {
80	return NewDecoder().Decode(av, out)
81}
82
83// UnmarshalMap is an alias for Unmarshal which unmarshals from
84// a map of AttributeValues.
85//
86// The output value provided must be a non-nil pointer
87func UnmarshalMap(m map[string]*dynamodb.AttributeValue, out interface{}) error {
88	return NewDecoder().Decode(&dynamodb.AttributeValue{M: m}, out)
89}
90
91// UnmarshalList is an alias for Unmarshal func which unmarshals
92// a slice of AttributeValues.
93//
94// The output value provided must be a non-nil pointer
95func UnmarshalList(l []*dynamodb.AttributeValue, out interface{}) error {
96	return NewDecoder().Decode(&dynamodb.AttributeValue{L: l}, out)
97}
98
99// UnmarshalListOfMaps is an alias for Unmarshal func which unmarshals a
100// slice of maps of attribute values.
101//
102// This is useful for when you need to unmarshal the Items from a DynamoDB
103// Query API call.
104//
105// The output value provided must be a non-nil pointer
106func UnmarshalListOfMaps(l []map[string]*dynamodb.AttributeValue, out interface{}) error {
107	items := make([]*dynamodb.AttributeValue, len(l))
108	for i, m := range l {
109		items[i] = &dynamodb.AttributeValue{M: m}
110	}
111
112	return UnmarshalList(items, out)
113}
114
115// A Decoder provides unmarshaling AttributeValues to Go value types.
116type Decoder struct {
117	MarshalOptions
118
119	// Instructs the decoder to decode AttributeValue Numbers as
120	// Number type instead of float64 when the destination type
121	// is interface{}. Similar to encoding/json.Number
122	UseNumber bool
123}
124
125// NewDecoder creates a new Decoder with default configuration. Use
126// the `opts` functional options to override the default configuration.
127func NewDecoder(opts ...func(*Decoder)) *Decoder {
128	d := &Decoder{
129		MarshalOptions: MarshalOptions{
130			SupportJSONTags: true,
131		},
132	}
133	for _, o := range opts {
134		o(d)
135	}
136
137	return d
138}
139
140// Decode will unmarshal an AttributeValue into a Go value type. An error
141// will be return if the decoder is unable to unmarshal the AttributeValue
142// to the provide Go value type.
143//
144// The output value provided must be a non-nil pointer
145func (d *Decoder) Decode(av *dynamodb.AttributeValue, out interface{}, opts ...func(*Decoder)) error {
146	v := reflect.ValueOf(out)
147	if v.Kind() != reflect.Ptr || v.IsNil() || !v.IsValid() {
148		return &InvalidUnmarshalError{Type: reflect.TypeOf(out)}
149	}
150
151	return d.decode(av, v, tag{})
152}
153
154var stringInterfaceMapType = reflect.TypeOf(map[string]interface{}(nil))
155var byteSliceType = reflect.TypeOf([]byte(nil))
156var byteSliceSlicetype = reflect.TypeOf([][]byte(nil))
157var numberType = reflect.TypeOf(Number(""))
158var timeType = reflect.TypeOf(time.Time{})
159var ptrStringType = reflect.TypeOf(aws.String(""))
160
161func (d *Decoder) decode(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
162	var u Unmarshaler
163	if av == nil || av.NULL != nil {
164		u, v = indirect(v, true)
165		if u != nil {
166			return u.UnmarshalDynamoDBAttributeValue(av)
167		}
168		return d.decodeNull(v)
169	}
170
171	u, v = indirect(v, false)
172	if u != nil {
173		return u.UnmarshalDynamoDBAttributeValue(av)
174	}
175
176	switch {
177	case av.B != nil:
178		return d.decodeBinary(av.B, v)
179	case av.BOOL != nil:
180		return d.decodeBool(av.BOOL, v)
181	case av.BS != nil:
182		return d.decodeBinarySet(av.BS, v)
183	case av.L != nil:
184		return d.decodeList(av.L, v)
185	case av.M != nil:
186		return d.decodeMap(av.M, v)
187	case av.N != nil:
188		return d.decodeNumber(av.N, v, fieldTag)
189	case av.NS != nil:
190		return d.decodeNumberSet(av.NS, v)
191	case av.S != nil:
192		return d.decodeString(av.S, v, fieldTag)
193	case av.SS != nil:
194		return d.decodeStringSet(av.SS, v)
195	}
196
197	return nil
198}
199
200func (d *Decoder) decodeBinary(b []byte, v reflect.Value) error {
201	if v.Kind() == reflect.Interface {
202		buf := make([]byte, len(b))
203		copy(buf, b)
204		v.Set(reflect.ValueOf(buf))
205		return nil
206	}
207
208	if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
209		return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
210	}
211
212	if v.Type() == byteSliceType {
213		// Optimization for []byte types
214		if v.IsNil() || v.Cap() < len(b) {
215			v.Set(reflect.MakeSlice(byteSliceType, len(b), len(b)))
216		} else if v.Len() != len(b) {
217			v.SetLen(len(b))
218		}
219		copy(v.Interface().([]byte), b)
220		return nil
221	}
222
223	switch v.Type().Elem().Kind() {
224	case reflect.Uint8:
225		// Fallback to reflection copy for type aliased of []byte type
226		if v.Kind() != reflect.Array && (v.IsNil() || v.Cap() < len(b)) {
227			v.Set(reflect.MakeSlice(v.Type(), len(b), len(b)))
228		} else if v.Len() != len(b) {
229			v.SetLen(len(b))
230		}
231		for i := 0; i < len(b); i++ {
232			v.Index(i).SetUint(uint64(b[i]))
233		}
234	default:
235		if v.Kind() == reflect.Array {
236			switch v.Type().Elem().Kind() {
237			case reflect.Uint8:
238				reflect.Copy(v, reflect.ValueOf(b))
239			default:
240				return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
241			}
242
243			break
244		}
245
246		return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
247	}
248
249	return nil
250}
251
252func (d *Decoder) decodeBool(b *bool, v reflect.Value) error {
253	switch v.Kind() {
254	case reflect.Bool, reflect.Interface:
255		v.Set(reflect.ValueOf(*b).Convert(v.Type()))
256	default:
257		return &UnmarshalTypeError{Value: "bool", Type: v.Type()}
258	}
259
260	return nil
261}
262
263func (d *Decoder) decodeBinarySet(bs [][]byte, v reflect.Value) error {
264	isArray := false
265
266	switch v.Kind() {
267	case reflect.Slice:
268		// Make room for the slice elements if needed
269		if v.IsNil() || v.Cap() < len(bs) {
270			// What about if ignoring nil/empty values?
271			v.Set(reflect.MakeSlice(v.Type(), 0, len(bs)))
272		}
273	case reflect.Array:
274		// Limited to capacity of existing array.
275		isArray = true
276	case reflect.Interface:
277		set := make([][]byte, len(bs))
278		for i, b := range bs {
279			if err := d.decodeBinary(b, reflect.ValueOf(&set[i]).Elem()); err != nil {
280				return err
281			}
282		}
283		v.Set(reflect.ValueOf(set))
284		return nil
285	default:
286		return &UnmarshalTypeError{Value: "binary set", Type: v.Type()}
287	}
288
289	for i := 0; i < v.Cap() && i < len(bs); i++ {
290		if !isArray {
291			v.SetLen(i + 1)
292		}
293		u, elem := indirect(v.Index(i), false)
294		if u != nil {
295			return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{BS: bs})
296		}
297		if err := d.decodeBinary(bs[i], elem); err != nil {
298			return err
299		}
300	}
301
302	return nil
303}
304
305func (d *Decoder) decodeNumber(n *string, v reflect.Value, fieldTag tag) error {
306	switch v.Kind() {
307	case reflect.Interface:
308		i, err := d.decodeNumberToInterface(n)
309		if err != nil {
310			return err
311		}
312		v.Set(reflect.ValueOf(i))
313		return nil
314	case reflect.String:
315		if v.Type() == numberType { // Support Number value type
316			v.Set(reflect.ValueOf(Number(*n)))
317			return nil
318		}
319		v.SetString(*n)
320	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
321		i, err := strconv.ParseInt(*n, 10, 64)
322		if err != nil {
323			return err
324		}
325		if v.OverflowInt(i) {
326			return &UnmarshalTypeError{
327				Value: fmt.Sprintf("number overflow, %s", *n),
328				Type:  v.Type(),
329			}
330		}
331		v.SetInt(i)
332	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
333		i, err := strconv.ParseUint(*n, 10, 64)
334		if err != nil {
335			return err
336		}
337		if v.OverflowUint(i) {
338			return &UnmarshalTypeError{
339				Value: fmt.Sprintf("number overflow, %s", *n),
340				Type:  v.Type(),
341			}
342		}
343		v.SetUint(i)
344	case reflect.Float32, reflect.Float64:
345		i, err := strconv.ParseFloat(*n, 64)
346		if err != nil {
347			return err
348		}
349		if v.OverflowFloat(i) {
350			return &UnmarshalTypeError{
351				Value: fmt.Sprintf("number overflow, %s", *n),
352				Type:  v.Type(),
353			}
354		}
355		v.SetFloat(i)
356	default:
357		if v.Type().ConvertibleTo(timeType) && fieldTag.AsUnixTime {
358			t, err := decodeUnixTime(*n)
359			if err != nil {
360				return err
361			}
362			v.Set(reflect.ValueOf(t).Convert(v.Type()))
363			return nil
364		}
365		return &UnmarshalTypeError{Value: "number", Type: v.Type()}
366	}
367
368	return nil
369}
370
371func (d *Decoder) decodeNumberToInterface(n *string) (interface{}, error) {
372	if d.UseNumber {
373		return Number(*n), nil
374	}
375
376	// Default to float64 for all numbers
377	return strconv.ParseFloat(*n, 64)
378}
379
380func (d *Decoder) decodeNumberSet(ns []*string, v reflect.Value) error {
381	isArray := false
382
383	switch v.Kind() {
384	case reflect.Slice:
385		// Make room for the slice elements if needed
386		if v.IsNil() || v.Cap() < len(ns) {
387			// What about if ignoring nil/empty values?
388			v.Set(reflect.MakeSlice(v.Type(), 0, len(ns)))
389		}
390	case reflect.Array:
391		// Limited to capacity of existing array.
392		isArray = true
393	case reflect.Interface:
394		if d.UseNumber {
395			set := make([]Number, len(ns))
396			for i, n := range ns {
397				if err := d.decodeNumber(n, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
398					return err
399				}
400			}
401			v.Set(reflect.ValueOf(set))
402		} else {
403			set := make([]float64, len(ns))
404			for i, n := range ns {
405				if err := d.decodeNumber(n, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
406					return err
407				}
408			}
409			v.Set(reflect.ValueOf(set))
410		}
411		return nil
412	default:
413		return &UnmarshalTypeError{Value: "number set", Type: v.Type()}
414	}
415
416	for i := 0; i < v.Cap() && i < len(ns); i++ {
417		if !isArray {
418			v.SetLen(i + 1)
419		}
420		u, elem := indirect(v.Index(i), false)
421		if u != nil {
422			return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{NS: ns})
423		}
424		if err := d.decodeNumber(ns[i], elem, tag{}); err != nil {
425			return err
426		}
427	}
428
429	return nil
430}
431
432func (d *Decoder) decodeList(avList []*dynamodb.AttributeValue, v reflect.Value) error {
433	isArray := false
434
435	switch v.Kind() {
436	case reflect.Slice:
437		// Make room for the slice elements if needed
438		if v.IsNil() || v.Cap() < len(avList) {
439			// What about if ignoring nil/empty values?
440			v.Set(reflect.MakeSlice(v.Type(), 0, len(avList)))
441		}
442	case reflect.Array:
443		// Limited to capacity of existing array.
444		isArray = true
445	case reflect.Interface:
446		s := make([]interface{}, len(avList))
447		for i, av := range avList {
448			if err := d.decode(av, reflect.ValueOf(&s[i]).Elem(), tag{}); err != nil {
449				return err
450			}
451		}
452		v.Set(reflect.ValueOf(s))
453		return nil
454	default:
455		return &UnmarshalTypeError{Value: "list", Type: v.Type()}
456	}
457
458	// If v is not a slice, array
459	for i := 0; i < v.Cap() && i < len(avList); i++ {
460		if !isArray {
461			v.SetLen(i + 1)
462		}
463
464		if err := d.decode(avList[i], v.Index(i), tag{}); err != nil {
465			return err
466		}
467	}
468
469	return nil
470}
471
472func (d *Decoder) decodeMap(avMap map[string]*dynamodb.AttributeValue, v reflect.Value) error {
473	switch v.Kind() {
474	case reflect.Map:
475		t := v.Type()
476		if t.Key().Kind() != reflect.String {
477			return &UnmarshalTypeError{Value: "map string key", Type: t.Key()}
478		}
479		if v.IsNil() {
480			v.Set(reflect.MakeMap(t))
481		}
482	case reflect.Struct:
483	case reflect.Interface:
484		v.Set(reflect.MakeMap(stringInterfaceMapType))
485		v = v.Elem()
486	default:
487		return &UnmarshalTypeError{Value: "map", Type: v.Type()}
488	}
489
490	if v.Kind() == reflect.Map {
491		for k, av := range avMap {
492			key := reflect.New(v.Type().Key()).Elem()
493			key.SetString(k)
494			elem := reflect.New(v.Type().Elem()).Elem()
495			if err := d.decode(av, elem, tag{}); err != nil {
496				return err
497			}
498			v.SetMapIndex(key, elem)
499		}
500	} else if v.Kind() == reflect.Struct {
501		fields := unionStructFields(v.Type(), d.MarshalOptions)
502		for k, av := range avMap {
503			if f, ok := fields.FieldByName(k); ok {
504				fv := decoderFieldByIndex(v, f.Index)
505				if err := d.decode(av, fv, f.tag); err != nil {
506					return err
507				}
508			}
509		}
510	}
511
512	return nil
513}
514
515func (d *Decoder) decodeNull(v reflect.Value) error {
516	if v.IsValid() && v.CanSet() {
517		v.Set(reflect.Zero(v.Type()))
518	}
519
520	return nil
521}
522
523func (d *Decoder) decodeString(s *string, v reflect.Value, fieldTag tag) error {
524	if fieldTag.AsString {
525		return d.decodeNumber(s, v, fieldTag)
526	}
527
528	// To maintain backwards compatibility with ConvertFrom family of methods which
529	// converted strings to time.Time structs
530	if v.Type().ConvertibleTo(timeType) {
531		t, err := time.Parse(time.RFC3339, *s)
532		if err != nil {
533			return err
534		}
535		v.Set(reflect.ValueOf(t).Convert(v.Type()))
536		return nil
537	}
538
539	switch v.Kind() {
540	case reflect.String:
541		v.SetString(*s)
542	case reflect.Slice:
543		// To maintain backwards compatibility with the ConvertFrom family of methods
544		// which converted []byte into base64-encoded strings if the input was typed
545		if v.Type() == byteSliceType {
546			decoded, err := base64.StdEncoding.DecodeString(*s)
547			if err != nil {
548				return &UnmarshalError{Err: err, Value: "string", Type: v.Type()}
549			}
550			v.SetBytes(decoded)
551		}
552	case reflect.Interface:
553		// Ensure type aliasing is handled properly
554		v.Set(reflect.ValueOf(*s).Convert(v.Type()))
555	default:
556		return &UnmarshalTypeError{Value: "string", Type: v.Type()}
557	}
558
559	return nil
560}
561
562func (d *Decoder) decodeStringSet(ss []*string, v reflect.Value) error {
563	isArray := false
564
565	switch v.Kind() {
566	case reflect.Slice:
567		// Make room for the slice elements if needed
568		if v.IsNil() || v.Cap() < len(ss) {
569			v.Set(reflect.MakeSlice(v.Type(), 0, len(ss)))
570		}
571	case reflect.Array:
572		// Limited to capacity of existing array.
573		isArray = true
574	case reflect.Interface:
575		set := make([]string, len(ss))
576		for i, s := range ss {
577			if err := d.decodeString(s, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
578				return err
579			}
580		}
581		v.Set(reflect.ValueOf(set))
582		return nil
583	default:
584		return &UnmarshalTypeError{Value: "string set", Type: v.Type()}
585	}
586
587	for i := 0; i < v.Cap() && i < len(ss); i++ {
588		if !isArray {
589			v.SetLen(i + 1)
590		}
591		u, elem := indirect(v.Index(i), false)
592		if u != nil {
593			return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{SS: ss})
594		}
595		if err := d.decodeString(ss[i], elem, tag{}); err != nil {
596			return err
597		}
598	}
599
600	return nil
601}
602
603func decodeUnixTime(n string) (time.Time, error) {
604	v, err := strconv.ParseInt(n, 10, 64)
605	if err != nil {
606		return time.Time{}, &UnmarshalError{
607			Err: err, Value: n, Type: timeType,
608		}
609	}
610
611	return time.Unix(v, 0), nil
612}
613
614// decoderFieldByIndex finds the field with the provided nested index, allocating
615// embedded parent structs if needed
616func decoderFieldByIndex(v reflect.Value, index []int) reflect.Value {
617	for i, x := range index {
618		if i > 0 && v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct {
619			if v.IsNil() {
620				v.Set(reflect.New(v.Type().Elem()))
621			}
622			v = v.Elem()
623		}
624		v = v.Field(x)
625	}
626	return v
627}
628
629// indirect will walk a value's interface or pointer value types. Returning
630// the final value or the value a unmarshaler is defined on.
631//
632// Based on the enoding/json type reflect value type indirection in Go Stdlib
633// https://golang.org/src/encoding/json/decode.go indirect func.
634func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) {
635	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
636		v = v.Addr()
637	}
638	for {
639		if v.Kind() == reflect.Interface && !v.IsNil() {
640			e := v.Elem()
641			if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
642				v = e
643				continue
644			}
645		}
646		if v.Kind() != reflect.Ptr {
647			break
648		}
649		if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
650			break
651		}
652		if v.IsNil() {
653			v.Set(reflect.New(v.Type().Elem()))
654		}
655		if v.Type().NumMethod() > 0 {
656			if u, ok := v.Interface().(Unmarshaler); ok {
657				return u, reflect.Value{}
658			}
659		}
660		v = v.Elem()
661	}
662
663	return nil, v
664}
665
666// A Number represents a Attributevalue number literal.
667type Number string
668
669// Float64 attempts to cast the number ot a float64, returning
670// the result of the case or error if the case failed.
671func (n Number) Float64() (float64, error) {
672	return strconv.ParseFloat(string(n), 64)
673}
674
675// Int64 attempts to cast the number ot a int64, returning
676// the result of the case or error if the case failed.
677func (n Number) Int64() (int64, error) {
678	return strconv.ParseInt(string(n), 10, 64)
679}
680
681// Uint64 attempts to cast the number ot a uint64, returning
682// the result of the case or error if the case failed.
683func (n Number) Uint64() (uint64, error) {
684	return strconv.ParseUint(string(n), 10, 64)
685}
686
687// String returns the raw number represented as a string
688func (n Number) String() string {
689	return string(n)
690}
691
692type emptyOrigError struct{}
693
694func (e emptyOrigError) OrigErr() error {
695	return nil
696}
697
698// An UnmarshalTypeError is an error type representing a error
699// unmarshaling the AttributeValue's element to a Go value type.
700// Includes details about the AttributeValue type and Go value type.
701type UnmarshalTypeError struct {
702	emptyOrigError
703	Value string
704	Type  reflect.Type
705}
706
707// Error returns the string representation of the error.
708// satisfying the error interface
709func (e *UnmarshalTypeError) Error() string {
710	return fmt.Sprintf("%s: %s", e.Code(), e.Message())
711}
712
713// Code returns the code of the error, satisfying the awserr.Error
714// interface.
715func (e *UnmarshalTypeError) Code() string {
716	return "UnmarshalTypeError"
717}
718
719// Message returns the detailed message of the error, satisfying
720// the awserr.Error interface.
721func (e *UnmarshalTypeError) Message() string {
722	return "cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
723}
724
725// An InvalidUnmarshalError is an error type representing an invalid type
726// encountered while unmarshaling a AttributeValue to a Go value type.
727type InvalidUnmarshalError struct {
728	emptyOrigError
729	Type reflect.Type
730}
731
732// Error returns the string representation of the error.
733// satisfying the error interface
734func (e *InvalidUnmarshalError) Error() string {
735	return fmt.Sprintf("%s: %s", e.Code(), e.Message())
736}
737
738// Code returns the code of the error, satisfying the awserr.Error
739// interface.
740func (e *InvalidUnmarshalError) Code() string {
741	return "InvalidUnmarshalError"
742}
743
744// Message returns the detailed message of the error, satisfying
745// the awserr.Error interface.
746func (e *InvalidUnmarshalError) Message() string {
747	if e.Type == nil {
748		return "cannot unmarshal to nil value"
749	}
750	if e.Type.Kind() != reflect.Ptr {
751		return "cannot unmarshal to non-pointer value, got " + e.Type.String()
752	}
753	return "cannot unmarshal to nil value, " + e.Type.String()
754}
755
756// An UnmarshalError wraps an error that occurred while unmarshaling a DynamoDB
757// AttributeValue element into a Go type. This is different from UnmarshalTypeError
758// in that it wraps the underlying error that occurred.
759type UnmarshalError struct {
760	Err   error
761	Value string
762	Type  reflect.Type
763}
764
765// Error returns the string representation of the error.
766// satisfying the error interface.
767func (e *UnmarshalError) Error() string {
768	return fmt.Sprintf("%s: %s\ncaused by: %v", e.Code(), e.Message(), e.Err)
769}
770
771// OrigErr returns the original error that caused this issue.
772func (e UnmarshalError) OrigErr() error {
773	return e.Err
774}
775
776// Code returns the code of the error, satisfying the awserr.Error
777// interface.
778func (e *UnmarshalError) Code() string {
779	return "UnmarshalError"
780}
781
782// Message returns the detailed message of the error, satisfying
783// the awserr.Error interface.
784func (e *UnmarshalError) Message() string {
785	return fmt.Sprintf("cannot unmarshal %q into %s.",
786		e.Value, e.Type.String())
787}
788