Skip to content

Commit

Permalink
ports/go: add more type conversions and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
iyear committed Mar 28, 2023
1 parent a1a079f commit 05e49d7
Showing 2 changed files with 129 additions and 7 deletions.
63 changes: 61 additions & 2 deletions source/ports/go_port/source/go_port.go
Original file line number Diff line number Diff line change
@@ -44,6 +44,7 @@ import "C"
import (
"errors"
"fmt"
"reflect"
"runtime"
"sync"
"unsafe"
@@ -362,11 +363,40 @@ func getFunction(function string) (unsafe.Pointer, error) {
}

func goToValue(arg interface{}, ptr *unsafe.Pointer) {
// Create null
if arg == nil {
*ptr = C.metacall_value_create_null()
}

// Create bool
if i, ok := arg.(bool); ok {
if i {
*ptr = C.metacall_value_create_bool(C.uchar(1))
} else {
*ptr = C.metacall_value_create_bool(C.uchar(0))
}
}

// Create char
if i, ok := arg.(byte); ok {
*ptr = C.metacall_value_create_char((C.char)(i))
}

// Create short
if i, ok := arg.(int16); ok {
*ptr = C.metacall_value_create_short((C.short)(i))
}

// Create int
if i, ok := arg.(int); ok {
*ptr = C.metacall_value_create_int((C.int)(i))
}

// Create long
if i, ok := arg.(int64); ok {
*ptr = C.metacall_value_create_long((C.long)(i))
}

// Create float32
if i, ok := arg.(float32); ok {
*ptr = C.metacall_value_create_float((C.float)(i))
@@ -384,16 +414,45 @@ func goToValue(arg interface{}, ptr *unsafe.Pointer) {
*ptr = C.metacall_value_create_string(cStr, (C.size_t)(len(str)))
}

// Create array
if v := reflect.ValueOf(arg); v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
length := v.Len()
cArgs := C.malloc(C.size_t(length) * C.size_t(unsafe.Sizeof(uintptr(0))))
for index := 0; index < length; index++ {
goToValue(v.Index(index).Interface(), (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(cArgs))+uintptr(index)*PtrSizeInBytes)))
}
*ptr = C.metacall_value_create_array((*unsafe.Pointer)(cArgs), (C.size_t)(length))
}

// TODO: Add more types
}

func valueToGo(value unsafe.Pointer) interface{} {
switch C.metacall_value_id(value) {
case C.METACALL_NULL:
{
return nil
}
case C.METACALL_BOOL:
{
return C.metacall_value_to_bool(value) != C.uchar(0)
}
case C.METACALL_CHAR:
{
return byte(C.metacall_value_to_char(value))
}
case C.METACALL_SHORT:
{
return int16(C.metacall_value_to_short(value))
}
case C.METACALL_INT:
{
return int(C.metacall_value_to_int(value))
}

case C.METACALL_LONG:
{
return int64(C.metacall_value_to_long(value))
}
case C.METACALL_FLOAT:
{
return float32(C.metacall_value_to_float(value))
@@ -415,7 +474,7 @@ func valueToGo(value unsafe.Pointer) interface{} {
array := make([]interface{}, arraySize)

for iterator := C.size_t(0); iterator < arraySize; iterator++ {
currentValue := (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(arrayValue))+uintptr(iterator*PtrSizeInBytes)))
currentValue := (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(arrayValue)) + uintptr(iterator*PtrSizeInBytes)))
array[iterator] = valueToGo(*currentValue)
}

73 changes: 68 additions & 5 deletions source/ports/go_port/source/go_port_test.go
Original file line number Diff line number Diff line change
@@ -3,8 +3,10 @@ package metacall
import (
"log"
"os"
"reflect"
"sync"
"testing"
"unsafe"
)

