//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

// This code is heavily inspired by the Go sources.
// See https://golang.org/src/encoding/json/

package velocypack

import (
	"bytes"
	"encoding"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"runtime"
	"strconv"
)

// A Decoder decodes velocypack values into Go structures.
type Decoder struct {
	r io.Reader
}

// Unmarshaler is implemented by types that can convert themselves from Velocypack.
type Unmarshaler interface {
	UnmarshalVPack(Slice) error
}

// NewDecoder creates a new Decoder that reads data from the given reader.
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{
		r: r,
	}
}

// Unmarshal reads v from the given Velocypack encoded data slice.
//
// Unmarshal uses the inverse of the encodings that
// Marshal uses, allocating maps, slices, and pointers as necessary,
// with the following additional rules:
//
// To unmarshal VelocyPack into a pointer, Unmarshal first handles the case of
// the VelocyPack being the VelocyPack literal Null. In that case, Unmarshal sets
// the pointer to nil. Otherwise, Unmarshal unmarshals the VelocyPack into
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
// allocates a new value for it to point to.
//
// To unmarshal VelocyPack into a value implementing the Unmarshaler interface,
// Unmarshal calls that value's UnmarshalVPack method, including
// when the input is a VelocyPack Null.
// Otherwise, if the value implements encoding.TextUnmarshaler
// and the input is a VelocyPack quoted string, Unmarshal calls that value's
// UnmarshalText method with the unquoted form of the string.
//
// To unmarshal VelocyPack into a struct, Unmarshal matches incoming object
// keys to the keys used by Marshal (either the struct field name or its tag),
// preferring an exact match but also accepting a case-insensitive match.
// Unmarshal will only set exported fields of the struct.
//
// To unmarshal VelocyPack into an interface value,
// Unmarshal stores one of these in the interface value:
//
//	bool, for VelocyPack Bool's
//	float64 for VelocyPack Double's
//	uint64 for VelocyPack UInt's
//	int64 for VelocyPack Int's
//	string, for VelocyPack String's
//	[]interface{}, for VelocyPack Array's
//	map[string]interface{}, for VelocyPack Object's
//	nil for VelocyPack Null.
//	[]byte for VelocyPack Binary.
//
// To unmarshal a VelocyPack array into a slice, Unmarshal resets the slice length
// to zero and then appends each element to the slice.
// As a special case, to unmarshal an empty VelocyPack array into a slice,
// Unmarshal replaces the slice with a new empty slice.
//
// To unmarshal a VelocyPack array into a Go array, Unmarshal decodes
// VelocyPack array elements into corresponding Go array elements.
// If the Go array is smaller than the VelocyPack array,
// the additional VelocyPack array elements are discarded.
// If the VelocyPack array is smaller than the Go array,
// the additional Go array elements are set to zero values.
//
// To unmarshal a VelocyPack object into a map, Unmarshal first establishes a map to
// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
// reuses the existing map, keeping existing entries. Unmarshal then stores
// key-value pairs from the VelocyPack object into the map. The map's key type must
// either be a string, an integer, or implement encoding.TextUnmarshaler.
//
// If a VelocyPack value is not appropriate for a given target type,
// or if a VelocyPack number overflows the target type, Unmarshal
// skips that field and completes the unmarshaling as best it can.
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
// The VelocyPack Null value unmarshals into an interface, map, pointer, or slice
// by setting that Go value to nil. Because null is often used in VelocyPack to mean
// ``not present,'' unmarshaling a VelocyPack Null into any other Go type has no effect
// on the value and produces no error.
//
func Unmarshal(data Slice, v interface{}) error {
	if err := unmarshalSlice(data, v); err != nil {
		return WithStack(err)
	}
	return nil
}

// Decode reads v from the decoder stream.
func (e *Decoder) Decode(v interface{}) error {
	s, err := SliceFromReader(e.r)
	if err != nil {
		return WithStack(err)
	}
	if err := unmarshalSlice(s, v); err != nil {
		return WithStack(err)
	}
	return nil
}

