Convert should only handle specific types
This commit is contained in:
@@ -350,20 +350,6 @@ type errStruct struct {
|
|||||||
String *string `toml:"string"`
|
String *string `toml:"string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var errTomls = []string{
|
|
||||||
"bool = truly\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
|
|
||||||
"bool = true\ndate = 1979-05-27T07:3200Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
|
|
||||||
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123a4\nint = 5000\nstring = \"Bite me\"",
|
|
||||||
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = j000\nstring = \"Bite me\"",
|
|
||||||
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
|
|
||||||
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
|
|
||||||
"bool = 1\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
|
|
||||||
"bool = true\ndate = 1\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
|
|
||||||
"bool = true\ndate = 1979-05-27T07:32:00Z\n\"sorry\"\nint = 5000\nstring = \"Bite me\"",
|
|
||||||
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = \"sorry\"\nstring = \"Bite me\"",
|
|
||||||
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = 1",
|
|
||||||
}
|
|
||||||
|
|
||||||
type mapErr struct {
|
type mapErr struct {
|
||||||
Vals map[string]float64
|
Vals map[string]float64
|
||||||
}
|
}
|
||||||
@@ -399,12 +385,28 @@ var intErrTomls = []string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestErrUnmarshal(t *testing.T) {
|
func TestErrUnmarshal(t *testing.T) {
|
||||||
|
var errTomls = []string{
|
||||||
|
"bool = truly\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
|
||||||
|
"bool = true\ndate = 1979-05-27T07:3200Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
|
||||||
|
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123a4\nint = 5000\nstring = \"Bite me\"",
|
||||||
|
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = j000\nstring = \"Bite me\"",
|
||||||
|
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
|
||||||
|
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
|
||||||
|
"bool = 1\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
|
||||||
|
"bool = true\ndate = 1\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
|
||||||
|
"bool = true\ndate = 1979-05-27T07:32:00Z\n\"sorry\"\nint = 5000\nstring = \"Bite me\"",
|
||||||
|
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = \"sorry\"\nstring = \"Bite me\"",
|
||||||
|
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = 1",
|
||||||
|
}
|
||||||
|
|
||||||
for ind, x := range errTomls {
|
for ind, x := range errTomls {
|
||||||
|
t.Run(fmt.Sprintf("Base Case %d", ind), func(t *testing.T) {
|
||||||
result := errStruct{}
|
result := errStruct{}
|
||||||
err := toml.Unmarshal([]byte(x), &result)
|
err := toml.Unmarshal([]byte(x), &result)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected err from case %d\n", ind)
|
t.Errorf("Expected err from case %d\n", ind)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
result2 := mapErr{}
|
result2 := mapErr{}
|
||||||
err := toml.Unmarshal([]byte("[Vals]\nfred=\"1.2\""), &result2)
|
err := toml.Unmarshal([]byte("[Vals]\nfred=\"1.2\""), &result2)
|
||||||
|
|||||||
@@ -22,13 +22,6 @@ type target interface {
|
|||||||
fmt.Stringer
|
fmt.Stringer
|
||||||
}
|
}
|
||||||
|
|
||||||
func isAssignable(t reflect.Type, v reflect.Value) error {
|
|
||||||
if v.Type().AssignableTo(t) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("cannot assign '%s' ('%s') to a '%s'", v, v.Type(), t)
|
|
||||||
}
|
|
||||||
|
|
||||||
type valueTarget reflect.Value
|
type valueTarget reflect.Value
|
||||||
|
|
||||||
func (v valueTarget) get() reflect.Value {
|
func (v valueTarget) get() reflect.Value {
|
||||||
@@ -39,6 +32,9 @@ func (v valueTarget) set(value reflect.Value) error {
|
|||||||
rv := reflect.Value(v)
|
rv := reflect.Value(v)
|
||||||
|
|
||||||
// value is guaranteed to be a pointer
|
// value is guaranteed to be a pointer
|
||||||
|
if value.Kind() != reflect.Ptr {
|
||||||
|
panic(fmt.Sprintf("set() should receive a pointer, not a '%s'", value.Kind()))
|
||||||
|
}
|
||||||
|
|
||||||
if rv.Kind() != reflect.Ptr {
|
if rv.Kind() != reflect.Ptr {
|
||||||
// TODO: check value is nil?
|
// TODO: check value is nil?
|
||||||
@@ -46,12 +42,12 @@ func (v valueTarget) set(value reflect.Value) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
targetType := rv.Type()
|
targetType := rv.Type()
|
||||||
value, err := tryConvert(targetType, value)
|
value, err := convert(targetType, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
reflect.Value(v).Set(value)
|
rv.Set(value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +73,7 @@ func (v mapTarget) set(value reflect.Value) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
targetType := v.m.Type().Elem()
|
targetType := v.m.Type().Elem()
|
||||||
value, err := tryConvert(targetType, value)
|
value, err := convert(targetType, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -277,7 +273,7 @@ func (b *Builder) DigField(s string) error {
|
|||||||
// TODO: handle error when map is not indexed by strings
|
// TODO: handle error when map is not indexed by strings
|
||||||
key := reflect.ValueOf(s)
|
key := reflect.ValueOf(s)
|
||||||
|
|
||||||
key, err := tryConvert(v.Type().Key(), key)
|
key, err := convert(v.Type().Key(), key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -433,7 +429,7 @@ func (b *Builder) SliceAppend(value reflect.Value) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if v.Type().Elem() != value.Type() {
|
if v.Type().Elem() != value.Type() {
|
||||||
//nv, err := tryConvert(v.Type().Elem(), value)
|
//nv, err := convert(v.Type().Elem(), value)
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
return fmt.Errorf("cannot assign '%s' to '%s'", value.Type(), v.Type().Elem())
|
return fmt.Errorf("cannot assign '%s' to '%s'", value.Type(), v.Type().Elem())
|
||||||
//}
|
//}
|
||||||
@@ -446,7 +442,19 @@ func (b *Builder) SliceAppend(value reflect.Value) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryConvert(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
// convert value so that it can be assigned to t.
|
||||||
|
//
|
||||||
|
// Conversion rules:
|
||||||
|
//
|
||||||
|
// * Pointers are de-referenced as needed.
|
||||||
|
// * Integer types are converted between each other as long as they don't
|
||||||
|
// overflow.
|
||||||
|
// * Float types are converted between each other as long as they don't
|
||||||
|
// overflow.
|
||||||
|
//
|
||||||
|
// TODO: this function acts as a switchboard. Runtime has enough information to
|
||||||
|
// generate per-type functions avoiding the double type switches.
|
||||||
|
func convert(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
||||||
result := value
|
result := value
|
||||||
|
|
||||||
if value.Type().AssignableTo(t) {
|
if value.Type().AssignableTo(t) {
|
||||||
@@ -462,13 +470,20 @@ func tryConvert(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
|||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !value.Type().ConvertibleTo(t) {
|
var err error
|
||||||
return result, fmt.Errorf("cannot convert '%s' to '%s'", value.Type(), t)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
value.Convert(reflect.TypeOf(int64(0)))
|
value, err = convertInt(t, value)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
value, err = convertUint(t, value)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
value, err = convertFloat(t, value)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("not converting a %s into a %s", value.Kind(), t.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return value, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result = reflect.New(t)
|
result = reflect.New(t)
|
||||||
@@ -476,6 +491,39 @@ func tryConvert(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
|||||||
return result.Elem(), nil
|
return result.Elem(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertInt(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return value.Convert(t), nil // reflect.TypeOf(int64(0))
|
||||||
|
default:
|
||||||
|
return value, fmt.Errorf("cannot convert %s to integer (%s)", value.Kind(), t.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertUint(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
return value.Convert(t), nil // reflect.TypeOf(int64(0))
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
x := value.Int()
|
||||||
|
if x < 0 {
|
||||||
|
return value, fmt.Errorf("cannot store negative integer '%d' into %s", x, t.Kind())
|
||||||
|
}
|
||||||
|
return value.Convert(t), nil
|
||||||
|
default:
|
||||||
|
return value, fmt.Errorf("cannot convert %s to unsigned integer (%s)", value.Kind(), t.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertFloat(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return value.Convert(t), nil
|
||||||
|
default:
|
||||||
|
return value, fmt.Errorf("cannot convert %s to integer (%s)", value.Kind(), t.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set the value at the cursor to the given string.
|
// Set the value at the cursor to the given string.
|
||||||
// Errors if a string cannot be assigned to the current value.
|
// Errors if a string cannot be assigned to the current value.
|
||||||
func (b *Builder) SetString(s string) error {
|
func (b *Builder) SetString(s string) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user