// +build !go1.7 safe appengine

// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

package codec

import (
	"reflect"
	"sync/atomic"
	"time"
)

const safeMode = true

// stringView returns a view of the []byte as a string.
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
// In regular safe mode, it is an allocation and copy.
//
// Usage: Always maintain a reference to v while result of this call is in use,
//        and call keepAlive4BytesView(v) at point where done with view.
func stringView(v []byte) string {
	return string(v)
}

// bytesView returns a view of the string as a []byte.
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
// In regular safe mode, it is an allocation and copy.
//
// Usage: Always maintain a reference to v while result of this call is in use,
//        and call keepAlive4BytesView(v) at point where done with view.
func bytesView(v string) []byte {
	return []byte(v)
}

// isNil says whether the value v is nil.
// This applies to references like map/ptr/unsafepointer/chan/func,
// and non-reference values like interface/slice.
func isNil(v interface{}) (rv reflect.Value, isnil bool) {
	rv = rv4i(v)
	if isnilBitset.isset(byte(rv.Kind())) {
		isnil = rv.IsNil()
	}
	return
}

func rv4i(i interface{}) reflect.Value {
	return reflect.ValueOf(i)
}

func rv2i(rv reflect.Value) interface{} {
	return rv.Interface()
}

func rvIsNil(rv reflect.Value) bool {
	return rv.IsNil()
}

func rvSetSliceLen(rv reflect.Value, length int) {
	rv.SetLen(length)
}

func rvZeroAddrK(t reflect.Type, k reflect.Kind) reflect.Value {
	return reflect.New(t).Elem()
}

func rvConvert(v reflect.Value, t reflect.Type) (rv reflect.Value) {
	return v.Convert(t)
}

func rt2id(rt reflect.Type) uintptr {
	return rv4i(rt).Pointer()
}

func i2rtid(i interface{}) uintptr {
	return rv4i(reflect.TypeOf(i)).Pointer()
}

// --------------------------

func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool {
	switch v.Kind() {
	case reflect.Invalid:
		return true
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Ptr:
		if deref {
			if v.IsNil() {
				return true
			}
			return isEmptyValue(v.Elem(), tinfos, deref, checkStruct)
		}
		return v.IsNil()
	case reflect.Struct:
		return isEmptyStruct(v, tinfos, deref, checkStruct)
	}
	return false
}

// --------------------------
type atomicClsErr struct {
	v atomic.Value
}

func (x *atomicClsErr) load() (e clsErr) {
	if i := x.v.Load(); i != nil {
		e = i.(clsErr)
	}
	return
}

func (x *atomicClsErr) store(p clsErr) {
	x.v.Store(p)
}

// --------------------------
type atomicTypeInfoSlice struct { // expected to be 2 words
	v atomic.Value
}

func (x *atomicTypeInfoSlice) load() (e []rtid2ti) {
	if i := x.v.Load(); i != nil {
		e = i.([]rtid2ti)
	}
	return
}

func (x *atomicTypeInfoSlice) store(p []rtid2ti) {
	x.v.Store(p)
}

// --------------------------
type atomicRtidFnSlice struct { // expected to be 2 words
	v atomic.Value
}

func (x *atomicRtidFnSlice) load() (e []codecRtidFn) {
	if i := x.v.Load(); i != nil {
		e = i.([]codecRtidFn)
	}
	return
}

func (x *atomicRtidFnSlice) store(p []codecRtidFn) {
	x.v.Store(p)
}

// --------------------------
func (n *fauxUnion) ru() reflect.Value {
	return rv4i(&n.u).Elem()
}
func (n *fauxUnion) ri() reflect.Value {
	return rv4i(&n.i).Elem()
}
func (n *fauxUnion) rf() reflect.Value {
	return rv4i(&n.f).Elem()
}
func (n *fauxUnion) rl() reflect.Value {
	return rv4i(&n.l).Elem()
}
func (n *fauxUnion) rs() reflect.Value {
	return rv4i(&n.s).Elem()
}
func (n *fauxUnion) rt() reflect.Value {
	return rv4i(&n.t).Elem()
}
func (n *fauxUnion) rb() reflect.Value {
	return rv4i(&n.b).Elem()
}

// --------------------------
func rvSetBytes(rv reflect.Value, v []byte) {
	rv.SetBytes(v)
}

func rvSetString(rv reflect.Value, v string) {
	rv.SetString(v)
}

func rvSetBool(rv reflect.Value, v bool) {
	rv.SetBool(v)
}

func rvSetTime(rv reflect.Value, v time.Time) {
	rv.Set(rv4i(v))
}

func rvSetFloat32(rv reflect.Value, v float32) {
	rv.SetFloat(float64(v))
}

func rvSetFloat64(rv reflect.Value, v float64) {
	rv.SetFloat(v)
}

func rvSetInt(rv reflect.Value, v int) {
	rv.SetInt(int64(v))
}

func rvSetInt8(rv reflect.Value, v int8) {
	rv.SetInt(int64(v))
}

func rvSetInt16(rv reflect.Value, v int16) {
	rv.SetInt(int64(v))
}