// unmarshalSlice reads v from the given slice.
func unmarshalSlice(data Slice, v interface{}) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				panic(r)
			}
			err = r.(error)
		}
	}()

	rv := reflect.ValueOf(v)
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return &InvalidUnmarshalError{reflect.TypeOf(v)}
	}

	d := &decodeState{}
	// We decode rv not rv.Elem because the Unmarshaler interface
	// test must be applied at the top level of the value.
	d.unmarshalValue(data, rv)
	return d.savedError
}

var (
	textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
	numberType          = reflect.TypeOf(json.Number(""))
)

type decodeState struct {
	useNumber    bool
	errorContext struct { // provides context for type errors
		Struct string
		Field  string
	}
	savedError error
}

// error aborts the decoding by panicking with err.
func (d *decodeState) error(err error) {
	panic(d.addErrorContext(err))
}

// saveError saves the first err it is called with,
// for reporting at the end of the unmarshal.
func (d *decodeState) saveError(err error) {
	if d.savedError == nil {
		d.savedError = d.addErrorContext(err)
	}
}

// addErrorContext returns a new error enhanced with information from d.errorContext
func (d *decodeState) addErrorContext(err error) error {
	if d.errorContext.Struct != "" || d.errorContext.Field != "" {
		switch err := err.(type) {
		case *UnmarshalTypeError:
			err.Struct = d.errorContext.Struct
			err.Field = d.errorContext.Field
			return err
		}
	}
	return err
}

// unmarshalValue unmarshals any slice into given v.
func (d *decodeState) unmarshalValue(data Slice, v reflect.Value) {
	if !v.IsValid() {
		return
	}

	switch data.Type() {
	case Array:
		d.unmarshalArray(data, v)
	case Object:
		d.unmarshalObject(data, v)
	case Bool, Int, SmallInt, UInt, Double, Binary, BCD, String:
		d.unmarshalLiteral(data, v)
	}
}

// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) {
	// 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() {
		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() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
				v = e
				continue
			}
		}

		if v.Kind() != reflect.Ptr {
			break
		}

		if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
			break
		}
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		if v.Type().NumMethod() > 0 {
			if u, ok := v.Interface().(Unmarshaler); ok {
				return u, nil, nil, reflect.Value{}
			}
			if u, ok := v.Interface().(json.Unmarshaler); ok {
				return nil, u, nil, reflect.Value{}
			}
			if !decodingNull {
				if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
					return nil, nil, u, reflect.Value{}
				}
			}
		}
		v = v.Elem()
	}
	return nil, nil, nil, v
}

// unmarshalArray unmarshals an array slice into given v.
func (d *decodeState) unmarshalArray(data Slice, v reflect.Value) {
	// Check for unmarshaler.
	u, ju, ut, pv := d.indirect(v, false)
	if u != nil {
		if err := u.UnmarshalVPack(data); err != nil {
			d.error(err)
		}
		return
	}
	if ju != nil {
		json, err := data.JSONString()
		if err != nil {
			d.error(err)
		} else {
			if err := ju.UnmarshalJSON([]byte(json)); err != nil {
				d.error(err)
			}
		}
		return
	}
	if ut != nil {
		d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type()})
		return
	}

	v = pv

	// Check type of target.
	switch v.Kind() {
	case reflect.Interface:
		if v.NumMethod() == 0 {
			// Decoding into nil interface?  Switch to non-reflect code.
			v.Set(reflect.ValueOf(d.arrayInterface(data)))
			return
		}
		// Otherwise it's invalid.
		fallthrough
	default:
		d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type()})
		return
	case reflect.Array:
	case reflect.Slice:
		break
	}

	i := 0
	it, err := NewArrayIterator(data)
	if err != nil {
		d.error(err)
	}
	for it.IsValid() {
		value, err := it.Value()
		if err != nil {
			d.error(err)
		}

		// Get element of array, growing if necessary.
		if v.Kind() == reflect.Slice {
			// Grow slice if necessary
			if i >= v.Cap() {
				newcap := v.Cap() + v.Cap()/2
				if newcap < 4 {
					newcap = 4
				}
				newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
				reflect.Copy(newv, v)
				v.Set(newv)
			}
			if i >= v.Len() {
				v.SetLen(i + 1)
			}
		}

		if i < v.Len() {
			// Decode into element.
			d.unmarshalValue(value, v.Index(i))
		}
		i++
		if err := it.Next(); err != nil {
			d.error(err)
		}
	}

	if i < v.Len() {
		if v.Kind() == reflect.Array {
			// Array. Zero the rest.
			z := reflect.Zero(v.Type().Elem())
			for ; i < v.Len(); i++ {
				v.Index(i).Set(z)
			}
		} else {
			v.SetLen(i)
		}
	}
	if i == 0 && v.Kind() == reflect.Slice {
		v.Set(reflect.MakeSlice(v.Type(), 0, 0))
	}
}

