Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(go): generate concrete structs for behavioral interfaces #2257

Merged
merged 6 commits into from
Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions packages/@jsii/go-runtime/jsii-calc-test/main.go

This file was deleted.

77 changes: 77 additions & 0 deletions packages/@jsii/go-runtime/jsii-calc-test/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
calc "github.com/aws-cdk/jsii/jsii-calc/go/jsiicalc"
"github.com/aws-cdk/jsii/jsii-experimental"
"math"
"os"
"testing"
)

func TestMain(m *testing.M) {
status := m.Run()
jsii.Close()
os.Exit(status)
}

func TestCalculator(t *testing.T) {
var initialValue float64 = 10
calculatorProps := calc.CalculatorProps{InitialValue: initialValue, MaximumValue: math.MaxFloat64}
calculator := calc.NewCalculator(&calculatorProps)

t.Run("Primitive Property Access", func(t *testing.T) {
actual := calculator.GetValue()
if actual != initialValue {
t.Errorf("Expected: %f; Actual %f;", initialValue, actual)
}
})

t.Run("Method Call Effect", func(t *testing.T) {
var factor float64 = 3
calculator.Mul(factor)
var expected float64 = initialValue * factor
actual := calculator.GetValue()

if actual != expected {
t.Errorf("Expected: %f; Actual %f;", expected, actual)
}
})

t.Run("Method Call Returns Any Value", func(t *testing.T) {
// JSII tells us this return value is an "any" type. Therefore the
// value received by go is type `interface{}` and can be further
// specialized using reflection.
expected := "Calculator"
actual := calculator.TypeName()
switch retType := actual.(type) {
case string:
if actual != expected {
t.Errorf("Expected: %s; Actual %s", expected, actual)
}
default:
t.Errorf("Expected type: %s; Actual type: %s", "string", retType)
}
})
}

// func TestUpcasingReflectable(t *testing.T) {
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
// delegate := make(map[string]interface{})
// key, val := "key1", "value1"
// delegate[key] = val
// upReflectable := calc.NewUpcasingReflectable(delegate)
// entries := upReflectable.GetEntries()

// if len(entries) != 1 {
// t.Errorf("Entries expected to have length of: 1; Actual: %d", len(entries))
// }

// entry := entries[0]

// // t.Logf("Pointer entry obj: %s\n", entry)
// // t.Logf("Pointer entry addr: %p\n", entry)
// actualKey, actualVal := entry.GetKey(), entry.GetValue()
// if actualKey != key || actualVal != val {
// t.Errorf("Expected Key: %s; Received Key: %s", key, actualKey)
// t.Errorf("Expected Value: %s; Received Value: %s", val, actualVal)
// }
// }
76 changes: 62 additions & 14 deletions packages/@jsii/go-runtime/jsii-experimental/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io/ioutil"
"os"
"reflect"
"regexp"
)

