diff --git a/values/convert.go b/values/convert.go index bbe923d..c75932f 100644 --- a/values/convert.go +++ b/values/convert.go @@ -31,6 +31,28 @@ func conversionError(modifier string, value interface{}, typ reflect.Type) error return typeErrorf("can't convert %s%T(%v) to type %s", modifier, value, value, typ) } +func convertValueToInt(value interface{}, typ reflect.Type) (int64, error) { + switch value := value.(type) { + case bool: + if value { + return 1, nil + } + return 0, nil + case string: + return strconv.ParseInt(value, 10, 64) + } + return 0, conversionError("", value, typ) +} + +func convertValueToFloat(value interface{}, typ reflect.Type) (float64, error) { + switch value := value.(type) { + // case int is handled by rv.Convert(typ) in Convert function + case string: + return strconv.ParseFloat(value, 64) + } + return 0, conversionError("", value, typ) +} + // Convert value to the type. This is a more aggressive conversion, that will // recursively create new map and slice values as necessary. It doesn't // handle circular references. @@ -51,22 +73,42 @@ func Convert(value interface{}, typ reflect.Type) (interface{}, error) { // noli switch typ.Kind() { case reflect.Bool: return !(value == nil || value == false), nil - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch value := value.(type) { - case bool: - if value { - return 1, nil - } - return 0, nil - case string: - return strconv.Atoi(value) - } - case reflect.Float32, reflect.Float64: - switch value := value.(type) { - // case int is handled by r.Convert(type) above - case string: - return strconv.ParseFloat(value, 64) - } + case reflect.Uint: + v, err := convertValueToInt(value, typ) + return uint(v), err + case reflect.Uint8: + v, err := convertValueToInt(value, typ) + return uint8(v), err + case reflect.Uint16: + v, err := convertValueToInt(value, typ) + return uint16(v), err + case reflect.Uint32: + v, err := convertValueToInt(value, typ) + return uint32(v), err + case reflect.Uint64: + v, err := convertValueToInt(value, typ) + return uint64(v), err + case reflect.Int: + v, err := convertValueToInt(value, typ) + return int(v), err + case reflect.Int8: + v, err := convertValueToInt(value, typ) + return int8(v), err + case reflect.Int16: + v, err := convertValueToInt(value, typ) + return int16(v), err + case reflect.Int32: + v, err := convertValueToInt(value, typ) + return int32(v), err + case reflect.Int64: + v, err := convertValueToInt(value, typ) + return v, err + case reflect.Float32: + v, err := convertValueToFloat(value, typ) + return float32(v), err + case reflect.Float64: + v, err := convertValueToFloat(value, typ) + return v, err case reflect.Map: et := typ.Elem() result := reflect.MakeMap(typ) diff --git a/values/convert_test.go b/values/convert_test.go index d03f292..e290f3d 100644 --- a/values/convert_test.go +++ b/values/convert_test.go @@ -23,7 +23,27 @@ var convertTests = []struct { }{ {nil, false}, {false, 0}, + {false, int(0)}, + {false, int8(0)}, + {false, int16(0)}, + {false, int32(0)}, + {false, int64(0)}, + {false, uint(0)}, + {false, uint8(0)}, + {false, uint16(0)}, + {false, uint32(0)}, + {false, uint64(0)}, {true, 1}, + {true, int(1)}, + {true, int8(1)}, + {true, int16(1)}, + {true, int32(1)}, + {true, int64(1)}, + {true, uint(1)}, + {true, uint8(1)}, + {true, uint16(1)}, + {true, uint32(1)}, + {true, uint64(1)}, {false, false}, {true, true}, {true, "true"}, @@ -33,10 +53,22 @@ var convertTests = []struct { {2, "2"}, {2, 2.0}, {"", true}, + {"2", int(2)}, + {"2", int8(2)}, + {"2", int16(2)}, + {"2", int32(2)}, + {"2", int64(2)}, + {"2", uint(2)}, + {"2", uint8(2)}, + {"2", uint16(2)}, + {"2", uint32(2)}, + {"2", uint64(2)}, {"2", 2}, {"2", 2.0}, {"2.0", 2.0}, {"2.1", 2.1}, + {"2.1", float32(2.1)}, + {"2.1", float64(2.1)}, {"string", "string"}, {[]interface{}{1, 2}, []interface{}{1, 2}}, {[]int{1, 2}, []int{1, 2}},