Skip to content

Commit

Permalink
Keep separate fn for []interface{} unmarshal
Browse files Browse the repository at this point in the history
  • Loading branch information
pelletier committed Nov 14, 2021
1 parent f77775b commit dc72d75
Showing 1 changed file with 70 additions and 38 deletions.
108 changes: 70 additions & 38 deletions unmarshaler.go
Expand Up @@ -688,21 +688,78 @@ func unmarshalArrayFnForSlice(vt reflect.Type) unmarshalArrayFn {
return fn
}

func unmarshalArraySliceInterface(d *decoder, array *ast.Node, v reflect.Value) error {
sp := (*danger.Slice)(unsafe.Pointer(v.UnsafeAddr()))

sp.Len = 0

var x interface{}

it := array.Children()
for it.Next() {
n := it.Node()

idx := sp.Len

if sp.Len == sp.Cap {
c := sp.Cap
if c == 0 {
c = 16
} else {
c *= 2
}
*sp = danger.ExtendSlice(sliceInterfaceType, sp, c)
}

datap := unsafe.Pointer(sp.Data)
elemp := danger.Stride(datap, unsafe.Sizeof(x), idx)
elem := reflect.NewAt(sliceInterfaceType.Elem(), elemp).Elem()

err := d.handleValue(n, elem)
if err != nil {
return err
}

sp.Len++
}

if sp.Data == nil {
*sp = danger.ExtendSlice(sliceInterfaceType, sp, 0)
}

return nil
}

func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
var vt reflect.Type
switch v.Kind() {
case reflect.Slice:
vt = v.Type()
fn := unmarshalArrayFnForSlice(vt)
fn := unmarshalArrayFnForSlice(v.Type())
return fn(d, array, v)
case reflect.Array:
vt = v.Type()
// arrays are always initialized

it := array.Children()
idx := 0
for it.Next() {
n := it.Node()

if idx >= v.Len() {
return nil
}
elem := v.Index(idx)
err := d.handleValue(n, elem)
if err != nil {
return err
}
idx++
}
case reflect.Interface:
elemIsSliceInterface := false
elem := v.Elem()
if !elem.IsValid() {
s := make([]interface{}, 0, 16)
elem = reflect.ValueOf(&s).Elem()
elemIsSliceInterface = true
} else if elem.Kind() == reflect.Slice {
if elem.Type() != sliceInterfaceType {
s := make([]interface{}, 0, 16)
Expand All @@ -713,49 +770,24 @@ func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
reflect.Copy(nelem, elem)
elem = nelem
}
elemIsSliceInterface = true
}
err := d.unmarshalArray(array, elem)
if err != nil {
return err

var err error
if elemIsSliceInterface {
err = unmarshalArraySliceInterface(d, array, elem)
} else {
err = d.unmarshalArray(array, elem)
}

v.Set(elem)
return nil
return err
default:
// TODO: use newDecodeError, but first the parser needs to fill
// array.Data.
return fmt.Errorf("toml: cannot store array in Go type %s", v.Kind())
}

elemType := vt.Elem()

it := array.Children()
idx := 0
for it.Next() {
n := it.Node()

// TODO: optimize
if v.Kind() == reflect.Slice {
elem := reflect.New(elemType).Elem()

err := d.handleValue(n, elem)
if err != nil {
return err
}

v.Set(reflect.Append(v, elem))
} else { // array
if idx >= v.Len() {
return nil
}
elem := v.Index(idx)
err := d.handleValue(n, elem)
if err != nil {
return err
}
idx++
}
}

return nil
}

Expand Down

0 comments on commit dc72d75

Please sign in to comment.