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

x/mobile/bind: support slices of structs #101

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
10 changes: 10 additions & 0 deletions bind/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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) {
Expand Down
14 changes: 14 additions & 0 deletions bind/gengo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
35 changes: 33 additions & 2 deletions bind/genjava.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
34 changes: 30 additions & 4 deletions bind/genobjc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
}
}
}
Expand Down Expand Up @@ -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.
Expand Down
42 changes: 42 additions & 0 deletions bind/java/seq_android.c.support
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions bind/java/seq_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions bind/objc/seq_darwin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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__
32 changes: 32 additions & 0 deletions bind/testdata/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 7 additions & 2 deletions bind/testdata/structs.java.golden
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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();
}

Expand All @@ -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;
}