Specialize array unmarshal into []interface{}
This commit is contained in:
+44
-1
@@ -11,6 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/pelletier/go-toml/v2/internal/ast"
|
"github.com/pelletier/go-toml/v2/internal/ast"
|
||||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||||
@@ -620,15 +621,57 @@ func (d *decoder) handleValue(value *ast.Node, v reflect.Value) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *decoder) unmarshalArrayFastSliceInterface(array *ast.Node, v reflect.Value) error {
|
||||||
|
ifaceType := v.Type().Elem()
|
||||||
|
|
||||||
|
sp := (*[]interface{})(unsafe.Pointer(v.UnsafeAddr()))
|
||||||
|
s := *sp
|
||||||
|
|
||||||
|
if s == nil {
|
||||||
|
s = make([]interface{}, 0, 16)
|
||||||
|
} else {
|
||||||
|
s = s[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
var x interface{}
|
||||||
|
|
||||||
|
it := array.Children()
|
||||||
|
for it.Next() {
|
||||||
|
n := it.Node()
|
||||||
|
|
||||||
|
idx := len(s)
|
||||||
|
s = append(s, x)
|
||||||
|
|
||||||
|
datap := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s)).Data)
|
||||||
|
elemP := danger.Stride(datap, unsafe.Sizeof(x), idx)
|
||||||
|
elem := reflect.NewAt(ifaceType, elemP).Elem()
|
||||||
|
|
||||||
|
err := d.handleValue(n, elem)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*sp = s
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
|
func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
|
||||||
|
var vt reflect.Type
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
|
vt = v.Type()
|
||||||
|
if vt == sliceInterfaceType {
|
||||||
|
return d.unmarshalArrayFastSliceInterface(array, v)
|
||||||
|
}
|
||||||
if v.IsNil() {
|
if v.IsNil() {
|
||||||
v.Set(reflect.MakeSlice(v.Type(), 0, 16))
|
v.Set(reflect.MakeSlice(v.Type(), 0, 16))
|
||||||
} else {
|
} else {
|
||||||
v.SetLen(0)
|
v.SetLen(0)
|
||||||
}
|
}
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
|
vt = v.Type()
|
||||||
// arrays are always initialized
|
// arrays are always initialized
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
elem := v.Elem()
|
elem := v.Elem()
|
||||||
@@ -658,7 +701,7 @@ func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
|
|||||||
return fmt.Errorf("toml: cannot store array in Go type %s", v.Kind())
|
return fmt.Errorf("toml: cannot store array in Go type %s", v.Kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
elemType := v.Type().Elem()
|
elemType := vt.Elem()
|
||||||
|
|
||||||
it := array.Children()
|
it := array.Children()
|
||||||
idx := 0
|
idx := 0
|
||||||
|
|||||||
Reference in New Issue
Block a user