// unmarshalObject unmarshals an object slice into given v.
func (d *decodeState) unmarshalObject(data Slice, v reflect.Value) {
	// Check for unmarshaler.
	u, ju, ut, pv := d.indirect(v, false)
	if u != nil {
		if err := u.UnmarshalVPack(data); err != nil {
			d.error(err)
		}
		return
	}
	if ju != nil {
		json, err := data.JSONString()
		if err != nil {
			d.error(err)
		} else {
			if err := ju.UnmarshalJSON([]byte(json)); err != nil {
				d.error(err)
			}
		}
		return
	}
	if ut != nil {
		d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type()})
		return
	}
	v = pv

	// Decoding into nil interface?  Switch to non-reflect code.
	if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
		v.Set(reflect.ValueOf(d.objectInterface(data)))
		return
	}

	// Check type of target:
	//   struct or
	//   map[T1]T2 where T1 is string, an integer type,
	//             or an encoding.TextUnmarshaler
	switch v.Kind() {
	case reflect.Map:
		// Map key must either have string kind, have an integer kind,
		// or be an encoding.TextUnmarshaler.
		t := v.Type()
		switch t.Key().Kind() {
		case reflect.String,
			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		default:
			if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
				d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type()})
				return
			}
		}
		if v.IsNil() {
			v.Set(reflect.MakeMap(t))
		}
	case reflect.Struct:
		// ok
	default:
		d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type()})
		return
	}

	var mapElem reflect.Value

	it, err := NewObjectIterator(data)
	if err != nil {
		d.error(err)
	}
	for it.IsValid() {
		key, err := it.Key(true)
		if err != nil {
			d.error(err)
		}
		keyUTF8, err := key.GetStringUTF8()
		if err != nil {
			d.error(err)
		}
		value, err := it.Value()
		if err != nil {
			d.error(err)
		}

		// Figure out field corresponding to key.
		var subv reflect.Value
		destring := false // whether the value is wrapped in a string to be decoded first

		if v.Kind() == reflect.Map {
			elemType := v.Type().Elem()
			if !mapElem.IsValid() {
				mapElem = reflect.New(elemType).Elem()
			} else {
				mapElem.Set(reflect.Zero(elemType))
			}
			subv = mapElem
		} else {
			var f *field
			fields := cachedTypeFields(v.Type())
			for i := range fields {
				ff := &fields[i]
				if bytes.Equal(ff.nameBytes, key) {
					f = ff
					break
				}
				if f == nil && ff.equalFold(ff.nameBytes, keyUTF8) {
					f = ff
				}
			}
			if f != nil {
				subv = v
				destring = f.quoted
				for _, i := range f.index {
					if subv.Kind() == reflect.Ptr {
						if subv.IsNil() {
							subv.Set(reflect.New(subv.Type().Elem()))
						}
						subv = subv.Elem()
					}
					subv = subv.Field(i)
				}
				d.errorContext.Field = f.name
				d.errorContext.Struct = v.Type().Name()
			}
		}

		if destring {
			// Value should be a string that we'll decode as JSON
			valueUTF8, err := value.GetStringUTF8()
			if err != nil {
				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, expected string, got %s in %v (%v)", value.Type(), subv.Type(), err))
			}
			v, err := ParseJSONFromUTF8(valueUTF8)
			if err != nil {
				d.saveError(err)
			} else {
				d.unmarshalValue(v, subv)
			}
		} else {
			d.unmarshalValue(value, subv)
		}

		// Write value back to map;
		// if using struct, subv points into struct already.
		if v.Kind() == reflect.Map {
			kt := v.Type().Key()
			var kv reflect.Value
			switch {
			case kt.Kind() == reflect.String:
				kv = reflect.ValueOf(keyUTF8).Convert(kt)
			case reflect.PtrTo(kt).Implements(textUnmarshalerType):
				kv = reflect.New(v.Type().Key())
				d.literalStore(key, kv, true)
				kv = kv.Elem()
			default:
				keyStr := string(keyUTF8)
				switch kt.Kind() {
				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
					n, err := strconv.ParseInt(keyStr, 10, 64)
					if err != nil || reflect.Zero(kt).OverflowInt(n) {
						d.saveError(&UnmarshalTypeError{Value: "number " + keyStr, Type: kt})
						return
					}
					kv = reflect.ValueOf(n).Convert(kt)
				case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
					n, err := strconv.ParseUint(keyStr, 10, 64)
					if err != nil || reflect.Zero(kt).OverflowUint(n) {
						d.saveError(&UnmarshalTypeError{Value: "number " + keyStr, Type: kt})
						return
					}
					kv = reflect.ValueOf(n).Convert(kt)
				default:
					panic("json: Unexpected key type") // should never occur
				}
			}
			v.SetMapIndex(kv, subv)
		}

		d.errorContext.Struct = ""
		d.errorContext.Field = ""

		if err := it.Next(); err != nil {
			d.error(err)
		}
	}
}

