|
|
- 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) (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
- 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.
- 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
- }
|