diff --git a/bind/gen.go b/bind/gen.go index 4fedfbeb5..64dad01c2 100644 --- a/bind/gen.go +++ b/bind/gen.go @@ -402,6 +402,11 @@ func (g *Generator) cgoType(t types.Type) string { default: g.errorf("unsupported slice type: %s", t) } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + return "nrefnumslice" + } default: g.errorf("unsupported slice type: %s", t) } @@ -507,6 +512,11 @@ func (g *Generator) isSupported(t types.Type) bool { switch e := t.Elem().(type) { case *types.Basic: return e.Kind() == types.Uint8 + case *types.Pointer: + switch f := e.Elem().(type) { + case *types.Named: + return g.validPkg(f.Obj().Pkg()) + } } case *types.Pointer: switch t := t.Elem().(type) { diff --git a/bind/gengo.go b/bind/gengo.go index 8087c7ad2..9a017e5ec 100644 --- a/bind/gengo.go +++ b/bind/gengo.go @@ -119,6 +119,13 @@ func (g *goGen) genWrite(toVar, fromVar string, t types.Type, mode varMode) { default: g.errorf("unsupported type: %s", t) } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + g.Printf("%s := toRefNumSlice(%s)\n", toVar, fromVar) + default: + g.errorf("unsupported type: %s", t) + } default: g.errorf("unsupported type: %s", t) } @@ -403,6 +410,13 @@ func (g *goGen) genRead(toVar, fromVar string, typ types.Type, mode varMode) { default: g.errorf("unsupported type: %s", t) } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + g.Printf("%s := fromRefNumSlice(%s)\n", toVar, fromVar) + default: + g.errorf("unsupported type: %s", t) + } default: g.errorf("unsupported type: %s", t) } diff --git a/bind/genjava.go b/bind/genjava.go index b197640aa..fecfb191c 100644 --- a/bind/genjava.go +++ b/bind/genjava.go @@ -135,6 +135,13 @@ func (j *javaClassInfo) toJavaType(T types.Type) *java.Type { case types.Uint8: // Byte. return &java.Type{Kind: java.Array, Elem: &java.Type{Kind: java.Byte}} } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + if isJavaType(e) { + return &java.Type{Kind: java.Array, Elem: &java.Type{Kind: java.Object, Class: classNameFor(e)}} + } + } } return nil case *types.Named: @@ -641,8 +648,18 @@ func (g *JavaGen) jniType(T types.Type) string { return "TODO" } case *types.Slice: - return "jbyteArray" - + switch e := T.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + return "jbyteArray" + } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + return "jobjectArray" + } + } case *types.Pointer: if _, ok := T.Elem().(*types.Named); ok { return g.jniType(T.Elem()) @@ -915,6 +932,13 @@ func (g *JavaGen) genJavaToC(varName string, t types.Type, mode varMode) { default: g.errorf("unsupported type: %s", t) } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + g.Printf("nobjectarray _%s = go_seq_from_java_objectarray(env, %s, %d);\n", varName, varName, toCFlag(mode == modeRetained)) + default: + g.errorf("unsupported type: %s", t) + } default: g.errorf("unsupported type: %s", t) } @@ -952,6 +976,13 @@ func (g *JavaGen) genCToJava(toName, fromName string, t types.Type, mode varMode default: g.errorf("unsupported type: %s", t) } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + g.Printf("jobjectArray %s = go_seq_to_java_objectarray(env, %s, %d);\n", toName, fromName, toCFlag(mode == modeRetained)) + default: + g.errorf("unsupported type: %s", t) + } default: g.errorf("unsupported type: %s", t) } diff --git a/bind/genobjc.go b/bind/genobjc.go index d5914138a..28df8b9c7 100644 --- a/bind/genobjc.go +++ b/bind/genobjc.go @@ -696,6 +696,13 @@ func (g *ObjcGen) genWrite(varName string, t types.Type, mode varMode) { default: g.errorf("unsupported type: %s", t) } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + g.Printf("nrefnumslice _%s = go_seq_from_objc_refnumarray(%s);\n", varName, varName) + default: + g.errorf("unsupported type: %s", t) + } default: g.errorf("unsupported type: %s", t) } @@ -763,6 +770,13 @@ func (g *ObjcGen) genRead(toName, fromName string, t types.Type, mode varMode) { default: g.errorf("unsupported type: %s", t) } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + g.Printf("NSArray *%s = go_seq_to_objc_refnumarray(%s);\n", toName, fromName) + default: + g.errorf("unsupported type: %s", t) + } default: g.errorf("unsupported type: %s", t) } @@ -1047,6 +1061,11 @@ func (g *ObjcGen) genRelease(varName string, t types.Type, mode varMode) { g.Printf("}\n") } } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + g.Printf("free(_%s.ptr);\n", varName) + } } } } @@ -1344,10 +1363,17 @@ func (g *ObjcGen) objcType(typ types.Type) string { return "TODO" } case *types.Slice: - elem := g.objcType(typ.Elem()) - // Special case: NSData seems to be a better option for byte slice. - if elem == "byte" { - return "NSData* _Nullable" + switch e := typ.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: + return "NSData* _Nullable" + } + case *types.Pointer: + switch e.Elem().(type) { + case *types.Named: + return "NSArray* _Nullable" + } } // TODO(hyangah): support other slice types: NSArray or CFArrayRef. // Investigate the performance implication. diff --git a/bind/java/seq_android.c.support b/bind/java/seq_android.c.support index 77ec5f4ae..e8307e0c7 100644 --- a/bind/java/seq_android.c.support +++ b/bind/java/seq_android.c.support @@ -93,6 +93,20 @@ jbyteArray go_seq_to_java_bytearray(JNIEnv *env, nbyteslice s, int copy) { return res; } +jobjectArray go_seq_to_java_objectarray(JNIEnv *env, nrefnumslice arr) { + if (arr.ptr == NULL) { + return NULL; + } + jobjectArray res = (*env)->NewObjectArray(env, arr.len, (*env)->FindClass(env, "java/lang/Object"), NULL); + if (res == NULL) { + LOG_FATAL("NewObjectArray failed"); + } + for (int i = 0; i < arr.len; i++) { + (*env)->SetObjectArrayElement(env, res, i, go_seq_from_refnum(env, arr.ptr[i])); + } + return res; +} + #define surr1 0xd800 #define surr2 0xdc00 #define surr3 0xe000 @@ -224,6 +238,34 @@ nbyteslice go_seq_from_java_bytearray(JNIEnv *env, jbyteArray arr, int copy) { return res; } +nrefnumslice go_seq_from_java_objectarray(JNIEnv *env, jobjectArray arr) { + struct nrefnumslice res = {NULL, 0}; + if (arr == NULL) { + return res; + } + + jsize len = (*env)->GetArrayLength(env, arr); + if (len == 0) { + return res; + } + jint *ptr = (jint *)(*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (ptr == NULL) { + LOG_FATAL("GetPrimitiveArrayCritical failed"); + } + void *refnums = (void *)malloc(len * sizeof(jint)); + if (refnums == NULL) { + LOG_FATAL("malloc failed"); + } + // convert to refnums + for (int i = 0; i < len; i++) { + refnums[i] = go_seq_to_refnum(env, (*env)->GetObjectArrayElement(env, arr, i)); + } + res.ptr = refnums; + res.len = len; + (*env)->ReleasePrimitiveArrayCritical(env, arr, ptr, JNI_ABORT); + return res; +} + int32_t go_seq_to_refnum_go(JNIEnv *env, jobject o) { if (o == NULL) { return NULL_REFNUM; diff --git a/bind/java/seq_android.h b/bind/java/seq_android.h index 26e90251e..7b8d3e144 100644 --- a/bind/java/seq_android.h +++ b/bind/java/seq_android.h @@ -30,6 +30,10 @@ typedef struct nbyteslice { void *ptr; jsize len; } nbyteslice; +typedef struct nrefnumslice { + void *ptr; + jsize len; +} nrefnumslice; typedef jlong nint; extern void go_seq_dec_ref(int32_t ref); @@ -47,6 +51,8 @@ extern jobject go_seq_get_exception(JNIEnv *env); extern jbyteArray go_seq_to_java_bytearray(JNIEnv *env, nbyteslice s, int copy); extern nbyteslice go_seq_from_java_bytearray(JNIEnv *env, jbyteArray s, int copy); +extern jobjectArray go_seq_to_java_objectarray(JNIEnv *env, nrefnumslice arr); +extern nrefnumslice go_seq_from_java_objectarray(JNIEnv *env, jobjectArray arr); extern void go_seq_release_byte_array(JNIEnv *env, jbyteArray arr, jbyte* ptr); extern jstring go_seq_to_java_string(JNIEnv *env, nstring str); diff --git a/bind/objc/seq_darwin.h b/bind/objc/seq_darwin.h index 1aeec4ada..1b53ffbf2 100644 --- a/bind/objc/seq_darwin.h +++ b/bind/objc/seq_darwin.h @@ -34,6 +34,10 @@ typedef struct nbyteslice { void *ptr; int len; } nbyteslice; +typedef struct nrefnumslice { + void *ptr; + int len; +} nrefnumslice; typedef int nint; extern void init_seq(); @@ -55,9 +59,11 @@ extern GoSeqRef *go_seq_from_refnum(int32_t refnum); extern id go_seq_objc_from_refnum(int32_t refnum); extern nbyteslice go_seq_from_objc_bytearray(NSData *data, int copy); +extern nrefnumslice go_seq_from_objc_objectarray(NSArray *arr); extern nstring go_seq_from_objc_string(NSString *s); extern NSData *go_seq_to_objc_bytearray(nbyteslice, int copy); +extern NSArray *go_seq_to_objc_objectarray(nrefnumslice arr); extern NSString *go_seq_to_objc_string(nstring str); #endif // __GO_SEQ_DARWIN_HDR__ diff --git a/bind/testdata/structs.go b/bind/testdata/structs.go index 5974bdc36..450bdd9b9 100644 --- a/bind/testdata/structs.go +++ b/bind/testdata/structs.go @@ -25,6 +25,38 @@ func IdentityWithError(s *S) (*S, error) { return s, nil } +func (s *S) Repeat(n int) []*S { + t := make([]*S, n) + for i := range t { + t[i] = s + } + return t +} + +func (s *S) RepeatWithError(n int) ([]*S, error) { + return Repeat(s, n), nil +} + +func Repeat(s *S, n int) []*S { + t := make([]*S, n) + for i := range t { + t[i] = s + } + return t +} + +func RepeatWithError(s *S, n int) ([]*S, error) { + return Repeat(s, n), nil +} + +func FirstSum(s []*S) float64 { + return s[0].Sum() +} + +func FirstSumWithError(s []*S) (float64, error) { + return s[0].Sum(), nil +} + type ( S2 struct{} I interface { diff --git a/bind/testdata/structs.java.golden b/bind/testdata/structs.java.golden index 5a140fe00..9b8d0743d 100644 --- a/bind/testdata/structs.java.golden +++ b/bind/testdata/structs.java.golden @@ -30,6 +30,8 @@ public final class S implements Seq.Proxy { public final native void setY(double v); public native S identity() throws Exception; + public native S[] repeat(long n); + public native S[] repeatWithError(long n) throws Exception; public native double sum(); @Override public boolean equals(Object o) { if (o == null || !(o instanceof S)) { @@ -176,7 +178,7 @@ import go.Seq; public abstract class Structs { static { - Seq.touch(); // for loading the native library + Seq.touch(); // for loading the native library _init(); } @@ -200,7 +202,10 @@ public abstract class Structs { public native void m(); } - + public static native double firstSum(S[] s); + public static native double firstSumWithError(S[] s) throws Exception; public static native S identity(S s); public static native S identityWithError(S s) throws Exception; + public static native S[] repeat(S s, long n); + public static native S[] repeatWithError(S s, long n) throws Exception; }