// unmarshalLiteral unmarshals a literal slice into given v.
func (d *decodeState) unmarshalLiteral(data Slice, v reflect.Value) {
	d.literalStore(data, v, false)
}

// The xxxInterface routines build up a value to be stored
// in an empty interface. They are not strictly necessary,
// but they avoid the weight of reflection in this common case.

// valueInterface is like value but returns interface{}
func (d *decodeState) valueInterface(data Slice) interface{} {
	switch data.Type() {
	case Array:
		return d.arrayInterface(data)
	case Object:
		return d.objectInterface(data)
	default:
		return d.literalInterface(data)
	}
}

// arrayInterface is like array but returns []interface{}.
func (d *decodeState) arrayInterface(data Slice) []interface{} {
	l, err := data.Length()
	if err != nil {
		d.error(err)
	}
	v := make([]interface{}, 0, l)
	it, err := NewArrayIterator(data)
	if err != nil {
		d.error(err)
	}
	for it.IsValid() {
		value, err := it.Value()
		if err != nil {
			d.error(err)
		}

		v = append(v, d.valueInterface(value))

		// Move to next field
		if err := it.Next(); err != nil {
			d.error(err)
		}
	}
	return v
}

// objectInterface is like object but returns map[string]interface{}.
func (d *decodeState) objectInterface(data Slice) map[string]interface{} {
	m := make(map[string]interface{})
	it, err := NewObjectIterator(data)
	if err != nil {
		d.error(err)
	}
	for it.IsValid() {
		key, err := it.Key(true)
		if err != nil {
			d.error(err)
		}
		keyStr, err := key.GetString()
		if err != nil {
			d.error(err)
		}
		value, err := it.Value()
		if err != nil {
			d.error(err)
		}

		// Read value.
		m[keyStr] = d.valueInterface(value)

		// Move to next field
		if err := it.Next(); err != nil {
			d.error(err)
		}
	}
	return m
}

// literalInterface is like literal but returns an interface value.
func (d *decodeState) literalInterface(data Slice) interface{} {
	switch data.Type() {
	case Null:
		return nil

	case Bool:
		v, err := data.GetBool()
		if err != nil {
			d.error(err)
		}
		return v

	case String:
		v, err := data.GetString()
		if err != nil {
			d.error(err)
		}
		return v

	case Double:
		v, err := data.GetDouble()
		if err != nil {
			d.error(err)
		}
		return v

	case Int, SmallInt:
		v, err := data.GetInt()
		if err != nil {
			d.error(err)
		}
		intV := int(v)
		if int64(intV) == v {
			// Value fits in int
			return intV
		}
		return v

	case UInt:
		v, err := data.GetUInt()
		if err != nil {
			d.error(err)
		}
		return v

	case Binary:
		v, err := data.GetBinary()
		if err != nil {
			d.error(err)
		}
		return v

	default: // ??
		d.error(fmt.Errorf("unknown literal type: %s", data.Type()))
		return nil
	}
}

