mirror of
https://github.com/danog/liquid.git
synced 2024-11-26 23:34:47 +01:00
Properly handle implicit conversion to integer types.
Go's reflect API is very picky about arguments to Call method. You can't just pass in the "int" when function expects "int64", even on 64 bit machines. This patch solves this problem by performing conversions properly. Truncation problems however, as well as negative to uint issues are completely ignored. Which is perhaps not ideal, but still better than returning "int" when "int32" or "int64" is requested. I did split the Kind switch cases and moved value -> int and value -> float conversions to separate functions. An alternative to that would be using the reflection API, which might be less performant. Not that it matters much, but this solution is correct, even though looks a bit copy & pasty. Oh and of course all "uint" types were completely missing in the function and they are now added.
This commit is contained in:
parent
aadc886acd
commit
4354d48a04
@ -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)
|
||||
|
@ -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}},
|
||||
|
Loading…
Reference in New Issue
Block a user