func rvSetInt32(rv reflect.Value, v int32) {
	rv.SetInt(int64(v))
}

func rvSetInt64(rv reflect.Value, v int64) {
	rv.SetInt(v)
}

func rvSetUint(rv reflect.Value, v uint) {
	rv.SetUint(uint64(v))
}

func rvSetUintptr(rv reflect.Value, v uintptr) {
	rv.SetUint(uint64(v))
}

func rvSetUint8(rv reflect.Value, v uint8) {
	rv.SetUint(uint64(v))
}

func rvSetUint16(rv reflect.Value, v uint16) {
	rv.SetUint(uint64(v))
}

func rvSetUint32(rv reflect.Value, v uint32) {
	rv.SetUint(uint64(v))
}

func rvSetUint64(rv reflect.Value, v uint64) {
	rv.SetUint(v)
}

// ----------------

// rvSetDirect is rv.Set for all kinds except reflect.Interface
func rvSetDirect(rv reflect.Value, v reflect.Value) {
	rv.Set(v)
}

// rvSlice returns a slice of the slice of lenth
func rvSlice(rv reflect.Value, length int) reflect.Value {
	return rv.Slice(0, length)
}

// ----------------

func rvSliceIndex(rv reflect.Value, i int, ti *typeInfo) reflect.Value {
	return rv.Index(i)
}

func rvGetSliceLen(rv reflect.Value) int {
	return rv.Len()
}

func rvGetSliceCap(rv reflect.Value) int {
	return rv.Cap()
}

func rvGetArrayBytesRO(rv reflect.Value, scratch []byte) (bs []byte) {
	l := rv.Len()
	if rv.CanAddr() {
		return rvGetBytes(rv.Slice(0, l))
	}

	if l <= cap(scratch) {
		bs = scratch[:l]
	} else {
		bs = make([]byte, l)
	}
	reflect.Copy(rv4i(bs), rv)
	return
}

func rvGetArray4Slice(rv reflect.Value) (v reflect.Value) {
	v = rvZeroAddrK(reflectArrayOf(rvGetSliceLen(rv), rv.Type().Elem()), reflect.Array)
	reflect.Copy(v, rv)
	return
}

func rvGetSlice4Array(rv reflect.Value, tslice reflect.Type) (v reflect.Value) {
	return rv.Slice(0, rv.Len())
}

func rvCopySlice(dest, src reflect.Value) {
	reflect.Copy(dest, src)
}

// ------------

func rvGetBool(rv reflect.Value) bool {
	return rv.Bool()
}

func rvGetBytes(rv reflect.Value) []byte {
	return rv.Bytes()
}

func rvGetTime(rv reflect.Value) time.Time {
	return rv2i(rv).(time.Time)
}

func rvGetString(rv reflect.Value) string {
	return rv.String()
}

func rvGetFloat64(rv reflect.Value) float64 {
	return rv.Float()
}

func rvGetFloat32(rv reflect.Value) float32 {
	return float32(rv.Float())
}

func rvGetInt(rv reflect.Value) int {
	return int(rv.Int())
}

func rvGetInt8(rv reflect.Value) int8 {
	return int8(rv.Int())
}

func rvGetInt16(rv reflect.Value) int16 {
	return int16(rv.Int())
}

func rvGetInt32(rv reflect.Value) int32 {
	return int32(rv.Int())
}

func rvGetInt64(rv reflect.Value) int64 {
	return rv.Int()
}

func rvGetUint(rv reflect.Value) uint {
	return uint(rv.Uint())
}

func rvGetUint8(rv reflect.Value) uint8 {
	return uint8(rv.Uint())
}

func rvGetUint16(rv reflect.Value) uint16 {
	return uint16(rv.Uint())
}

func rvGetUint32(rv reflect.Value) uint32 {
	return uint32(rv.Uint())
}

func rvGetUint64(rv reflect.Value) uint64 {
	return rv.Uint()
}

func rvGetUintptr(rv reflect.Value) uintptr {
	return uintptr(rv.Uint())
}

// ------------ map range and map indexing ----------

func mapGet(m, k, v reflect.Value) (vv reflect.Value) {
	return m.MapIndex(k)
}

func mapSet(m, k, v reflect.Value) {
	m.SetMapIndex(k, v)
}

func mapDelete(m, k reflect.Value) {
	m.SetMapIndex(k, reflect.Value{})
}

// return an addressable reflect value that can be used in mapRange and mapGet operations.
//
// all calls to mapGet or mapRange will call here to get an addressable reflect.Value.
func mapAddressableRV(t reflect.Type, k reflect.Kind) (r reflect.Value) {
	return // reflect.New(t).Elem()
}

// ---------- ENCODER optimized ---------------

func (e *Encoder) jsondriver() *jsonEncDriver {
	return e.e.(*jsonEncDriver)
}

// ---------- DECODER optimized ---------------

func (d *Decoder) checkBreak() bool {
	return d.d.CheckBreak()
}

func (d *Decoder) jsondriver() *jsonDecDriver {
	return d.d.(*jsonDecDriver)
}