func TestMain(m *testing.M) {
@@ -13,12 +15,12 @@ func TestMain(m *testing.M) {
}

// if benchmark {
buffer := "module.exports = { benchmark: async x => x }"
buffer := "module.exports = { benchmark: async x => x }"

if err := LoadFromMemory("node", buffer); err != nil {
log.Fatal(err)
return
}
if err := LoadFromMemory("node", buffer); err != nil {
log.Fatal(err)
return
}
// }

code := m.Run()
@@ -123,6 +125,67 @@ func TestNodeJSAwait(t *testing.T) {
wg.Wait()
}

func TestValues(t *testing.T) {
tests := []struct {
name string
input interface{}
want interface{}
}{
{"null", nil, nil},
{"bool_true", true, true},
{"bool_false", false, false},
{"char", byte('H'), byte('H')},
{"char_min", byte(127), byte(127)},
{"char_max", byte(128), byte(128)},
{"short", int16(1), int16(1)},
{"short_min", int16(-32768), int16(-32768)},
{"short_max", int16(32767), int16(32767)},
{"int", int(1), int(1)},
{"int_min", int(-2147483648), int(-2147483648)},
{"int_max", int(2147483647), int(2147483647)},
{"long", int64(3), int64(3)},
{"long_min", int64(-9223372036854775808), int64(-9223372036854775808)},
{"long_max", int64(9223372036854775807), int64(9223372036854775807)},
{"float", float32(1.0), float32(1.0)},
{"float_min", float32(1.2e-38), float32(1.2e-38)},
{"float_max", float32(3.4e+38), float32(3.4e+38)},
{"double", float64(1.0), float64(1.0)},
{"double_min", float64(2.3e-308), float64(2.3e-308)},
{"double_max", float64(1.7e+308), float64(1.7e+308)},
{"string", "hello", "hello"},
{"array", [3]interface{}{1, 2, 3}, []interface{}{1, 2, 3}},
{"array_bool", [3]bool{true, false, true}, []interface{}{true, false, true}},
{"array_char", [3]byte{'1', '2', '3'}, []interface{}{byte('1'), byte('2'), byte('3')}},
{"array_short", [3]int16{1, 2, 3}, []interface{}{int16(1), int16(2), int16(3)}},
{"array_int", [3]int{1, 2, 3}, []interface{}{int(1), int(2), int(3)}},
{"array_float", [3]float32{1.0, 2.0, 3.0}, []interface{}{float32(1.0), float32(2.0), float32(3.0)}},
{"array_double", [3]float64{1.0, 2.0, 3.0}, []interface{}{float64(1.0), float64(2.0), float64(3.0)}},
{"array_string", [3]string{"1", "2", "3"}, []interface{}{"1", "2", "3"}},
{"slice", []interface{}{1, 2, 3}, []interface{}{1, 2, 3}},
{"slice_bool", []bool{true, false, true}, []interface{}{true, false, true}},
{"slice_char", []byte{'1', '2', '3'}, []interface{}{byte('1'), byte('2'), byte('3')}},
{"slice_short", []int16{1, 2, 3}, []interface{}{int16(1), int16(2), int16(3)}},
{"slice_int", []int{1, 2, 3}, []interface{}{int(1), int(2), int(3)}},
{"slice_float", []float32{1.0, 2.0, 3.0}, []interface{}{float32(1.0), float32(2.0), float32(3.0)}},
{"slice_double", []float64{1.0, 2.0, 3.0}, []interface{}{float64(1.0), float64(2.0), float64(3.0)}},
{"slice_string", []string{"1", "2", "3"}, []interface{}{"1", "2", "3"}},
}

for _, tt := range tests {
var ptr unsafe.Pointer
goToValue(tt.input, &ptr)

if ptr == nil {
t.Errorf("invalid pointer: %s", tt.name)
return
}

if v := valueToGo(ptr); !reflect.DeepEqual(v, tt.want) {
t.Errorf("name: %s, input: %T,%v, want: %T,%v, got: %T,%v", tt.name, tt.input, tt.input, tt.want, tt.want, v, v)
}
}
}

func benchmarkNodeJS(b *testing.B, n int) {
var wg sync.WaitGroup

0 comments on commit 05e49d7

Please sign in to comment.