package JsonSerialization
|
|
|
|
import (
|
|
"math"
|
|
"reflect"
|
|
)
|
|
|
|
// isIntegerType returns whether the type is an integer and if it's unsigned.
|
|
// See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L328
|
|
func isIntegerType(t reflect.Type) (bool, bool) {
|
|
var (
|
|
yes bool
|
|
unsigned bool
|
|
)
|
|
switch t.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
yes = true
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
yes = true
|
|
unsigned = true
|
|
}
|
|
|
|
return yes, unsigned
|
|
}
|
|
|
|
// isFloatType returns true if the type is a floating point. Note that this doesn't
|
|
// care about the value -- unmarshaling the number "0" gives a float, not an int.
|
|
// See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L319
|
|
func isFloatType(t reflect.Type) bool {
|
|
var (
|
|
yes bool
|
|
)
|
|
switch t.Kind() {
|
|
case reflect.Float32, reflect.Float64:
|
|
yes = true
|
|
}
|
|
|
|
return yes
|
|
}
|
|
|
|
// CanConvert returns whether value v is convertible to type t.
|
|
//
|
|
// If t is a pointer and v is not nil, it checks if v is convertible to the type that
|
|
// t points to.
|
|
// Modified due to not handling slices (DefaultCanConvert fails on PhotoUrls and Tags)
|
|
// See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L191
|
|
func CanConvert(t reflect.Type, v reflect.Value) bool {
|
|
var (
|
|
isPtr bool
|
|
isStruct bool
|
|
isArray bool
|
|
dstType reflect.Type
|
|
dstInt bool
|
|
unsigned bool
|
|
f float64
|
|
srcInt bool
|
|
)
|
|
isPtr = t.Kind() == reflect.Ptr
|
|
isStruct = t.Kind() == reflect.Struct
|
|
isArray = t.Kind() == reflect.Array
|
|
dstType = t
|
|
|
|
// Check if v is a nil value.
|
|
if !v.IsValid() || (v.CanAddr() && v.IsNil()) {
|
|
return isPtr
|
|
}
|
|
|
|
// If the dst is a pointer, check if we can convert to the type it's pointing to.
|
|
if isPtr {
|
|
dstType = t.Elem()
|
|
isStruct = t.Elem().Kind() == reflect.Struct
|
|
}
|
|
|
|
// If the dst is a struct, we should check its nested fields.
|
|
if isStruct {
|
|
return v.Kind() == reflect.Map
|
|
}
|
|
|
|
if isArray {
|
|
return v.Kind() == reflect.String
|
|
}
|
|
|
|
if t.Kind() == reflect.Slice {
|
|
return v.Kind() == reflect.Slice
|
|
}
|
|
|
|
if !v.Type().ConvertibleTo(dstType) {
|
|
return false
|
|
}
|
|
|
|
// Handle converting to an integer type.
|
|
dstInt, unsigned = isIntegerType(dstType)
|
|
if dstInt {
|
|
if isFloatType(v.Type()) {
|
|
f = v.Float()
|
|
|
|
if math.Trunc(f) != f || unsigned && f < 0 {
|
|
return false
|
|
}
|
|
}
|
|
srcInt, _ = isIntegerType(v.Type())
|
|
if srcInt && unsigned && v.Int() < 0 {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|