You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
2.2 KiB

package api
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) (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
}
// 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) (yes bool) {
switch t.Kind() {
case reflect.Float32, reflect.Float64:
yes = true
}
return
}
// 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 {
isPtr := t.Kind() == reflect.Ptr
isStruct := t.Kind() == reflect.Struct
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 t.Kind() == reflect.Slice {
return v.Kind() == reflect.Slice
}
if !v.Type().ConvertibleTo(dstType) {
return false
}
// Handle converting to an integer type.
if dstInt, unsigned := isIntegerType(dstType); dstInt {
if isFloatType(v.Type()) {
f := v.Float()
if math.Trunc(f) != f {
return false
} else if unsigned && f < 0 {
return false
}
} else if srcInt, _ := isIntegerType(v.Type()); srcInt {
if unsigned && v.Int() < 0 {
return false
}
}
}
return true
}