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.

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