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  }