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