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

3 years ago
  1. package api
  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. dstType := t
  38. // Check if v is a nil value.
  39. if !v.IsValid() || (v.CanAddr() && v.IsNil()) {
  40. return isPtr
  41. }
  42. // If the dst is a pointer, check if we can convert to the type it's pointing to.
  43. if isPtr {
  44. dstType = t.Elem()
  45. isStruct = t.Elem().Kind() == reflect.Struct
  46. }
  47. // If the dst is a struct, we should check its nested fields.
  48. if isStruct {
  49. return v.Kind() == reflect.Map
  50. }
  51. if t.Kind() == reflect.Slice {
  52. return v.Kind() == reflect.Slice
  53. }
  54. if !v.Type().ConvertibleTo(dstType) {
  55. return false
  56. }
  57. // Handle converting to an integer type.
  58. if dstInt, unsigned := isIntegerType(dstType); dstInt {
  59. if isFloatType(v.Type()) {
  60. f := v.Float()
  61. if math.Trunc(f) != f {
  62. return false
  63. } else if unsigned && f < 0 {
  64. return false
  65. }
  66. } else if srcInt, _ := isIntegerType(v.Type()); srcInt {
  67. if unsigned && v.Int() < 0 {
  68. return false
  69. }
  70. }
  71. }
  72. return true
  73. }