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.

92 lines
2.3 KiB

  1. package JsonSerialization
  2. import (
  3. "math"
  4. "reflect"
  5. )
  6. // isIntegerType returns whether the type is an integer and if it's unsigned.
  7. // See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L328
  8. func isIntegerType(t reflect.Type) (yes bool, unsigned bool) {
  9. switch t.Kind() {
  10. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  11. yes = true
  12. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  13. yes = true
  14. unsigned = true
  15. }
  16. return
  17. }
  18. // isFloatType returns true if the type is a floating point. Note that this doesn't
  19. // care about the value -- unmarshaling the number "0" gives a float, not an int.
  20. // See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L319
  21. func isFloatType(t reflect.Type) (yes bool) {
  22. switch t.Kind() {
  23. case reflect.Float32, reflect.Float64:
  24. yes = true
  25. }
  26. return
  27. }
  28. // CanConvert returns whether value v is convertible to type t.
  29. //
  30. // If t is a pointer and v is not nil, it checks if v is convertible to the type that
  31. // t points to.
  32. // Modified due to not handling slices (DefaultCanConvert fails on PhotoUrls and Tags)
  33. // See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L191
  34. func CanConvert(t reflect.Type, v reflect.Value) bool {
  35. isPtr := t.Kind() == reflect.Ptr
  36. isStruct := t.Kind() == reflect.Struct
  37. isArray := t.Kind() == reflect.Array
  38. dstType := t
  39. // Check if v is a nil value.
  40. if !v.IsValid() || (v.CanAddr() && v.IsNil()) {
  41. return isPtr
  42. }
  43. // If the dst is a pointer, check if we can convert to the type it's pointing to.
  44. if isPtr {
  45. dstType = t.Elem()
  46. isStruct = t.Elem().Kind() == reflect.Struct
  47. }
  48. // If the dst is a struct, we should check its nested fields.
  49. if isStruct {
  50. return v.Kind() == reflect.Map
  51. }
  52. if isArray {
  53. return v.Kind() == reflect.String
  54. }
  55. if t.Kind() == reflect.Slice {
  56. return v.Kind() == reflect.Slice
  57. }
  58. if !v.Type().ConvertibleTo(dstType) {
  59. return false
  60. }
  61. // Handle converting to an integer type.
  62. if dstInt, unsigned := isIntegerType(dstType); dstInt {
  63. if isFloatType(v.Type()) {
  64. f := v.Float()
  65. if math.Trunc(f) != f {
  66. return false
  67. } else if unsigned && f < 0 {
  68. return false
  69. }
  70. } else if srcInt, _ := isIntegerType(v.Type()); srcInt {
  71. if unsigned && v.Int() < 0 {
  72. return false
  73. }
  74. }
  75. }
  76. return true
  77. }