Expand Down Expand Up @@ -38,7 +39,7 @@ func Load(name string, version string, tarball []byte) {

// Create will construct a new JSII object within the kernel runtime. This is
// called by jsii object constructors.
func Create(fqn FQN, args []interface{}, interfaces []FQN, overrides []Override, returns interface{}) {
func Create(fqn FQN, args []interface{}, interfaces []FQN, overrides []Override, returnsPtr interface{}) {
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
client := getClient()
res, err := client.create(createRequest{
Api: "create",
Expand All @@ -52,12 +53,12 @@ func Create(fqn FQN, args []interface{}, interfaces []FQN, overrides []Override,
panic(err)
}

client.objects[returns] = res.JsiiInstanceId
client.objects[returnsPtr] = res.JsiiInstanceId
}

// Invoke will call a method on a jsii class instance. The response should be
// decoded into the expected return type for the method being called.
func Invoke(obj interface{}, method string, args []interface{}, returns interface{}) {
func Invoke(obj interface{}, method string, args []interface{}, returns bool, returnsPtr interface{}) {
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
client := getClient()

// Find reference to class instance in client
Expand All @@ -67,7 +68,7 @@ func Invoke(obj interface{}, method string, args []interface{}, returns interfac
panic("No Object Found")
}

_, err := client.invoke(invokeRequest{
res, err := client.invoke(invokeRequest{
Api: "invoke",
Method: method,
Args: args,
Expand All @@ -79,12 +80,16 @@ func Invoke(obj interface{}, method string, args []interface{}, returns interfac
if err != nil {
panic(err)
}

if returns {
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
castAndSetToPtr(returnsPtr, res.Result)
}
}

func InvokeStatic(fqn FQN, method string, args []interface{}, returns interface{}) {
func InvokeStatic(fqn FQN, method string, args []interface{}, returns bool, returnsPtr interface{}) {
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
client := getClient()

_, err := client.sinvoke(staticInvokeRequest{
res, err := client.sinvoke(staticInvokeRequest{
Api: "sinvoke",
Fqn: fqn,
Method: method,
Expand All @@ -94,9 +99,13 @@ func InvokeStatic(fqn FQN, method string, args []interface{}, returns interface{
if err != nil {
panic(err)
}

if returns {
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
castAndSetToPtr(returnsPtr, res.Result)
}
}

func Get(property string, obj interface{}) {
func Get(obj interface{}, property string, returnsPtr interface{}) {
client := getClient()

// Find reference to class instance in client
Expand All @@ -106,23 +115,25 @@ func Get(property string, obj interface{}) {
panic("No Object Found")
}

_, err := client.get(getRequest{
res, err := client.get(getRequest{
Api: "get",
Property: property,
Objref: objref{JsiiInstanceId: refid},
Objref: objref{
JsiiInstanceId: refid,
},
})

if err != nil {
panic(err)
}

// Do we need to return Value from getResponse?
castAndSetToPtr(returnsPtr, res.Value)
}

func StaticGet(fqn FQN, property string) {
func StaticGet(fqn FQN, property string, returnsPtr interface{}) {
client := getClient()

_, err := client.sget(staticGetRequest{
res, err := client.sget(staticGetRequest{
Api: "sget",
Fqn: fqn,
Property: property,
Expand All @@ -131,9 +142,11 @@ func StaticGet(fqn FQN, property string) {
if err != nil {
panic(err)
}

castAndSetToPtr(returnsPtr, res.Value)
}

func Set(property string, value, obj interface{}) {
func Set(obj interface{}, property string, value interface{}) {
client := getClient()

// Find reference to class instance in client
Expand All @@ -146,7 +159,10 @@ func Set(property string, value, obj interface{}) {
_, err := client.set(setRequest{
Api: "set",
Property: property,
Objref: objref{JsiiInstanceId: refid},
Value: value,
Objref: objref{
JsiiInstanceId: refid,
},
})

if err != nil {
Expand All @@ -169,6 +185,38 @@ func StaticSet(fqn FQN, property string, value interface{}) {
}
}

func castValToRef(data interface{}) (objref, bool) {
ref := objref{}
ok := false
dataVal := reflect.ValueOf(data)

if dataVal.Kind() == reflect.Map {
for _, k := range dataVal.MapKeys() {
// Finding values type requires extracting from reflect.Value
// otherwise .Kind() returns `interface{}`
v := reflect.ValueOf(dataVal.MapIndex(k).Interface())

if k.Kind() == reflect.String && k.String() == "$jsii.byref" && v.Kind() == reflect.String {
ref.JsiiInstanceId = v.String()
ok = true
}

MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
}
}

return ref, ok
}

// castAndSetToPtr accepts a pointer to any type and attempts to cast the value
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
// argument to be the same type. Then it sets the value of the pointer element
// to be the newly casted data. This is used to cast payloads from JSII to
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
// expected return types for Get and Invoke functions.
func castAndSetToPtr(ptr interface{}, data interface{}) {
MrArnoldPalmer marked this conversation as resolved.
Show resolved Hide resolved
ptrVal := reflect.ValueOf(ptr).Elem()
val := reflect.ValueOf(data)
ptrVal.Set(val)
}

// Close finalizes the runtime process, signalling the end of the execution to
// the jsii kernel process, and waiting for graceful termination. The best
// practice is to defer call thins at the beginning of the "main" function.
Expand Down
2 changes: 1 addition & 1 deletion packages/@jsii/go-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"generate": "npm run gen:rt && npm run gen:calc",
"build": "npm run generate && go build ./jsii-experimental",
"test": "go test ./jsii-experimental && npm run test:calc",
"test:calc": "npm run gen:calc && go run ./jsii-calc-test"
"test:calc": "npm run gen:calc && go test ./jsii-calc-test"
},
"keywords": [],
"author": "",
Expand Down
2 changes: 1 addition & 1 deletion packages/jsii-pacmak/lib/targets/go/runtime/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const JSII_GET_FUNC = `${JSII_RT_ALIAS}.Get`;
export const JSII_SGET_FUNC = `${JSII_RT_ALIAS}.StaticGet`;

// JSII set request
export const JSII_SET_FUNC = `${JSII_RT_ALIAS}.Get`;
export const JSII_SET_FUNC = `${JSII_RT_ALIAS}.Set`;

// JSII static set request
export const JSII_SSET_FUNC = `${JSII_RT_ALIAS}.StaticSet`;
Expand Down
1 change: 1 addition & 0 deletions packages/jsii-pacmak/lib/targets/go/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './constants';
export * from './class-constructor';
export * from './method-call';
export * from './property-access';
export * from './util';
Loading