toX.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package core
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "github.com/mattn/anko/env"
  9. )
  10. // ImportToX adds all the toX to the env given
  11. func ImportToX(e *env.Env) {
  12. e.Define("toBool", func(v interface{}) bool {
  13. rv := reflect.ValueOf(v)
  14. if !rv.IsValid() {
  15. return false
  16. }
  17. nt := reflect.TypeOf(true)
  18. if rv.Type().ConvertibleTo(nt) {
  19. return rv.Convert(nt).Bool()
  20. }
  21. if rv.Type().ConvertibleTo(reflect.TypeOf(1.0)) && rv.Convert(reflect.TypeOf(1.0)).Float() > 0.0 {
  22. return true
  23. }
  24. if rv.Kind() == reflect.String {
  25. s := strings.ToLower(v.(string))
  26. if s == "y" || s == "yes" {
  27. return true
  28. }
  29. b, err := strconv.ParseBool(s)
  30. if err == nil {
  31. return b
  32. }
  33. }
  34. return false
  35. })
  36. e.Define("toString", func(v interface{}) string {
  37. if b, ok := v.([]byte); ok {
  38. return string(b)
  39. }
  40. return fmt.Sprint(v)
  41. })
  42. e.Define("toInt", func(v interface{}) int64 {
  43. rv := reflect.ValueOf(v)
  44. if !rv.IsValid() {
  45. return 0
  46. }
  47. nt := reflect.TypeOf(1)
  48. if rv.Type().ConvertibleTo(nt) {
  49. return rv.Convert(nt).Int()
  50. }
  51. if rv.Kind() == reflect.String {
  52. i, err := strconv.ParseInt(v.(string), 10, 64)
  53. if err == nil {
  54. return i
  55. }
  56. f, err := strconv.ParseFloat(v.(string), 64)
  57. if err == nil {
  58. return int64(f)
  59. }
  60. }
  61. if rv.Kind() == reflect.Bool {
  62. if v.(bool) {
  63. return 1
  64. }
  65. }
  66. return 0
  67. })
  68. e.Define("toFloat", func(v interface{}) float64 {
  69. rv := reflect.ValueOf(v)
  70. if !rv.IsValid() {
  71. return 0
  72. }
  73. nt := reflect.TypeOf(1.0)
  74. if rv.Type().ConvertibleTo(nt) {
  75. return rv.Convert(nt).Float()
  76. }
  77. if rv.Kind() == reflect.String {
  78. f, err := strconv.ParseFloat(v.(string), 64)
  79. if err == nil {
  80. return f
  81. }
  82. }
  83. if rv.Kind() == reflect.Bool {
  84. if v.(bool) {
  85. return 1.0
  86. }
  87. }
  88. return 0.0
  89. })
  90. e.Define("toChar", func(s rune) string {
  91. return string(s)
  92. })
  93. e.Define("toRune", func(s string) rune {
  94. if len(s) == 0 {
  95. return 0
  96. }
  97. return []rune(s)[0]
  98. })
  99. e.Define("toBoolSlice", func(v []interface{}) []bool {
  100. var result []bool
  101. toSlice(v, &result)
  102. return result
  103. })
  104. e.Define("toStringSlice", func(v []interface{}) []string {
  105. var result []string
  106. toSlice(v, &result)
  107. return result
  108. })
  109. e.Define("toIntSlice", func(v []interface{}) []int64 {
  110. var result []int64
  111. toSlice(v, &result)
  112. return result
  113. })
  114. e.Define("toFloatSlice", func(v []interface{}) []float64 {
  115. var result []float64
  116. toSlice(v, &result)
  117. return result
  118. })
  119. e.Define("toByteSlice", func(s string) []byte {
  120. return []byte(s)
  121. })
  122. e.Define("toRuneSlice", func(s string) []rune {
  123. return []rune(s)
  124. })
  125. e.Define("toDuration", func(v int64) time.Duration {
  126. return time.Duration(v)
  127. })
  128. }
  129. // toSlice takes in a "generic" slice and converts and copies
  130. // it's elements into the typed slice pointed at by ptr.
  131. // Note that this is a costly operation.
  132. func toSlice(from []interface{}, ptr interface{}) {
  133. // Value of the pointer to the target
  134. obj := reflect.Indirect(reflect.ValueOf(ptr))
  135. // We can't just convert from interface{} to whatever the target is (diff memory layout),
  136. // so we need to create a New slice of the proper type and copy the values individually
  137. t := reflect.TypeOf(ptr).Elem()
  138. tt := t.Elem()
  139. slice := reflect.MakeSlice(t, len(from), len(from))
  140. // Copying the data, val is an addressable Pointer of the actual target type
  141. val := reflect.Indirect(reflect.New(tt))
  142. for i := 0; i < len(from); i++ {
  143. v := reflect.ValueOf(from[i])
  144. if v.IsValid() && v.Type().ConvertibleTo(tt) {
  145. val.Set(v.Convert(tt))
  146. } else {
  147. val.Set(reflect.Zero(tt))
  148. }
  149. slice.Index(i).Set(val)
  150. }
  151. // Ok now assign our slice to the target pointer
  152. obj.Set(slice)
  153. }