From b6c2f3cad3359d39ea9c7594f1b12cdc47374a33 Mon Sep 17 00:00:00 2001 From: Grant Nelson Date: Tue, 23 Jul 2024 13:01:16 -0600 Subject: [PATCH] added copy from slice to array copy --- compiler/prelude/types.js | 11 +++- tests/arrays_test.go | 111 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/compiler/prelude/types.js b/compiler/prelude/types.js index 08be9593b..a64071985 100644 --- a/compiler/prelude/types.js +++ b/compiler/prelude/types.js @@ -150,7 +150,16 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => { }), "$"); }; typ.copy = (dst, src) => { - $copyArray(dst, src, 0, 0, src.length, elem); + if (src.length === undefined) { + // copy from a slice, the slice may be bigger but not smaller than the array + if (src.$length < dst.length) { + $throwRuntimeError("cannot convert slice with length "+src.$length+" to array or pointer to array with length "+dst.length); + } + $copyArray(dst, src.$array, 0, 0, dst.length, elem); + } else { + // copy from another array + $copyArray(dst, src, 0, 0, src.length, elem); + } }; typ.ptr.init(typ); Object.defineProperty(typ.ptr.nil, "nilCheck", { get: $throwNilPointerError }); diff --git a/tests/arrays_test.go b/tests/arrays_test.go index feca983c5..12449db03 100644 --- a/tests/arrays_test.go +++ b/tests/arrays_test.go @@ -1,6 +1,7 @@ package tests import ( + "fmt" "reflect" "testing" "unsafe" @@ -121,3 +122,113 @@ func TestNilPrototypeNotModifiedByReflectGrow(t *testing.T) { println("s2:", s2) } } + +func TestConversionFromSliceToArray(t *testing.T) { + t.Run(`nil byte slice to zero byte array`, func(t *testing.T) { + s := []byte(nil) + _ = [0]byte(s) // should not have runtime panic + }) + + t.Run(`empty byte slice to zero byte array`, func(t *testing.T) { + s := []byte{} + _ = [0]byte(s) // should not have runtime panic + }) + + t.Run(`3 byte slice to 3 byte array`, func(t *testing.T) { + s := []byte{12, 34, 56} + a := [3]byte(s) + if s[0] != a[0] || s[1] != a[1] || s[2] != a[2] { + t.Errorf("slice and array are not equal after conversion:\n\tslice: %#v\n\tarray: %#v", s, a) + } + }) + + t.Run(`4 byte slice to 4 byte array`, func(t *testing.T) { + s := []byte{12, 34, 56, 78} + a := [4]byte(s) + if s[0] != a[0] || s[1] != a[1] || s[2] != a[2] || s[3] != a[3] { + t.Errorf("slice and array are not equal after conversion:\n\tslice: %#v\n\tarray: %#v", s, a) + } + }) + + t.Run(`5 byte slice to 5 byte array`, func(t *testing.T) { + s := []byte{12, 34, 56, 78, 90} + a := [5]byte(s) + if s[0] != a[0] || s[1] != a[1] || s[2] != a[2] || s[3] != a[3] || s[4] != a[4] { + t.Errorf("slice and array are not equal after conversion:\n\tslice: %#v\n\tarray: %#v", s, a) + } + }) + + t.Run(`larger 5 byte slice to smaller 4 byte array`, func(t *testing.T) { + s := []byte{12, 34, 56, 78, 90} + a := [4]byte(s) + if s[0] != a[0] || s[1] != a[1] || s[2] != a[2] || s[3] != a[3] { + t.Errorf("slice and array are not equal after conversion:\n\tslice: %#v\n\tarray: %#v", s, a) + } + }) + + t.Run(`larger 4 byte slice to smaller zero byte array`, func(t *testing.T) { + s := []byte{12, 34, 56, 78} + _ = [0]byte(s) // should not have runtime panic + }) + + t.Run(`smaller 3 byte slice to larger 4 byte array`, func(t *testing.T) { + defer func() { + if r := recover(); r != nil { + err := fmt.Sprintf(`%v`, r) + exp := `runtime error: cannot convert slice with length 3 to array or pointer to array with length 4` + if err != exp { + t.Error(`unexpected panic message:`, r) + t.Log("\texpected:", exp) + } + } + }() + + s := []byte{12, 34, 56} + a := [4]byte(s) + t.Errorf("expected a runtime panic:\n\tslice: %#v\n\tarray: %#v", s, a) + }) + + t.Run(`nil byte slice to 5 byte array`, func(t *testing.T) { + defer func() { + if r := recover(); r != nil { + err := fmt.Sprintf(`%v`, r) + exp := `runtime error: cannot convert slice with length 0 to array or pointer to array with length 5` + if err != exp { + t.Error(`unexpected panic message:`, r) + t.Log("\texpected:", exp) + } + } + }() + + s := []byte(nil) + a := [5]byte(s) + t.Errorf("expected a runtime panic:\n\tslice: %#v\n\tarray: %#v", s, a) + }) + + type Cat struct { + name string + age int + } + cats := []Cat{ + {name: "Tom", age: 3}, + {name: "Jonesy", age: 5}, + {name: "Sylvester", age: 7}, + {name: "Rita", age: 2}, + } + + t.Run(`4 Cat slice to 4 Cat array`, func(t *testing.T) { + s := cats + a := [4]Cat(s) + if s[0] != a[0] || s[1] != a[1] || s[2] != a[2] || s[3] != a[3] { + t.Errorf("slice and array are not equal after conversion:\n\tslice: %#v\n\tarray: %#v", s, a) + } + }) + + t.Run(`4 *Cat slice to 4 *Cat array`, func(t *testing.T) { + s := []*Cat{&cats[0], &cats[1], &cats[2], &cats[3]} + a := [4]*Cat(s) + if s[0] != a[0] || s[1] != a[1] || s[2] != a[2] || s[3] != a[3] { + t.Errorf("slice and array are not equal after conversion:\n\tslice: %#v\n\tarray: %#v", s, a) + } + }) +}