From 72d92c8e1993eee6f30334d82ac7be2febc28f9d Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Tue, 17 Feb 2015 22:59:21 +0000 Subject: [PATCH] Export arrays to common type if possible If there is a common type for all values in an array export to a slice of that type otherwise return a slice of interfaces. --- reflect_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ value.go | 27 ++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/reflect_test.go b/reflect_test.go index 3c5daa5..fc5abca 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -523,6 +523,46 @@ func Test_reflectArray(t *testing.T) { is(abc[len(abc)-1], true) } + // no common type + { + test(` + abc = [1, 2.2, "str"]; + abc; + `, "1,2.2,str") + val, err := vm.Get("abc") + is(err, nil) + abc, err := val.Export() + is(err, nil) + is(abc, []interface{}{int64(1), 2.2, "str"}) + } + + // common type int + { + test(` + abc = [1, 2, 3]; + abc; + `, "1,2,3") + val, err := vm.Get("abc") + is(err, nil) + abc, err := val.Export() + is(err, nil) + is(abc, []int64{1, 2, 3}) + } + + // common type string + { + + test(` + abc = ["str1", "str2", "str3"]; + abc; + `, "str1,str2,str3") + + val, err := vm.Get("abc") + is(err, nil) + abc, err := val.Export() + is(err, nil) + is(abc, []string{"str1", "str2", "str3"}) + } }) } diff --git a/value.go b/value.go index 05d61dd..d7ef7ce 100644 --- a/value.go +++ b/value.go @@ -680,15 +680,36 @@ func (self Value) export() interface{} { result := make([]interface{}, 0) lengthValue := object.get("length") length := lengthValue.value.(uint32) + kind := reflect.Invalid + state := 0 + var t reflect.Type for index := uint32(0); index < length; index += 1 { name := strconv.FormatInt(int64(index), 10) if !object.hasProperty(name) { continue } - value := object.get(name) - result = append(result, value.export()) + value := object.get(name).export() + t = reflect.TypeOf(value) + if state == 0 { + kind = t.Kind() + state = 1 + } else if state == 1 && kind != t.Kind() { + state = 2 + } + result = append(result, value) } - return result + + if state != 1 || kind == reflect.Interface { + // No common type + return result + } + + // Convert to the common type + val := reflect.MakeSlice(reflect.SliceOf(t), len(result), len(result)) + for i, v := range result { + val.Index(i).Set(reflect.ValueOf(v)) + } + return val.Interface() } else { result := make(map[string]interface{}) // TODO Should we export everything? Or just what is enumerable?