// literalStore decodes a literal stored in item into v.
//
// fromQuoted indicates whether this literal came from unwrapping a
// string from the ",string" struct tag option. this is used only to
// produce more helpful error messages.
func (d *decodeState) literalStore(item Slice, v reflect.Value, fromQuoted bool) {
	// Check for unmarshaler.
	if len(item) == 0 {
		//Empty string given
		d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal empty slice into %v", v.Type()))
		return
	}
	isNull := item.IsNull() // null
	u, ju, ut, pv := d.indirect(v, isNull)
	if u != nil {
		if err := u.UnmarshalVPack(item); err != nil {
			d.error(err)
		}
		return
	}
	if ju != nil {
		json, err := item.JSONString()
		if err != nil {
			d.error(err)
		} else {
			if err := ju.UnmarshalJSON([]byte(json)); err != nil {
				d.error(err)
			}
		}
		return
	}
	if ut != nil {
		if !item.IsString() {
			//if item[0] != '"' {
			if fromQuoted {
				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal Slice of type %s into %v", item.Type(), v.Type()))
			} else {
				val := item.Type().String()
				d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type()})
			}
			return
		}
		s, err := item.GetStringUTF8()
		if err != nil {
			if fromQuoted {
				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal slice of type %s into %v", item.Type(), v.Type()))
			} else {
				d.error(InternalError) // Out of sync
			}
		}
		if err := ut.UnmarshalText(s); err != nil {
			d.error(err)
		}
		return
	}

	v = pv

	switch item.Type() {
	case Null: // null
		// The main parser checks that only true and false can reach here,
		// but if this was a quoted string input, it could be anything.
		if fromQuoted /*&& string(item) != "null"*/ {
			d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
			break
		}
		switch v.Kind() {
		case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
			v.Set(reflect.Zero(v.Type()))
			// otherwise, ignore null for primitives/string
		}
	case Bool: // true, false
		value, err := item.GetBool()
		if err != nil {
			d.error(err)
		}
		// The main parser checks that only true and false can reach here,
		// but if this was a quoted string input, it could be anything.
		if fromQuoted /*&& string(item) != "true" && string(item) != "false"*/ {
			d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
			break
		}
		switch v.Kind() {
		default:
			if fromQuoted {
				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
			} else {
				d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type()})
			}
		case reflect.Bool:
			v.SetBool(value)
		case reflect.Interface:
			if v.NumMethod() == 0 {
				v.Set(reflect.ValueOf(value))
			} else {
				d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type()})
			}
		}

	case String: // string
		s, err := item.GetString()
		if err != nil {
			d.error(err)
		}
		switch v.Kind() {
		default:
			d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type()})
		case reflect.Slice:
			if v.Type().Elem().Kind() != reflect.Uint8 {
				d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type()})
				break
			}
			b, err := base64.StdEncoding.DecodeString(s)
			if err != nil {
				d.saveError(err)
				break
			}
			v.SetBytes(b)
		case reflect.String:
			v.SetString(string(s))
		case reflect.Interface:
			if v.NumMethod() == 0 {
				v.Set(reflect.ValueOf(string(s)))
			} else {
				d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type()})
			}
		}

	case Double:
		value, err := item.GetDouble()
		if err != nil {
			d.error(err)
		}
		switch v.Kind() {
		default:
			if v.Kind() == reflect.String && v.Type() == numberType {
				s, err := item.JSONString()
				if err != nil {
					d.error(err)
				}
				v.SetString(s)
				break
			}
			if fromQuoted {
				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
			} else {
				d.error(&UnmarshalTypeError{Value: "number", Type: v.Type()})
			}
		case reflect.Interface:
			n, err := d.convertNumber(value)
			if err != nil {
				d.saveError(err)
				break
			}
			if v.NumMethod() != 0 {
				d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type()})
				break
			}
			v.Set(reflect.ValueOf(n))

		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			n := int64(value)
			if err != nil || v.OverflowInt(n) {
				d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
				break
			}
			v.SetInt(n)

		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			n := uint64(value)
			if err != nil || v.OverflowUint(n) {
				d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
				break
			}
			v.SetUint(n)

		case reflect.Float32, reflect.Float64:
			n := value
			v.SetFloat(n)
		}

	case Int, SmallInt:
		value, err := item.GetInt()
		if err != nil {
			d.error(err)
		}
		switch v.Kind() {
		default:
			if v.Kind() == reflect.String && v.Type() == numberType {
				s, err := item.JSONString()
				if err != nil {
					d.error(err)
				}
				v.SetString(s)
				break
			}
			if fromQuoted {
				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
			} else {
				d.error(&UnmarshalTypeError{Value: "number", Type: v.Type()})
			}
		case reflect.Interface:
			var n interface{}
			intValue := int(value)
			if int64(intValue) == value {
				// When the value fits in an int, use int type.
				n, err = d.convertNumber(intValue)
			} else {
				n, err = d.convertNumber(value)
			}
			if err != nil {
				d.saveError(err)
				break
			}
			if v.NumMethod() != 0 {
				d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type()})
				break
			}
			v.Set(reflect.ValueOf(n))

		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			n := value
			if err != nil || v.OverflowInt(n) {
				d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
				break
			}
			v.SetInt(n)

		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			n := uint64(value)
			if err != nil || v.OverflowUint(n) {
				d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
				break
			}
			v.SetUint(n)

		case reflect.Float32, reflect.Float64:
			n := float64(value)
			if err != nil || v.OverflowFloat(n) {
				d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
				break
			}
			v.SetFloat(n)
		}

	case UInt:
		value, err := item.GetUInt()
		if err != nil {
			d.error(err)
		}
		switch v.Kind() {
		default:
			if v.Kind() == reflect.String && v.Type() == numberType {
				s, err := item.JSONString()
				if err != nil {
					d.error(err)
				}
				v.SetString(s)
				break
			}
			if fromQuoted {
				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
			} else {
				d.error(&UnmarshalTypeError{Value: "number", Type: v.Type()})
			}
		case reflect.Interface:
			n, err := d.convertNumber(value)
			if err != nil {
				d.saveError(err)
				break
			}
			if v.NumMethod() != 0 {
				d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type()})
				break
			}
			v.Set(reflect.ValueOf(n))

		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			n := int64(value)
			if err != nil || v.OverflowInt(n) {
				d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
				break
			}
			v.SetInt(n)

		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			n := value
			if err != nil || v.OverflowUint(n) {
				d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
				break
			}
			v.SetUint(n)

		case reflect.Float32, reflect.Float64:
			n := float64(value)
			if err != nil || v.OverflowFloat(n) {
				d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
				break
			}
			v.SetFloat(n)
		}

	case Binary:
		value, err := item.GetBinary()
		if err != nil {
			d.error(err)
		}
		switch v.Kind() {
		default:
			d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type()})
		case reflect.Slice:
			if v.Type().Elem().Kind() != reflect.Uint8 {
				d.saveError(&UnmarshalTypeError{Value: "binary", Type: v.Type()})
				break
			}
			v.SetBytes(value)
		case reflect.Interface:
			if v.NumMethod() == 0 {
				v.Set(reflect.ValueOf(value))
			} else {
				d.saveError(&UnmarshalTypeError{Value: "binary", Type: v.Type()})
			}
		}

	default: // number
		d.error(fmt.Errorf("Unknown type %s", item.Type()))
	}
}

// convertNumber converts the number literal s to a float64 or a Number
// depending on the setting of d.useNumber.
func (d *decodeState) convertNumber(s interface{}) (interface{}, error) {
	if d.useNumber {
		return json.Number(fmt.Sprintf("%v", s)), nil
	}
	return s, nil
}