From 061d8092fcbafb28f3c8b9e94b9d497474817e76 Mon Sep 17 00:00:00 2001 From: Rod Hynes Date: Mon, 5 Dec 2022 10:57:56 -0500 Subject: [PATCH 01/15] Fix: comment typos --- psiphon/common/tactics/tactics.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psiphon/common/tactics/tactics.go b/psiphon/common/tactics/tactics.go index 72e504059..1ce88c349 100755 --- a/psiphon/common/tactics/tactics.go +++ b/psiphon/common/tactics/tactics.go @@ -729,7 +729,7 @@ func (server *Server) GetFilterGeoIPScope(geoIPData common.GeoIPData) int { } // GetTacticsPayload assembles and returns a tactics payload for a client with -// the specified GeoIP, API parameter, and speed test attributes. +// the specified GeoIP, API parameters, and speed test attributes. // // The speed test samples are expected to be in apiParams, as is the stored // tactics tag. @@ -1107,7 +1107,7 @@ func (t *Tactics) merge(includeServerSideOnly bool, u *Tactics) { } // Note: there is no deep copy of parameter values; the the returned - // Tactics shares memory with the original and it individual parameters + // Tactics shares memory with the original and its individual parameters // should not be modified. if u.Parameters != nil { if t.Parameters == nil { From 44cb74bc2b013ee154ee578daa3cf79a25ee37bc Mon Sep 17 00:00:00 2001 From: Rod Hynes Date: Mon, 5 Dec 2022 13:24:46 -0500 Subject: [PATCH 02/15] Squashed 'MobileLibrary/go-mobile/' content from commit 43a03845 git-subtree-dir: MobileLibrary/go-mobile git-subtree-split: 43a0384520996c8376bfb8637390f12b44773e65 --- .gitattributes | 10 + .gitignore | 27 + CONTRIBUTING.md | 26 + LICENSE | 27 + PATENTS | 22 + README.md | 32 + app/GoNativeActivity.java | 67 + app/android.c | 201 + app/android.go | 825 ++++ app/app.go | 214 + app/app_test.go | 238 + app/darwin_desktop.go | 496 ++ app/darwin_desktop.m | 251 + app/darwin_ios.go | 216 + app/darwin_ios.m | 167 + app/doc.go | 88 + app/internal/apptest/apptest.go | 67 + app/internal/callfn/callfn.go | 18 + app/internal/callfn/callfn_386.s | 11 + app/internal/callfn/callfn_amd64.s | 11 + app/internal/callfn/callfn_arm.s | 11 + app/internal/callfn/callfn_arm64.s | 11 + app/internal/testapp/AndroidManifest.xml | 27 + app/internal/testapp/testapp.go | 95 + app/shiny.go | 84 + app/x11.c | 175 + app/x11.go | 127 + asset/asset.go | 25 + asset/asset_android.go | 109 + asset/asset_darwin_armx.go | 25 + asset/asset_desktop.go | 24 + asset/doc.go | 17 + bind/bind.go | 59 + bind/bind_test.go | 700 +++ bind/gen.go | 575 +++ bind/genclasses.go | 948 ++++ bind/gengo.go | 593 +++ bind/genjava.go | 1732 +++++++ bind/genobjc.go | 1428 ++++++ bind/genobjcw.go | 756 +++ bind/implicit.go | 10 + bind/java/ClassesTest.java | 157 + bind/java/CustomPkgTest.java | 15 + bind/java/Seq.java | 400 ++ bind/java/SeqBench.java | 162 + bind/java/SeqTest.java | 602 +++ bind/java/context_android.c | 16 + bind/java/context_android.go | 21 + bind/java/doc.go | 8 + bind/java/seq_android.c.support | 401 ++ bind/java/seq_android.go.support | 98 + bind/java/seq_android.h | 67 + bind/java/seq_test.go | 257 ++ bind/objc/SeqBench.m | 197 + bind/objc/SeqCustom.m | 22 + bind/objc/SeqTest.m | 481 ++ bind/objc/SeqWrappers.m | 98 + bind/objc/doc.go | 6 + bind/objc/ref.h | 35 + bind/objc/seq_darwin.go.support | 91 + bind/objc/seq_darwin.h | 63 + bind/objc/seq_darwin.m.support | 381 ++ bind/objc/seq_test.go | 1010 ++++ bind/printer.go | 67 + bind/seq.go.support | 52 + bind/seq/ref.go | 153 + bind/seq/seq.go | 21 + bind/seq/string.go | 49 + bind/seq/string_test.go | 28 + bind/testdata/basictypes.go | 25 + bind/testdata/basictypes.go.golden | 73 + bind/testdata/basictypes.java.c.golden | 61 + bind/testdata/basictypes.java.golden | 37 + bind/testdata/basictypes.java.h.golden | 12 + bind/testdata/basictypes.objc.go.h.golden | 11 + bind/testdata/basictypes.objc.h.golden | 32 + bind/testdata/basictypes.objc.m.golden | 82 + bind/testdata/benchmark/benchmark.go | 171 + bind/testdata/cgopkg/cgopkg.go | 9 + bind/testdata/classes.go | 62 + bind/testdata/classes.go.golden | 2136 +++++++++ bind/testdata/classes.java.c.golden | 892 ++++ bind/testdata/classes.java.golden | 155 + bind/testdata/classes.java.h.golden | 103 + bind/testdata/customprefix.go | 10 + bind/testdata/customprefix.java.c.golden | 23 + bind/testdata/customprefix.java.golden | 26 + bind/testdata/customprefix.java.h.golden | 12 + bind/testdata/customprefix.objc.go.h.golden | 11 + bind/testdata/customprefix.objc.h.golden | 16 + bind/testdata/customprefix.objc.m.golden | 18 + bind/testdata/customprefixEX.objc.go.h.golden | 11 + bind/testdata/customprefixEX.objc.h.golden | 16 + bind/testdata/customprefixEX.objc.m.golden | 18 + bind/testdata/doc.go | 59 + bind/testdata/doc.go.golden | 190 + bind/testdata/doc.java.c.golden | 194 + bind/testdata/doc.java.golden | 324 ++ bind/testdata/doc.java.h.golden | 23 + bind/testdata/doc.objc.go.h.golden | 13 + bind/testdata/doc.objc.h.golden | 136 + bind/testdata/doc.objc.m.golden | 231 + bind/testdata/ignore.go | 59 + bind/testdata/ignore.go.golden | 63 + bind/testdata/ignore.java.c.golden | 75 + bind/testdata/ignore.java.golden | 135 + bind/testdata/ignore.java.h.golden | 21 + bind/testdata/ignore.objc.go.h.golden | 15 + bind/testdata/ignore.objc.h.golden | 84 + bind/testdata/ignore.objc.m.golden | 91 + bind/testdata/interfaces.go | 69 + bind/testdata/interfaces.go.golden | 257 ++ bind/testdata/interfaces.java.c.golden | 277 ++ bind/testdata/interfaces.java.golden | 277 ++ bind/testdata/interfaces.java.h.golden | 59 + bind/testdata/interfaces.objc.go.h.golden | 27 + bind/testdata/interfaces.objc.h.golden | 166 + bind/testdata/interfaces.objc.m.golden | 351 ++ bind/testdata/issue10788.go | 14 + bind/testdata/issue10788.go.golden | 86 + bind/testdata/issue10788.java.c.golden | 88 + bind/testdata/issue10788.java.golden | 110 + bind/testdata/issue10788.java.h.golden | 21 + bind/testdata/issue10788.objc.go.h.golden | 15 + bind/testdata/issue10788.objc.h.golden | 43 + bind/testdata/issue10788.objc.m.golden | 105 + bind/testdata/issue12328.go | 9 + bind/testdata/issue12328.go.golden | 54 + bind/testdata/issue12328.java.c.golden | 43 + bind/testdata/issue12328.java.golden | 82 + bind/testdata/issue12328.java.h.golden | 14 + bind/testdata/issue12328.objc.go.h.golden | 11 + bind/testdata/issue12328.objc.h.golden | 25 + bind/testdata/issue12328.objc.m.golden | 61 + bind/testdata/issue12403.go | 6 + bind/testdata/issue12403.go.golden | 74 + bind/testdata/issue12403.java.c.golden | 75 + bind/testdata/issue12403.java.golden | 53 + bind/testdata/issue12403.java.h.golden | 23 + bind/testdata/issue12403.objc.go.h.golden | 19 + bind/testdata/issue12403.objc.h.golden | 33 + bind/testdata/issue12403.objc.m.golden | 91 + bind/testdata/issue29559.go | 5 + bind/testdata/issue29559.go.golden | 29 + bind/testdata/issue29559.java.c.golden | 24 + bind/testdata/issue29559.java.golden | 26 + bind/testdata/issue29559.java.h.golden | 12 + bind/testdata/issue29559.objc.go.h.golden | 11 + bind/testdata/issue29559.objc.h.golden | 16 + bind/testdata/issue29559.objc.m.golden | 19 + bind/testdata/java.go | 16 + bind/testdata/java.go.golden | 407 ++ bind/testdata/java.java.c.golden | 191 + bind/testdata/java.java.golden | 127 + bind/testdata/java.java.h.golden | 82 + bind/testdata/keywords.go | 66 + bind/testdata/keywords.go.golden | 646 +++ bind/testdata/keywords.java.c.golden | 862 ++++ bind/testdata/keywords.java.golden | 161 + bind/testdata/keywords.java.h.golden | 125 + bind/testdata/keywords.objc.go.h.golden | 121 + bind/testdata/keywords.objc.h.golden | 143 + bind/testdata/keywords.objc.m.golden | 696 +++ bind/testdata/objc.go | 15 + bind/testdata/objc.go.golden | 93 + bind/testdata/objcw.go | 60 + bind/testdata/objcw.go.golden | 620 +++ bind/testdata/structs.go | 46 + bind/testdata/structs.go.golden | 167 + bind/testdata/structs.java.c.golden | 156 + bind/testdata/structs.java.golden | 206 + bind/testdata/structs.java.h.golden | 23 + bind/testdata/structs.objc.go.h.golden | 13 + bind/testdata/structs.objc.h.golden | 72 + bind/testdata/structs.objc.m.golden | 233 + bind/testdata/testpkg/assets/hello.txt | 1 + bind/testdata/testpkg/javapkg/classes.go | 202 + bind/testdata/testpkg/javapkg/java.go | 57 + bind/testdata/testpkg/objcpkg/classes.go | 72 + bind/testdata/testpkg/objcpkg/objc.go | 47 + bind/testdata/testpkg/secondpkg/secondpkg.go | 44 + bind/testdata/testpkg/simplepkg/simplepkg.go | 16 + bind/testdata/testpkg/tagged.go | 11 + bind/testdata/testpkg/testpkg.go | 628 +++ .../testdata/testpkg/unboundpkg/unboundpkg.go | 12 + bind/testdata/try.go | 9 + bind/testdata/try.go.golden | 30 + bind/testdata/try.java.c.golden | 25 + bind/testdata/try.java.golden | 26 + bind/testdata/try.java.h.golden | 12 + bind/testdata/try.objc.go.h.golden | 11 + bind/testdata/try.objc.h.golden | 16 + bind/testdata/try.objc.m.golden | 20 + bind/testdata/underscores.go | 13 + bind/testdata/underscores.go.golden | 61 + bind/testdata/underscores.java.c.golden | 61 + bind/testdata/underscores.java.golden | 86 + bind/testdata/underscores.java.h.golden | 14 + bind/testdata/underscores.objc.go.h.golden | 11 + bind/testdata/underscores.objc.h.golden | 33 + bind/testdata/underscores.objc.m.golden | 66 + bind/testdata/universe.golden | 43 + bind/testdata/universe.java.c.golden | 43 + bind/testdata/universe.java.golden | 53 + bind/testdata/universe.java.h.golden | 17 + bind/testdata/universe.objc.go.h.golden | 13 + bind/testdata/universe.objc.h.golden | 29 + bind/testdata/universe.objc.m.golden | 45 + bind/testdata/vars.go | 24 + bind/testdata/vars.go.golden | 211 + bind/testdata/vars.java.c.golden | 191 + bind/testdata/vars.java.golden | 129 + bind/testdata/vars.java.h.golden | 17 + bind/testdata/vars.objc.go.h.golden | 11 + bind/testdata/vars.objc.h.golden | 77 + bind/testdata/vars.objc.m.golden | 208 + bind/types.go | 172 + cmd/gobind/doc.go | 252 + cmd/gobind/gen.go | 392 ++ cmd/gobind/gobind_test.go | 218 + cmd/gobind/implicit.go | 12 + cmd/gobind/main.go | 169 + cmd/gomobile/bind.go | 335 ++ cmd/gomobile/bind_androidapp.go | 401 ++ cmd/gomobile/bind_iosapp.go | 316 ++ cmd/gomobile/bind_test.go | 326 ++ cmd/gomobile/build.go | 448 ++ cmd/gomobile/build_androidapp.go | 358 ++ cmd/gomobile/build_apple.go | 618 +++ cmd/gomobile/build_darwin_test.go | 123 + cmd/gomobile/build_test.go | 284 ++ cmd/gomobile/cert.go | 154 + cmd/gomobile/cert_test.go | 102 + cmd/gomobile/clean.go | 32 + cmd/gomobile/dex.go | 51 + cmd/gomobile/doc.go | 170 + cmd/gomobile/env.go | 621 +++ cmd/gomobile/env_test.go | 161 + cmd/gomobile/gendex.go | 160 + cmd/gomobile/init.go | 355 ++ cmd/gomobile/init_test.go | 204 + cmd/gomobile/install.go | 57 + cmd/gomobile/main.go | 204 + cmd/gomobile/manifest.go | 75 + cmd/gomobile/strings_flag.go | 62 + cmd/gomobile/tools.go | 10 + cmd/gomobile/version.go | 82 + cmd/gomobile/writer.go | 269 ++ cmd/gomobile/writer_test.go | 176 + codereview.cfg | 1 + doc/caution.png | Bin 0 -> 90400 bytes event/key/code_string.go | 60 + event/key/key.go | 270 ++ event/lifecycle/lifecycle.go | 136 + event/mouse/mouse.go | 90 + event/paint/paint.go | 24 + event/size/size.go | 92 + event/touch/touch.go | 72 + example/basic/main.go | 179 + example/basic/main_x.go | 11 + example/bind/android/README | 11 + example/bind/android/app/build.gradle | 34 + .../android/app/src/main/AndroidManifest.xml | 22 + .../org/golang/example/bind/MainActivity.java | 29 + .../app/src/main/res/layout/activity_main.xml | 17 + .../app/src/main/res/values/dimens.xml | 8 + example/bind/android/build.gradle | 21 + example/bind/android/settings.gradle | 5 + example/bind/hello/hello.go | 12 + example/bind/ios/README | 14 + .../bind/ios/bind.xcodeproj/project.pbxproj | 323 ++ example/bind/ios/bind/AppDelegate.h | 10 + example/bind/ios/bind/AppDelegate.m | 16 + .../bind/ios/bind/Base.lproj/LaunchScreen.xib | 41 + .../bind/ios/bind/Base.lproj/Main.storyboard | 50 + example/bind/ios/bind/Info.plist | 47 + example/bind/ios/bind/ViewController.h | 9 + example/bind/ios/bind/ViewController.m | 20 + example/bind/ios/bind/main.m | 12 + example/flappy/assets/README | 2 + example/flappy/assets/sprite.png | Bin 0 -> 76531 bytes example/flappy/game.go | 357 ++ example/flappy/main.go | 99 + example/flappy/main_x.go | 11 + example/ivy/android/README.md | 38 + example/ivy/android/app/build.gradle | 25 + example/ivy/android/app/proguard-rules.pro | 17 + .../java/org/golang/ivy/ApplicationTest.java | 13 + .../android/app/src/main/AndroidManifest.xml | 52 + .../android/app/src/main/assets/aboutivy.html | 21 + .../ivy/android/app/src/main/assets/demo.ivy | 263 ++ .../ivy/android/app/src/main/assets/tape.html | 61 + .../android/app/src/main/ic_launcher-web.png | Bin 0 -> 78730 bytes .../main/java/org/golang/ivy/AboutIvy.java | 56 + .../src/main/java/org/golang/ivy/Help.java | 54 + .../java/org/golang/ivy/MainActivity.java | 356 ++ .../res/drawable-hdpi/actionbar_solid.png | Bin 0 -> 200 bytes .../res/drawable-hdpi/ic_done_white_24dp.png | Bin 0 -> 188 bytes .../res/drawable-mdpi/actionbar_solid.png | Bin 0 -> 158 bytes .../res/drawable-mdpi/ic_done_white_24dp.png | Bin 0 -> 139 bytes .../res/drawable-xhdpi/actionbar_solid.png | Bin 0 -> 271 bytes .../res/drawable-xhdpi/ic_done_white_24dp.png | Bin 0 -> 199 bytes .../res/drawable-xxhdpi/actionbar_solid.png | Bin 0 -> 358 bytes .../drawable-xxhdpi/ic_done_white_24dp.png | Bin 0 -> 255 bytes .../src/main/res/drawable/circle_shape.xml | 13 + .../app/src/main/res/drawable/ivyabout.png | Bin 0 -> 283369 bytes .../src/main/res/layout/activity_about.xml | 30 + .../app/src/main/res/layout/activity_help.xml | 14 + .../app/src/main/res/layout/activity_main.xml | 69 + .../app/src/main/res/menu/menu_about.xml | 10 + .../app/src/main/res/menu/menu_main.xml | 24 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 4980 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2726 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 7582 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 14161 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 22453 bytes .../app/src/main/res/values-w820dp/dimens.xml | 6 + .../src/main/res/values-w820dp/strings.xml | 4 + .../app/src/main/res/values/colors.xml | 11 + .../app/src/main/res/values/dimens.xml | 5 + .../app/src/main/res/values/strings.xml | 51 + .../app/src/main/res/values/styles.xml | 16 + example/ivy/android/build.gradle | 18 + example/ivy/android/settings.gradle | 1 + example/ivy/doc.go | 7 + example/ivy/go.mod | 15 + example/ivy/go.sum | 40 + example/ivy/ios/README.md | 27 + example/ivy/ios/ivy.xcodeproj/project.pbxproj | 391 ++ example/ivy/ios/ivy/AppDelegate.h | 14 + example/ivy/ios/ivy/AppDelegate.m | 35 + .../ivy/ios/ivy/Base.lproj/Main.storyboard | 178 + example/ivy/ios/ivy/DocsController.h | 11 + example/ivy/ios/ivy/DocsController.m | 42 + .../AppIcon.appiconset/Contents.json | 300 ++ .../AppIcon.appiconset/icon-100.png | Bin 0 -> 11925 bytes .../AppIcon.appiconset/icon-1024.png | Bin 0 -> 437260 bytes .../AppIcon.appiconset/icon-120.png | Bin 0 -> 15461 bytes .../AppIcon.appiconset/icon-128.png | Bin 0 -> 17126 bytes .../AppIcon.appiconset/icon-152.png | Bin 0 -> 22208 bytes .../AppIcon.appiconset/icon-16.png | Bin 0 -> 957 bytes .../AppIcon.appiconset/icon-167.png | Bin 0 -> 25883 bytes .../AppIcon.appiconset/icon-172.png | Bin 0 -> 26679 bytes .../AppIcon.appiconset/icon-180.png | Bin 0 -> 25457 bytes .../AppIcon.appiconset/icon-196.png | Bin 0 -> 31607 bytes .../AppIcon.appiconset/icon-20.png | Bin 0 -> 1270 bytes .../AppIcon.appiconset/icon-216.png | Bin 0 -> 37221 bytes .../AppIcon.appiconset/icon-256.png | Bin 0 -> 48925 bytes .../AppIcon.appiconset/icon-29.png | Bin 0 -> 2111 bytes .../AppIcon.appiconset/icon-32.png | Bin 0 -> 2413 bytes .../AppIcon.appiconset/icon-40.png | Bin 0 -> 3290 bytes .../AppIcon.appiconset/icon-48.png | Bin 0 -> 4237 bytes .../AppIcon.appiconset/icon-512.png | Bin 0 -> 147107 bytes .../AppIcon.appiconset/icon-55.png | Bin 0 -> 5059 bytes .../AppIcon.appiconset/icon-58.png | Bin 0 -> 5386 bytes .../AppIcon.appiconset/icon-60.png | Bin 0 -> 5678 bytes .../AppIcon.appiconset/icon-64.png | Bin 0 -> 6158 bytes .../AppIcon.appiconset/icon-76.png | Bin 0 -> 7973 bytes .../AppIcon.appiconset/icon-80.png | Bin 0 -> 8534 bytes .../AppIcon.appiconset/icon-87.png | Bin 0 -> 9691 bytes .../AppIcon.appiconset/icon-88.png | Bin 0 -> 9788 bytes example/ivy/ios/ivy/Info.plist | 52 + example/ivy/ios/ivy/IvyController.h | 25 + example/ivy/ios/ivy/IvyController.m | 216 + example/ivy/ios/ivy/Suggestion.h | 22 + example/ivy/ios/ivy/Suggestion.m | 164 + example/ivy/ios/ivy/en.lproj/Main.strings | 18 + example/ivy/ios/ivy/main.m | 11 + example/ivy/ios/ivy/tape.html | 61 + example/ivy/tools.go | 15 + example/network/AndroidManifest.xml | 31 + example/network/main.go | 112 + example/network/main_x.go | 11 + exp/README | 2 + exp/app/debug/fps.go | 221 + exp/audio/al/al.go | 457 ++ exp/audio/al/al_android.go | 486 ++ exp/audio/al/al_notandroid.go | 209 + exp/audio/al/alc.go | 75 + exp/audio/al/alc_android.go | 76 + exp/audio/al/alc_notandroid.go | 71 + exp/audio/al/const.go | 83 + exp/f32/affine.go | 109 + exp/f32/affine_test.go | 136 + exp/f32/f32.go | 93 + exp/f32/f32_test.go | 361 ++ exp/f32/gen.go | 49 + exp/f32/mat3.go | 63 + exp/f32/mat4.go | 195 + exp/f32/table.go | 4105 +++++++++++++++++ exp/f32/vec3.go | 49 + exp/f32/vec4.go | 47 + exp/font/doc.go | 6 + exp/font/font.go | 28 + exp/font/font_android.go | 15 + exp/font/font_darwin.go | 76 + exp/font/font_linux.go | 32 + exp/font/font_test.go | 58 + exp/gl/glutil/context_darwin_desktop.go | 95 + exp/gl/glutil/context_x11.go | 106 + exp/gl/glutil/doc.go | 6 + exp/gl/glutil/glimage.go | 334 ++ exp/gl/glutil/glimage_test.go | 213 + exp/gl/glutil/glutil.go | 76 + exp/sensor/android.c | 85 + exp/sensor/android.go | 207 + exp/sensor/darwin_armx.go | 155 + exp/sensor/darwin_armx.m | 71 + exp/sensor/notmobile.go | 25 + exp/sensor/sensor.go | 130 + exp/sprite/clock/clock.go | 26 + exp/sprite/clock/tween.go | 83 + exp/sprite/clock/tween_test.go | 53 + exp/sprite/glsprite/glsprite.go | 162 + exp/sprite/portable/affine_test.go | 206 + exp/sprite/portable/portable.go | 193 + exp/sprite/sprite.go | 126 + geom/geom.go | 102 + gl/consts.go | 657 +++ gl/dll_windows.go | 243 + gl/doc.go | 66 + gl/fn.go | 210 + gl/gendebug.go | 997 ++++ gl/gl.go | 1853 ++++++++ gl/gldebug.go | 3674 +++++++++++++++ gl/interface.go | 889 ++++ gl/types_debug.go | 83 + gl/types_prod.go | 94 + gl/work.c | 557 +++ gl/work.go | 174 + gl/work.h | 217 + gl/work_other.go | 37 + gl/work_windows.go | 569 +++ gl/work_windows_386.s | 9 + gl/work_windows_amd64.s | 12 + go.mod | 13 + go.sum | 41 + internal/binres/arsc.go | 9 + internal/binres/binres.go | 963 ++++ internal/binres/binres_string.go | 62 + internal/binres/binres_test.go | 663 +++ internal/binres/genarsc.go | 41 + internal/binres/node.go | 252 + internal/binres/pool.go | 293 ++ internal/binres/sdk.go | 149 + internal/binres/table.go | 833 ++++ .../bootstrap-res/mipmap-xxxhdpi/icon.png | Bin 0 -> 486 bytes internal/binres/testdata/bootstrap.arsc | Bin 0 -> 644 bytes internal/binres/testdata/bootstrap.bin | Bin 0 -> 2416 bytes internal/binres/testdata/bootstrap.xml | 38 + internal/binres/testdata/gen.sh | 20 + internal/importers/ast.go | 248 + internal/importers/ast_test.go | 65 + internal/importers/java/java.go | 1183 +++++ internal/importers/java/java_test.go | 206 + internal/importers/objc/objc.go | 868 ++++ internal/importers/objc/objc_test.go | 83 + internal/mobileinit/ctx_android.go | 124 + internal/mobileinit/mobileinit.go | 11 + internal/mobileinit/mobileinit_android.go | 93 + internal/mobileinit/mobileinit_ios.go | 41 + internal/sdkpath/sdkpath.go | 89 + testdata/gophercolor.png | Bin 0 -> 8837 bytes testdata/gopherswim.png | Bin 0 -> 4218 bytes testdata/testpattern-window.png | Bin 0 -> 11152 bytes testdata/testpattern.png | Bin 0 -> 3195 bytes 466 files changed, 70845 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 PATENTS create mode 100644 README.md create mode 100644 app/GoNativeActivity.java create mode 100644 app/android.c create mode 100644 app/android.go create mode 100644 app/app.go create mode 100644 app/app_test.go create mode 100644 app/darwin_desktop.go create mode 100644 app/darwin_desktop.m create mode 100644 app/darwin_ios.go create mode 100644 app/darwin_ios.m create mode 100644 app/doc.go create mode 100644 app/internal/apptest/apptest.go create mode 100644 app/internal/callfn/callfn.go create mode 100644 app/internal/callfn/callfn_386.s create mode 100644 app/internal/callfn/callfn_amd64.s create mode 100644 app/internal/callfn/callfn_arm.s create mode 100644 app/internal/callfn/callfn_arm64.s create mode 100644 app/internal/testapp/AndroidManifest.xml create mode 100644 app/internal/testapp/testapp.go create mode 100644 app/shiny.go create mode 100644 app/x11.c create mode 100644 app/x11.go create mode 100644 asset/asset.go create mode 100644 asset/asset_android.go create mode 100644 asset/asset_darwin_armx.go create mode 100644 asset/asset_desktop.go create mode 100644 asset/doc.go create mode 100644 bind/bind.go create mode 100644 bind/bind_test.go create mode 100644 bind/gen.go create mode 100644 bind/genclasses.go create mode 100644 bind/gengo.go create mode 100644 bind/genjava.go create mode 100644 bind/genobjc.go create mode 100644 bind/genobjcw.go create mode 100644 bind/implicit.go create mode 100644 bind/java/ClassesTest.java create mode 100644 bind/java/CustomPkgTest.java create mode 100644 bind/java/Seq.java create mode 100644 bind/java/SeqBench.java create mode 100644 bind/java/SeqTest.java create mode 100644 bind/java/context_android.c create mode 100644 bind/java/context_android.go create mode 100644 bind/java/doc.go create mode 100644 bind/java/seq_android.c.support create mode 100644 bind/java/seq_android.go.support create mode 100644 bind/java/seq_android.h create mode 100644 bind/java/seq_test.go create mode 100644 bind/objc/SeqBench.m create mode 100644 bind/objc/SeqCustom.m create mode 100644 bind/objc/SeqTest.m create mode 100644 bind/objc/SeqWrappers.m create mode 100644 bind/objc/doc.go create mode 100644 bind/objc/ref.h create mode 100644 bind/objc/seq_darwin.go.support create mode 100644 bind/objc/seq_darwin.h create mode 100644 bind/objc/seq_darwin.m.support create mode 100644 bind/objc/seq_test.go create mode 100644 bind/printer.go create mode 100644 bind/seq.go.support create mode 100644 bind/seq/ref.go create mode 100644 bind/seq/seq.go create mode 100644 bind/seq/string.go create mode 100644 bind/seq/string_test.go create mode 100644 bind/testdata/basictypes.go create mode 100644 bind/testdata/basictypes.go.golden create mode 100644 bind/testdata/basictypes.java.c.golden create mode 100644 bind/testdata/basictypes.java.golden create mode 100644 bind/testdata/basictypes.java.h.golden create mode 100644 bind/testdata/basictypes.objc.go.h.golden create mode 100644 bind/testdata/basictypes.objc.h.golden create mode 100644 bind/testdata/basictypes.objc.m.golden create mode 100644 bind/testdata/benchmark/benchmark.go create mode 100644 bind/testdata/cgopkg/cgopkg.go create mode 100644 bind/testdata/classes.go create mode 100644 bind/testdata/classes.go.golden create mode 100644 bind/testdata/classes.java.c.golden create mode 100644 bind/testdata/classes.java.golden create mode 100644 bind/testdata/classes.java.h.golden create mode 100644 bind/testdata/customprefix.go create mode 100644 bind/testdata/customprefix.java.c.golden create mode 100644 bind/testdata/customprefix.java.golden create mode 100644 bind/testdata/customprefix.java.h.golden create mode 100644 bind/testdata/customprefix.objc.go.h.golden create mode 100644 bind/testdata/customprefix.objc.h.golden create mode 100644 bind/testdata/customprefix.objc.m.golden create mode 100644 bind/testdata/customprefixEX.objc.go.h.golden create mode 100644 bind/testdata/customprefixEX.objc.h.golden create mode 100644 bind/testdata/customprefixEX.objc.m.golden create mode 100644 bind/testdata/doc.go create mode 100644 bind/testdata/doc.go.golden create mode 100644 bind/testdata/doc.java.c.golden create mode 100644 bind/testdata/doc.java.golden create mode 100644 bind/testdata/doc.java.h.golden create mode 100644 bind/testdata/doc.objc.go.h.golden create mode 100644 bind/testdata/doc.objc.h.golden create mode 100644 bind/testdata/doc.objc.m.golden create mode 100644 bind/testdata/ignore.go create mode 100644 bind/testdata/ignore.go.golden create mode 100644 bind/testdata/ignore.java.c.golden create mode 100644 bind/testdata/ignore.java.golden create mode 100644 bind/testdata/ignore.java.h.golden create mode 100644 bind/testdata/ignore.objc.go.h.golden create mode 100644 bind/testdata/ignore.objc.h.golden create mode 100644 bind/testdata/ignore.objc.m.golden create mode 100644 bind/testdata/interfaces.go create mode 100644 bind/testdata/interfaces.go.golden create mode 100644 bind/testdata/interfaces.java.c.golden create mode 100644 bind/testdata/interfaces.java.golden create mode 100644 bind/testdata/interfaces.java.h.golden create mode 100644 bind/testdata/interfaces.objc.go.h.golden create mode 100644 bind/testdata/interfaces.objc.h.golden create mode 100644 bind/testdata/interfaces.objc.m.golden create mode 100644 bind/testdata/issue10788.go create mode 100644 bind/testdata/issue10788.go.golden create mode 100644 bind/testdata/issue10788.java.c.golden create mode 100644 bind/testdata/issue10788.java.golden create mode 100644 bind/testdata/issue10788.java.h.golden create mode 100644 bind/testdata/issue10788.objc.go.h.golden create mode 100644 bind/testdata/issue10788.objc.h.golden create mode 100644 bind/testdata/issue10788.objc.m.golden create mode 100644 bind/testdata/issue12328.go create mode 100644 bind/testdata/issue12328.go.golden create mode 100644 bind/testdata/issue12328.java.c.golden create mode 100644 bind/testdata/issue12328.java.golden create mode 100644 bind/testdata/issue12328.java.h.golden create mode 100644 bind/testdata/issue12328.objc.go.h.golden create mode 100644 bind/testdata/issue12328.objc.h.golden create mode 100644 bind/testdata/issue12328.objc.m.golden create mode 100644 bind/testdata/issue12403.go create mode 100644 bind/testdata/issue12403.go.golden create mode 100644 bind/testdata/issue12403.java.c.golden create mode 100644 bind/testdata/issue12403.java.golden create mode 100644 bind/testdata/issue12403.java.h.golden create mode 100644 bind/testdata/issue12403.objc.go.h.golden create mode 100644 bind/testdata/issue12403.objc.h.golden create mode 100644 bind/testdata/issue12403.objc.m.golden create mode 100644 bind/testdata/issue29559.go create mode 100644 bind/testdata/issue29559.go.golden create mode 100644 bind/testdata/issue29559.java.c.golden create mode 100644 bind/testdata/issue29559.java.golden create mode 100644 bind/testdata/issue29559.java.h.golden create mode 100644 bind/testdata/issue29559.objc.go.h.golden create mode 100644 bind/testdata/issue29559.objc.h.golden create mode 100644 bind/testdata/issue29559.objc.m.golden create mode 100644 bind/testdata/java.go create mode 100644 bind/testdata/java.go.golden create mode 100644 bind/testdata/java.java.c.golden create mode 100644 bind/testdata/java.java.golden create mode 100644 bind/testdata/java.java.h.golden create mode 100644 bind/testdata/keywords.go create mode 100644 bind/testdata/keywords.go.golden create mode 100644 bind/testdata/keywords.java.c.golden create mode 100644 bind/testdata/keywords.java.golden create mode 100644 bind/testdata/keywords.java.h.golden create mode 100644 bind/testdata/keywords.objc.go.h.golden create mode 100644 bind/testdata/keywords.objc.h.golden create mode 100644 bind/testdata/keywords.objc.m.golden create mode 100644 bind/testdata/objc.go create mode 100644 bind/testdata/objc.go.golden create mode 100644 bind/testdata/objcw.go create mode 100644 bind/testdata/objcw.go.golden create mode 100644 bind/testdata/structs.go create mode 100644 bind/testdata/structs.go.golden create mode 100644 bind/testdata/structs.java.c.golden create mode 100644 bind/testdata/structs.java.golden create mode 100644 bind/testdata/structs.java.h.golden create mode 100644 bind/testdata/structs.objc.go.h.golden create mode 100644 bind/testdata/structs.objc.h.golden create mode 100644 bind/testdata/structs.objc.m.golden create mode 100644 bind/testdata/testpkg/assets/hello.txt create mode 100644 bind/testdata/testpkg/javapkg/classes.go create mode 100644 bind/testdata/testpkg/javapkg/java.go create mode 100644 bind/testdata/testpkg/objcpkg/classes.go create mode 100644 bind/testdata/testpkg/objcpkg/objc.go create mode 100644 bind/testdata/testpkg/secondpkg/secondpkg.go create mode 100644 bind/testdata/testpkg/simplepkg/simplepkg.go create mode 100644 bind/testdata/testpkg/tagged.go create mode 100644 bind/testdata/testpkg/testpkg.go create mode 100644 bind/testdata/testpkg/unboundpkg/unboundpkg.go create mode 100644 bind/testdata/try.go create mode 100644 bind/testdata/try.go.golden create mode 100644 bind/testdata/try.java.c.golden create mode 100644 bind/testdata/try.java.golden create mode 100644 bind/testdata/try.java.h.golden create mode 100644 bind/testdata/try.objc.go.h.golden create mode 100644 bind/testdata/try.objc.h.golden create mode 100644 bind/testdata/try.objc.m.golden create mode 100644 bind/testdata/underscores.go create mode 100644 bind/testdata/underscores.go.golden create mode 100644 bind/testdata/underscores.java.c.golden create mode 100644 bind/testdata/underscores.java.golden create mode 100644 bind/testdata/underscores.java.h.golden create mode 100644 bind/testdata/underscores.objc.go.h.golden create mode 100644 bind/testdata/underscores.objc.h.golden create mode 100644 bind/testdata/underscores.objc.m.golden create mode 100644 bind/testdata/universe.golden create mode 100644 bind/testdata/universe.java.c.golden create mode 100644 bind/testdata/universe.java.golden create mode 100644 bind/testdata/universe.java.h.golden create mode 100644 bind/testdata/universe.objc.go.h.golden create mode 100644 bind/testdata/universe.objc.h.golden create mode 100644 bind/testdata/universe.objc.m.golden create mode 100644 bind/testdata/vars.go create mode 100644 bind/testdata/vars.go.golden create mode 100644 bind/testdata/vars.java.c.golden create mode 100644 bind/testdata/vars.java.golden create mode 100644 bind/testdata/vars.java.h.golden create mode 100644 bind/testdata/vars.objc.go.h.golden create mode 100644 bind/testdata/vars.objc.h.golden create mode 100644 bind/testdata/vars.objc.m.golden create mode 100644 bind/types.go create mode 100644 cmd/gobind/doc.go create mode 100644 cmd/gobind/gen.go create mode 100644 cmd/gobind/gobind_test.go create mode 100644 cmd/gobind/implicit.go create mode 100644 cmd/gobind/main.go create mode 100644 cmd/gomobile/bind.go create mode 100644 cmd/gomobile/bind_androidapp.go create mode 100644 cmd/gomobile/bind_iosapp.go create mode 100644 cmd/gomobile/bind_test.go create mode 100644 cmd/gomobile/build.go create mode 100644 cmd/gomobile/build_androidapp.go create mode 100644 cmd/gomobile/build_apple.go create mode 100644 cmd/gomobile/build_darwin_test.go create mode 100644 cmd/gomobile/build_test.go create mode 100644 cmd/gomobile/cert.go create mode 100644 cmd/gomobile/cert_test.go create mode 100644 cmd/gomobile/clean.go create mode 100644 cmd/gomobile/dex.go create mode 100644 cmd/gomobile/doc.go create mode 100644 cmd/gomobile/env.go create mode 100644 cmd/gomobile/env_test.go create mode 100644 cmd/gomobile/gendex.go create mode 100644 cmd/gomobile/init.go create mode 100644 cmd/gomobile/init_test.go create mode 100644 cmd/gomobile/install.go create mode 100644 cmd/gomobile/main.go create mode 100644 cmd/gomobile/manifest.go create mode 100644 cmd/gomobile/strings_flag.go create mode 100644 cmd/gomobile/tools.go create mode 100644 cmd/gomobile/version.go create mode 100644 cmd/gomobile/writer.go create mode 100644 cmd/gomobile/writer_test.go create mode 100644 codereview.cfg create mode 100644 doc/caution.png create mode 100644 event/key/code_string.go create mode 100644 event/key/key.go create mode 100644 event/lifecycle/lifecycle.go create mode 100644 event/mouse/mouse.go create mode 100644 event/paint/paint.go create mode 100644 event/size/size.go create mode 100644 event/touch/touch.go create mode 100644 example/basic/main.go create mode 100644 example/basic/main_x.go create mode 100644 example/bind/android/README create mode 100644 example/bind/android/app/build.gradle create mode 100644 example/bind/android/app/src/main/AndroidManifest.xml create mode 100644 example/bind/android/app/src/main/java/org/golang/example/bind/MainActivity.java create mode 100644 example/bind/android/app/src/main/res/layout/activity_main.xml create mode 100644 example/bind/android/app/src/main/res/values/dimens.xml create mode 100644 example/bind/android/build.gradle create mode 100644 example/bind/android/settings.gradle create mode 100644 example/bind/hello/hello.go create mode 100644 example/bind/ios/README create mode 100644 example/bind/ios/bind.xcodeproj/project.pbxproj create mode 100644 example/bind/ios/bind/AppDelegate.h create mode 100644 example/bind/ios/bind/AppDelegate.m create mode 100644 example/bind/ios/bind/Base.lproj/LaunchScreen.xib create mode 100644 example/bind/ios/bind/Base.lproj/Main.storyboard create mode 100644 example/bind/ios/bind/Info.plist create mode 100644 example/bind/ios/bind/ViewController.h create mode 100644 example/bind/ios/bind/ViewController.m create mode 100644 example/bind/ios/bind/main.m create mode 100644 example/flappy/assets/README create mode 100644 example/flappy/assets/sprite.png create mode 100644 example/flappy/game.go create mode 100644 example/flappy/main.go create mode 100644 example/flappy/main_x.go create mode 100644 example/ivy/android/README.md create mode 100644 example/ivy/android/app/build.gradle create mode 100644 example/ivy/android/app/proguard-rules.pro create mode 100644 example/ivy/android/app/src/androidTest/java/org/golang/ivy/ApplicationTest.java create mode 100644 example/ivy/android/app/src/main/AndroidManifest.xml create mode 100644 example/ivy/android/app/src/main/assets/aboutivy.html create mode 100644 example/ivy/android/app/src/main/assets/demo.ivy create mode 100644 example/ivy/android/app/src/main/assets/tape.html create mode 100644 example/ivy/android/app/src/main/ic_launcher-web.png create mode 100644 example/ivy/android/app/src/main/java/org/golang/ivy/AboutIvy.java create mode 100644 example/ivy/android/app/src/main/java/org/golang/ivy/Help.java create mode 100644 example/ivy/android/app/src/main/java/org/golang/ivy/MainActivity.java create mode 100755 example/ivy/android/app/src/main/res/drawable-hdpi/actionbar_solid.png create mode 100644 example/ivy/android/app/src/main/res/drawable-hdpi/ic_done_white_24dp.png create mode 100755 example/ivy/android/app/src/main/res/drawable-mdpi/actionbar_solid.png create mode 100644 example/ivy/android/app/src/main/res/drawable-mdpi/ic_done_white_24dp.png create mode 100755 example/ivy/android/app/src/main/res/drawable-xhdpi/actionbar_solid.png create mode 100644 example/ivy/android/app/src/main/res/drawable-xhdpi/ic_done_white_24dp.png create mode 100755 example/ivy/android/app/src/main/res/drawable-xxhdpi/actionbar_solid.png create mode 100644 example/ivy/android/app/src/main/res/drawable-xxhdpi/ic_done_white_24dp.png create mode 100644 example/ivy/android/app/src/main/res/drawable/circle_shape.xml create mode 100644 example/ivy/android/app/src/main/res/drawable/ivyabout.png create mode 100644 example/ivy/android/app/src/main/res/layout/activity_about.xml create mode 100644 example/ivy/android/app/src/main/res/layout/activity_help.xml create mode 100644 example/ivy/android/app/src/main/res/layout/activity_main.xml create mode 100644 example/ivy/android/app/src/main/res/menu/menu_about.xml create mode 100644 example/ivy/android/app/src/main/res/menu/menu_main.xml create mode 100644 example/ivy/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 example/ivy/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 example/ivy/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 example/ivy/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 example/ivy/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 example/ivy/android/app/src/main/res/values-w820dp/dimens.xml create mode 100644 example/ivy/android/app/src/main/res/values-w820dp/strings.xml create mode 100644 example/ivy/android/app/src/main/res/values/colors.xml create mode 100644 example/ivy/android/app/src/main/res/values/dimens.xml create mode 100644 example/ivy/android/app/src/main/res/values/strings.xml create mode 100644 example/ivy/android/app/src/main/res/values/styles.xml create mode 100644 example/ivy/android/build.gradle create mode 100644 example/ivy/android/settings.gradle create mode 100644 example/ivy/doc.go create mode 100644 example/ivy/go.mod create mode 100644 example/ivy/go.sum create mode 100644 example/ivy/ios/README.md create mode 100644 example/ivy/ios/ivy.xcodeproj/project.pbxproj create mode 100644 example/ivy/ios/ivy/AppDelegate.h create mode 100644 example/ivy/ios/ivy/AppDelegate.m create mode 100644 example/ivy/ios/ivy/Base.lproj/Main.storyboard create mode 100644 example/ivy/ios/ivy/DocsController.h create mode 100644 example/ivy/ios/ivy/DocsController.m create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-100.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-1024.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-120.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-128.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-152.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-16.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-167.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-172.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-180.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-196.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-20.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-216.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-256.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-29.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-32.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-40.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-48.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-512.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-55.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-58.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-60.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-64.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-76.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-80.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-87.png create mode 100644 example/ivy/ios/ivy/Images.xcassets/AppIcon.appiconset/icon-88.png create mode 100644 example/ivy/ios/ivy/Info.plist create mode 100644 example/ivy/ios/ivy/IvyController.h create mode 100644 example/ivy/ios/ivy/IvyController.m create mode 100644 example/ivy/ios/ivy/Suggestion.h create mode 100644 example/ivy/ios/ivy/Suggestion.m create mode 100644 example/ivy/ios/ivy/en.lproj/Main.strings create mode 100644 example/ivy/ios/ivy/main.m create mode 100644 example/ivy/ios/ivy/tape.html create mode 100644 example/ivy/tools.go create mode 100644 example/network/AndroidManifest.xml create mode 100644 example/network/main.go create mode 100644 example/network/main_x.go create mode 100644 exp/README create mode 100644 exp/app/debug/fps.go create mode 100644 exp/audio/al/al.go create mode 100644 exp/audio/al/al_android.go create mode 100644 exp/audio/al/al_notandroid.go create mode 100644 exp/audio/al/alc.go create mode 100644 exp/audio/al/alc_android.go create mode 100644 exp/audio/al/alc_notandroid.go create mode 100644 exp/audio/al/const.go create mode 100644 exp/f32/affine.go create mode 100644 exp/f32/affine_test.go create mode 100644 exp/f32/f32.go create mode 100644 exp/f32/f32_test.go create mode 100644 exp/f32/gen.go create mode 100644 exp/f32/mat3.go create mode 100644 exp/f32/mat4.go create mode 100644 exp/f32/table.go create mode 100644 exp/f32/vec3.go create mode 100644 exp/f32/vec4.go create mode 100644 exp/font/doc.go create mode 100644 exp/font/font.go create mode 100644 exp/font/font_android.go create mode 100644 exp/font/font_darwin.go create mode 100644 exp/font/font_linux.go create mode 100644 exp/font/font_test.go create mode 100644 exp/gl/glutil/context_darwin_desktop.go create mode 100644 exp/gl/glutil/context_x11.go create mode 100644 exp/gl/glutil/doc.go create mode 100644 exp/gl/glutil/glimage.go create mode 100644 exp/gl/glutil/glimage_test.go create mode 100644 exp/gl/glutil/glutil.go create mode 100644 exp/sensor/android.c create mode 100644 exp/sensor/android.go create mode 100644 exp/sensor/darwin_armx.go create mode 100644 exp/sensor/darwin_armx.m create mode 100644 exp/sensor/notmobile.go create mode 100644 exp/sensor/sensor.go create mode 100644 exp/sprite/clock/clock.go create mode 100644 exp/sprite/clock/tween.go create mode 100644 exp/sprite/clock/tween_test.go create mode 100644 exp/sprite/glsprite/glsprite.go create mode 100644 exp/sprite/portable/affine_test.go create mode 100644 exp/sprite/portable/portable.go create mode 100644 exp/sprite/sprite.go create mode 100644 geom/geom.go create mode 100644 gl/consts.go create mode 100644 gl/dll_windows.go create mode 100644 gl/doc.go create mode 100644 gl/fn.go create mode 100644 gl/gendebug.go create mode 100644 gl/gl.go create mode 100644 gl/gldebug.go create mode 100644 gl/interface.go create mode 100644 gl/types_debug.go create mode 100644 gl/types_prod.go create mode 100644 gl/work.c create mode 100644 gl/work.go create mode 100644 gl/work.h create mode 100644 gl/work_other.go create mode 100644 gl/work_windows.go create mode 100644 gl/work_windows_386.s create mode 100644 gl/work_windows_amd64.s create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/binres/arsc.go create mode 100644 internal/binres/binres.go create mode 100644 internal/binres/binres_string.go create mode 100644 internal/binres/binres_test.go create mode 100644 internal/binres/genarsc.go create mode 100644 internal/binres/node.go create mode 100644 internal/binres/pool.go create mode 100644 internal/binres/sdk.go create mode 100644 internal/binres/table.go create mode 100644 internal/binres/testdata/bootstrap-res/mipmap-xxxhdpi/icon.png create mode 100644 internal/binres/testdata/bootstrap.arsc create mode 100644 internal/binres/testdata/bootstrap.bin create mode 100644 internal/binres/testdata/bootstrap.xml create mode 100755 internal/binres/testdata/gen.sh create mode 100644 internal/importers/ast.go create mode 100644 internal/importers/ast_test.go create mode 100644 internal/importers/java/java.go create mode 100644 internal/importers/java/java_test.go create mode 100644 internal/importers/objc/objc.go create mode 100644 internal/importers/objc/objc_test.go create mode 100644 internal/mobileinit/ctx_android.go create mode 100644 internal/mobileinit/mobileinit.go create mode 100644 internal/mobileinit/mobileinit_android.go create mode 100644 internal/mobileinit/mobileinit_ios.go create mode 100644 internal/sdkpath/sdkpath.go create mode 100644 testdata/gophercolor.png create mode 100644 testdata/gopherswim.png create mode 100644 testdata/testpattern-window.png create mode 100644 testdata/testpattern.png diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..d2f212e5d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +# Treat all files in this repo as binary, with no git magic updating +# line endings. Windows users contributing to Go will need to use a +# modern version of git and editors capable of LF line endings. +# +# We'll prevent accidental CRLF line endings from entering the repo +# via the git-review gofmt checks. +# +# See golang.org/issue/9281 + +* -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..87baa6455 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Add no patterns to .gitignore except for files generated by the build. +last-change +*.apk +*.app +*.framework +*.xcframework +*.aar +*.jar +*.iml +.idea +.gradle +*.properties +.DS_Store +example/ivy/**/build/ +example/ivy/android/gradle/ + +# Xcode configuration files. +*.xcworkspace +xcuserdata +*.entitlements + +# Android Studio build and IDE configuration files. +example/bind/android/local.properties +example/bind/android/gradlew* +example/bind/android/gradle +example/bind/android/build +example/bind/android/app/build diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..d0485e887 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to Go + +Go is an open source project. + +It is the work of hundreds of contributors. We appreciate your help! + +## Filing issues + +When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. +The gophers there will answer or ask you to file an issue if you've tripped over a bug. + +## Contributing code + +Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) +before sending patches. + +Unless otherwise noted, the Go source files are distributed under +the BSD-style license found in the LICENSE file. diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/PATENTS b/PATENTS new file mode 100644 index 000000000..733099041 --- /dev/null +++ b/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/README.md b/README.md new file mode 100644 index 000000000..48253c6af --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# Go support for Mobile devices + +[![Go Reference](https://pkg.go.dev/badge/golang.org/x/mobile.svg)](https://pkg.go.dev/golang.org/x/mobile) + +The Go mobile repository holds packages and build tools for using Go on mobile platforms. + +Package documentation as a starting point: + +- [Building all-Go apps](https://golang.org/x/mobile/app) +- [Building libraries for SDK apps](https://golang.org/x/mobile/cmd/gobind) + +![Caution image](doc/caution.png) + +The Go Mobile project is experimental. Use this at your own risk. +While we are working hard to improve it, neither Google nor the Go +team can provide end-user support. + +This is early work and installing the build system requires Go 1.5. +Follow the instructions on +[golang.org/wiki/Mobile](https://golang.org/wiki/Mobile) +to install the gomobile command, build the +[basic](https://golang.org/x/mobile/example/basic) +and the [bind](https://golang.org/x/mobile/example/bind) example apps. + +-- + +Contributions to Go are appreciated. See https://golang.org/doc/contribute.html. + +* Bugs can be filed at the [Go issue tracker](https://golang.org/issue/new?title=x/mobile:+). +* Feature requests should preliminary be discussed on +[golang-nuts](https://groups.google.com/forum/#!forum/golang-nuts) +mailing list. diff --git a/app/GoNativeActivity.java b/app/GoNativeActivity.java new file mode 100644 index 000000000..e829c8c44 --- /dev/null +++ b/app/GoNativeActivity.java @@ -0,0 +1,67 @@ +package org.golang.app; + +import android.app.Activity; +import android.app.NativeActivity; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.util.Log; +import android.view.KeyCharacterMap; + +public class GoNativeActivity extends NativeActivity { + private static GoNativeActivity goNativeActivity; + + public GoNativeActivity() { + super(); + goNativeActivity = this; + } + + String getTmpdir() { + return getCacheDir().getAbsolutePath(); + } + + static int getRune(int deviceId, int keyCode, int metaState) { + try { + int rune = KeyCharacterMap.load(deviceId).get(keyCode, metaState); + if (rune == 0) { + return -1; + } + return rune; + } catch (KeyCharacterMap.UnavailableException e) { + return -1; + } catch (Exception e) { + Log.e("Go", "exception reading KeyCharacterMap", e); + return -1; + } + } + + private void load() { + // Interestingly, NativeActivity uses a different method + // to find native code to execute, avoiding + // System.loadLibrary. The result is Java methods + // implemented in C with JNIEXPORT (and JNI_OnLoad) are not + // available unless an explicit call to System.loadLibrary + // is done. So we do it here, borrowing the name of the + // library from the same AndroidManifest.xml metadata used + // by NativeActivity. + try { + ActivityInfo ai = getPackageManager().getActivityInfo( + getIntent().getComponent(), PackageManager.GET_META_DATA); + if (ai.metaData == null) { + Log.e("Go", "loadLibrary: no manifest metadata found"); + return; + } + String libName = ai.metaData.getString("android.app.lib_name"); + System.loadLibrary(libName); + } catch (Exception e) { + Log.e("Go", "loadLibrary failed", e); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + load(); + super.onCreate(savedInstanceState); + } +} diff --git a/app/android.c b/app/android.c new file mode 100644 index 000000000..305d586af --- /dev/null +++ b/app/android.c @@ -0,0 +1,201 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build android +// +build android + +#include +#include +#include +#include +#include +#include +#include "_cgo_export.h" + +#define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "Go", __VA_ARGS__) +#define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Go", __VA_ARGS__) + +static jclass current_class; + +static jclass find_class(JNIEnv *env, const char *class_name) { + jclass clazz = (*env)->FindClass(env, class_name); + if (clazz == NULL) { + (*env)->ExceptionClear(env); + LOG_FATAL("cannot find %s", class_name); + return NULL; + } + return clazz; +} + +static jmethodID find_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) { + jmethodID m = (*env)->GetMethodID(env, clazz, name, sig); + if (m == 0) { + (*env)->ExceptionClear(env); + LOG_FATAL("cannot find method %s %s", name, sig); + return 0; + } + return m; +} + +static jmethodID find_static_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) { + jmethodID m = (*env)->GetStaticMethodID(env, clazz, name, sig); + if (m == 0) { + (*env)->ExceptionClear(env); + LOG_FATAL("cannot find method %s %s", name, sig); + return 0; + } + return m; +} + +static jmethodID key_rune_method; + +jint JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) { + return -1; + } + + return JNI_VERSION_1_6; +} + +static int main_running = 0; + +// Entry point from our subclassed NativeActivity. +// +// By here, the Go runtime has been initialized (as we are running in +// -buildmode=c-shared) but the first time it is called, Go's main.main +// hasn't been called yet. +// +// The Activity may be created and destroyed multiple times throughout +// the life of a single process. Each time, onCreate is called. +void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize) { + if (!main_running) { + JNIEnv* env = activity->env; + + // Note that activity->clazz is mis-named. + current_class = (*env)->GetObjectClass(env, activity->clazz); + current_class = (*env)->NewGlobalRef(env, current_class); + key_rune_method = find_static_method(env, current_class, "getRune", "(III)I"); + + setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz)); + + // Set TMPDIR. + jmethodID gettmpdir = find_method(env, current_class, "getTmpdir", "()Ljava/lang/String;"); + jstring jpath = (jstring)(*env)->CallObjectMethod(env, activity->clazz, gettmpdir, NULL); + const char* tmpdir = (*env)->GetStringUTFChars(env, jpath, NULL); + if (setenv("TMPDIR", tmpdir, 1) != 0) { + LOG_INFO("setenv(\"TMPDIR\", \"%s\", 1) failed: %d", tmpdir, errno); + } + (*env)->ReleaseStringUTFChars(env, jpath, tmpdir); + + // Call the Go main.main. + uintptr_t mainPC = (uintptr_t)dlsym(RTLD_DEFAULT, "main.main"); + if (!mainPC) { + LOG_FATAL("missing main.main"); + } + callMain(mainPC); + main_running = 1; + } + + // These functions match the methods on Activity, described at + // http://developer.android.com/reference/android/app/Activity.html + // + // Note that onNativeWindowResized is not called on resize. Avoid it. + // https://code.google.com/p/android/issues/detail?id=180645 + activity->callbacks->onStart = onStart; + activity->callbacks->onResume = onResume; + activity->callbacks->onSaveInstanceState = onSaveInstanceState; + activity->callbacks->onPause = onPause; + activity->callbacks->onStop = onStop; + activity->callbacks->onDestroy = onDestroy; + activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; + activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; + activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded; + activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; + activity->callbacks->onInputQueueCreated = onInputQueueCreated; + activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; + activity->callbacks->onConfigurationChanged = onConfigurationChanged; + activity->callbacks->onLowMemory = onLowMemory; + + onCreate(activity); +} + +// TODO(crawshaw): Test configuration on more devices. +static const EGLint RGB_888[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_DEPTH_SIZE, 16, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_NONE +}; + +EGLDisplay display = NULL; +EGLSurface surface = NULL; + +static char* initEGLDisplay() { + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (!eglInitialize(display, 0, 0)) { + return "EGL initialize failed"; + } + return NULL; +} + +char* createEGLSurface(ANativeWindow* window) { + char* err; + EGLint numConfigs, format; + EGLConfig config; + EGLContext context; + + if (display == 0) { + if ((err = initEGLDisplay()) != NULL) { + return err; + } + } + + if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) { + return "EGL choose RGB_888 config failed"; + } + if (numConfigs <= 0) { + return "EGL no config found"; + } + + eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); + if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) { + return "EGL set buffers geometry failed"; + } + + surface = eglCreateWindowSurface(display, config, window, NULL); + if (surface == EGL_NO_SURFACE) { + return "EGL create surface failed"; + } + + const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { + return "eglMakeCurrent failed"; + } + return NULL; +} + +char* destroyEGLSurface() { + if (!eglDestroySurface(display, surface)) { + return "EGL destroy surface failed"; + } + return NULL; +} + +int32_t getKeyRune(JNIEnv* env, AInputEvent* e) { + return (int32_t)(*env)->CallStaticIntMethod( + env, + current_class, + key_rune_method, + AInputEvent_getDeviceId(e), + AKeyEvent_getKeyCode(e), + AKeyEvent_getMetaState(e) + ); +} diff --git a/app/android.go b/app/android.go new file mode 100644 index 000000000..08a6e0538 --- /dev/null +++ b/app/android.go @@ -0,0 +1,825 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build android +// +build android + +/* +Android Apps are built with -buildmode=c-shared. They are loaded by a +running Java process. + +Before any entry point is reached, a global constructor initializes the +Go runtime, calling all Go init functions. All cgo calls will block +until this is complete. Next JNI_OnLoad is called. When that is +complete, one of two entry points is called. + +All-Go apps built using NativeActivity enter at ANativeActivity_onCreate. + +Go libraries (for example, those built with gomobile bind) do not use +the app package initialization. +*/ + +package app + +/* +#cgo LDFLAGS: -landroid -llog -lEGL -lGLESv2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EGLDisplay display; +extern EGLSurface surface; + + +char* createEGLSurface(ANativeWindow* window); +char* destroyEGLSurface(); +int32_t getKeyRune(JNIEnv* env, AInputEvent* e); +*/ +import "C" +import ( + "fmt" + "log" + "os" + "time" + "unsafe" + + "golang.org/x/mobile/app/internal/callfn" + "golang.org/x/mobile/event/key" + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/paint" + "golang.org/x/mobile/event/size" + "golang.org/x/mobile/event/touch" + "golang.org/x/mobile/geom" + "golang.org/x/mobile/internal/mobileinit" +) + +// RunOnJVM runs fn on a new goroutine locked to an OS thread with a JNIEnv. +// +// RunOnJVM blocks until the call to fn is complete. Any Java +// exception or failure to attach to the JVM is returned as an error. +// +// The function fn takes vm, the current JavaVM*, +// env, the current JNIEnv*, and +// ctx, a jobject representing the global android.context.Context. +func RunOnJVM(fn func(vm, jniEnv, ctx uintptr) error) error { + return mobileinit.RunOnJVM(fn) +} + +//export setCurrentContext +func setCurrentContext(vm *C.JavaVM, ctx C.jobject) { + mobileinit.SetCurrentContext(unsafe.Pointer(vm), uintptr(ctx)) +} + +//export callMain +func callMain(mainPC uintptr) { + for _, name := range []string{"TMPDIR", "PATH", "LD_LIBRARY_PATH"} { + n := C.CString(name) + os.Setenv(name, C.GoString(C.getenv(n))) + C.free(unsafe.Pointer(n)) + } + + // Set timezone. + // + // Note that Android zoneinfo is stored in /system/usr/share/zoneinfo, + // but it is in some kind of packed TZiff file that we do not support + // yet. As a stopgap, we build a fixed zone using the tm_zone name. + var curtime C.time_t + var curtm C.struct_tm + C.time(&curtime) + C.localtime_r(&curtime, &curtm) + tzOffset := int(curtm.tm_gmtoff) + tz := C.GoString(curtm.tm_zone) + time.Local = time.FixedZone(tz, tzOffset) + + go callfn.CallFn(mainPC) +} + +//export onStart +func onStart(activity *C.ANativeActivity) { +} + +//export onResume +func onResume(activity *C.ANativeActivity) { +} + +//export onSaveInstanceState +func onSaveInstanceState(activity *C.ANativeActivity, outSize *C.size_t) unsafe.Pointer { + return nil +} + +//export onPause +func onPause(activity *C.ANativeActivity) { +} + +//export onStop +func onStop(activity *C.ANativeActivity) { +} + +//export onCreate +func onCreate(activity *C.ANativeActivity) { + // Set the initial configuration. + // + // Note we use unbuffered channels to talk to the activity loop, and + // NativeActivity calls these callbacks sequentially, so configuration + // will be set before <-windowRedrawNeeded is processed. + windowConfigChange <- windowConfigRead(activity) +} + +//export onDestroy +func onDestroy(activity *C.ANativeActivity) { +} + +//export onWindowFocusChanged +func onWindowFocusChanged(activity *C.ANativeActivity, hasFocus C.int) { +} + +//export onNativeWindowCreated +func onNativeWindowCreated(activity *C.ANativeActivity, window *C.ANativeWindow) { +} + +//export onNativeWindowRedrawNeeded +func onNativeWindowRedrawNeeded(activity *C.ANativeActivity, window *C.ANativeWindow) { + // Called on orientation change and window resize. + // Send a request for redraw, and block this function + // until a complete draw and buffer swap is completed. + // This is required by the redraw documentation to + // avoid bad draws. + windowRedrawNeeded <- window + <-windowRedrawDone +} + +//export onNativeWindowDestroyed +func onNativeWindowDestroyed(activity *C.ANativeActivity, window *C.ANativeWindow) { + windowDestroyed <- window +} + +//export onInputQueueCreated +func onInputQueueCreated(activity *C.ANativeActivity, q *C.AInputQueue) { + inputQueue <- q + <-inputQueueDone +} + +//export onInputQueueDestroyed +func onInputQueueDestroyed(activity *C.ANativeActivity, q *C.AInputQueue) { + inputQueue <- nil + <-inputQueueDone +} + +//export onContentRectChanged +func onContentRectChanged(activity *C.ANativeActivity, rect *C.ARect) { +} + +type windowConfig struct { + orientation size.Orientation + pixelsPerPt float32 +} + +func windowConfigRead(activity *C.ANativeActivity) windowConfig { + aconfig := C.AConfiguration_new() + C.AConfiguration_fromAssetManager(aconfig, activity.assetManager) + orient := C.AConfiguration_getOrientation(aconfig) + density := C.AConfiguration_getDensity(aconfig) + C.AConfiguration_delete(aconfig) + + // Calculate the screen resolution. This value is approximate. For example, + // a physical resolution of 200 DPI may be quantized to one of the + // ACONFIGURATION_DENSITY_XXX values such as 160 or 240. + // + // A more accurate DPI could possibly be calculated from + // https://developer.android.com/reference/android/util/DisplayMetrics.html#xdpi + // but this does not appear to be accessible via the NDK. In any case, the + // hardware might not even provide a more accurate number, as the system + // does not apparently use the reported value. See golang.org/issue/13366 + // for a discussion. + var dpi int + switch density { + case C.ACONFIGURATION_DENSITY_DEFAULT: + dpi = 160 + case C.ACONFIGURATION_DENSITY_LOW, + C.ACONFIGURATION_DENSITY_MEDIUM, + 213, // C.ACONFIGURATION_DENSITY_TV + C.ACONFIGURATION_DENSITY_HIGH, + 320, // ACONFIGURATION_DENSITY_XHIGH + 480, // ACONFIGURATION_DENSITY_XXHIGH + 640: // ACONFIGURATION_DENSITY_XXXHIGH + dpi = int(density) + case C.ACONFIGURATION_DENSITY_NONE: + log.Print("android device reports no screen density") + dpi = 72 + default: + log.Printf("android device reports unknown density: %d", density) + // All we can do is guess. + if density > 0 { + dpi = int(density) + } else { + dpi = 72 + } + } + + o := size.OrientationUnknown + switch orient { + case C.ACONFIGURATION_ORIENTATION_PORT: + o = size.OrientationPortrait + case C.ACONFIGURATION_ORIENTATION_LAND: + o = size.OrientationLandscape + } + + return windowConfig{ + orientation: o, + pixelsPerPt: float32(dpi) / 72, + } +} + +//export onConfigurationChanged +func onConfigurationChanged(activity *C.ANativeActivity) { + // A rotation event first triggers onConfigurationChanged, then + // calls onNativeWindowRedrawNeeded. We extract the orientation + // here and save it for the redraw event. + windowConfigChange <- windowConfigRead(activity) +} + +//export onLowMemory +func onLowMemory(activity *C.ANativeActivity) { +} + +var ( + inputQueue = make(chan *C.AInputQueue) + inputQueueDone = make(chan struct{}) + windowDestroyed = make(chan *C.ANativeWindow) + windowRedrawNeeded = make(chan *C.ANativeWindow) + windowRedrawDone = make(chan struct{}) + windowConfigChange = make(chan windowConfig) +) + +func init() { + theApp.registerGLViewportFilter() +} + +func main(f func(App)) { + mainUserFn = f + // TODO: merge the runInputQueue and mainUI functions? + go func() { + if err := mobileinit.RunOnJVM(runInputQueue); err != nil { + log.Fatalf("app: %v", err) + } + }() + // Preserve this OS thread for: + // 1. the attached JNI thread + // 2. the GL context + if err := mobileinit.RunOnJVM(mainUI); err != nil { + log.Fatalf("app: %v", err) + } +} + +var mainUserFn func(App) + +func mainUI(vm, jniEnv, ctx uintptr) error { + workAvailable := theApp.worker.WorkAvailable() + + donec := make(chan struct{}) + go func() { + // close the donec channel in a defer statement + // so that we could still be able to return even + // if mainUserFn panics. + defer close(donec) + + mainUserFn(theApp) + }() + + var pixelsPerPt float32 + var orientation size.Orientation + + for { + select { + case <-donec: + return nil + case cfg := <-windowConfigChange: + pixelsPerPt = cfg.pixelsPerPt + orientation = cfg.orientation + case w := <-windowRedrawNeeded: + if C.surface == nil { + if errStr := C.createEGLSurface(w); errStr != nil { + return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError()) + } + } + theApp.sendLifecycle(lifecycle.StageFocused) + widthPx := int(C.ANativeWindow_getWidth(w)) + heightPx := int(C.ANativeWindow_getHeight(w)) + theApp.eventsIn <- size.Event{ + WidthPx: widthPx, + HeightPx: heightPx, + WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt), + HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt), + PixelsPerPt: pixelsPerPt, + Orientation: orientation, + } + theApp.eventsIn <- paint.Event{External: true} + case <-windowDestroyed: + if C.surface != nil { + if errStr := C.destroyEGLSurface(); errStr != nil { + return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError()) + } + } + C.surface = nil + theApp.sendLifecycle(lifecycle.StageAlive) + case <-workAvailable: + theApp.worker.DoWork() + case <-theApp.publish: + // TODO: compare a generation number to redrawGen for stale paints? + if C.surface != nil { + // eglSwapBuffers blocks until vsync. + if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE { + log.Printf("app: failed to swap buffers (%s)", eglGetError()) + } + } + select { + case windowRedrawDone <- struct{}{}: + default: + } + theApp.publishResult <- PublishResult{} + } + } +} + +func runInputQueue(vm, jniEnv, ctx uintptr) error { + env := (*C.JNIEnv)(unsafe.Pointer(jniEnv)) // not a Go heap pointer + + // Android loopers select on OS file descriptors, not Go channels, so we + // translate the inputQueue channel to an ALooper_wake call. + l := C.ALooper_prepare(C.ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) + pending := make(chan *C.AInputQueue, 1) + go func() { + for q := range inputQueue { + pending <- q + C.ALooper_wake(l) + } + }() + + var q *C.AInputQueue + for { + if C.ALooper_pollAll(-1, nil, nil, nil) == C.ALOOPER_POLL_WAKE { + select { + default: + case p := <-pending: + if q != nil { + processEvents(env, q) + C.AInputQueue_detachLooper(q) + } + q = p + if q != nil { + C.AInputQueue_attachLooper(q, l, 0, nil, nil) + } + inputQueueDone <- struct{}{} + } + } + if q != nil { + processEvents(env, q) + } + } +} + +func processEvents(env *C.JNIEnv, q *C.AInputQueue) { + var e *C.AInputEvent + for C.AInputQueue_getEvent(q, &e) >= 0 { + if C.AInputQueue_preDispatchEvent(q, e) != 0 { + continue + } + processEvent(env, e) + C.AInputQueue_finishEvent(q, e, 0) + } +} + +func processEvent(env *C.JNIEnv, e *C.AInputEvent) { + switch C.AInputEvent_getType(e) { + case C.AINPUT_EVENT_TYPE_KEY: + processKey(env, e) + case C.AINPUT_EVENT_TYPE_MOTION: + // At most one of the events in this batch is an up or down event; get its index and change. + upDownIndex := C.size_t(C.AMotionEvent_getAction(e)&C.AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> C.AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT + upDownType := touch.TypeMove + switch C.AMotionEvent_getAction(e) & C.AMOTION_EVENT_ACTION_MASK { + case C.AMOTION_EVENT_ACTION_DOWN, C.AMOTION_EVENT_ACTION_POINTER_DOWN: + upDownType = touch.TypeBegin + case C.AMOTION_EVENT_ACTION_UP, C.AMOTION_EVENT_ACTION_POINTER_UP: + upDownType = touch.TypeEnd + } + + for i, n := C.size_t(0), C.AMotionEvent_getPointerCount(e); i < n; i++ { + t := touch.TypeMove + if i == upDownIndex { + t = upDownType + } + theApp.eventsIn <- touch.Event{ + X: float32(C.AMotionEvent_getX(e, i)), + Y: float32(C.AMotionEvent_getY(e, i)), + Sequence: touch.Sequence(C.AMotionEvent_getPointerId(e, i)), + Type: t, + } + } + default: + log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e)) + } +} + +func processKey(env *C.JNIEnv, e *C.AInputEvent) { + deviceID := C.AInputEvent_getDeviceId(e) + if deviceID == 0 { + // Software keyboard input, leaving for scribe/IME. + return + } + + k := key.Event{ + Rune: rune(C.getKeyRune(env, e)), + Code: convAndroidKeyCode(int32(C.AKeyEvent_getKeyCode(e))), + } + switch C.AKeyEvent_getAction(e) { + case C.AKEY_EVENT_ACTION_DOWN: + k.Direction = key.DirPress + case C.AKEY_EVENT_ACTION_UP: + k.Direction = key.DirRelease + default: + k.Direction = key.DirNone + } + // TODO(crawshaw): set Modifiers. + theApp.eventsIn <- k +} + +func eglGetError() string { + switch errNum := C.eglGetError(); errNum { + case C.EGL_SUCCESS: + return "EGL_SUCCESS" + case C.EGL_NOT_INITIALIZED: + return "EGL_NOT_INITIALIZED" + case C.EGL_BAD_ACCESS: + return "EGL_BAD_ACCESS" + case C.EGL_BAD_ALLOC: + return "EGL_BAD_ALLOC" + case C.EGL_BAD_ATTRIBUTE: + return "EGL_BAD_ATTRIBUTE" + case C.EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT" + case C.EGL_BAD_CONFIG: + return "EGL_BAD_CONFIG" + case C.EGL_BAD_CURRENT_SURFACE: + return "EGL_BAD_CURRENT_SURFACE" + case C.EGL_BAD_DISPLAY: + return "EGL_BAD_DISPLAY" + case C.EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE" + case C.EGL_BAD_MATCH: + return "EGL_BAD_MATCH" + case C.EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER" + case C.EGL_BAD_NATIVE_PIXMAP: + return "EGL_BAD_NATIVE_PIXMAP" + case C.EGL_BAD_NATIVE_WINDOW: + return "EGL_BAD_NATIVE_WINDOW" + case C.EGL_CONTEXT_LOST: + return "EGL_CONTEXT_LOST" + default: + return fmt.Sprintf("Unknown EGL err: %d", errNum) + } +} + +func convAndroidKeyCode(aKeyCode int32) key.Code { + // Many Android key codes do not map into USB HID codes. + // For those, key.CodeUnknown is returned. This switch has all + // cases, even the unknown ones, to serve as a documentation + // and search aid. + switch aKeyCode { + case C.AKEYCODE_UNKNOWN: + case C.AKEYCODE_SOFT_LEFT: + case C.AKEYCODE_SOFT_RIGHT: + case C.AKEYCODE_HOME: + return key.CodeHome + case C.AKEYCODE_BACK: + case C.AKEYCODE_CALL: + case C.AKEYCODE_ENDCALL: + case C.AKEYCODE_0: + return key.Code0 + case C.AKEYCODE_1: + return key.Code1 + case C.AKEYCODE_2: + return key.Code2 + case C.AKEYCODE_3: + return key.Code3 + case C.AKEYCODE_4: + return key.Code4 + case C.AKEYCODE_5: + return key.Code5 + case C.AKEYCODE_6: + return key.Code6 + case C.AKEYCODE_7: + return key.Code7 + case C.AKEYCODE_8: + return key.Code8 + case C.AKEYCODE_9: + return key.Code9 + case C.AKEYCODE_STAR: + case C.AKEYCODE_POUND: + case C.AKEYCODE_DPAD_UP: + case C.AKEYCODE_DPAD_DOWN: + case C.AKEYCODE_DPAD_LEFT: + case C.AKEYCODE_DPAD_RIGHT: + case C.AKEYCODE_DPAD_CENTER: + case C.AKEYCODE_VOLUME_UP: + return key.CodeVolumeUp + case C.AKEYCODE_VOLUME_DOWN: + return key.CodeVolumeDown + case C.AKEYCODE_POWER: + case C.AKEYCODE_CAMERA: + case C.AKEYCODE_CLEAR: + case C.AKEYCODE_A: + return key.CodeA + case C.AKEYCODE_B: + return key.CodeB + case C.AKEYCODE_C: + return key.CodeC + case C.AKEYCODE_D: + return key.CodeD + case C.AKEYCODE_E: + return key.CodeE + case C.AKEYCODE_F: + return key.CodeF + case C.AKEYCODE_G: + return key.CodeG + case C.AKEYCODE_H: + return key.CodeH + case C.AKEYCODE_I: + return key.CodeI + case C.AKEYCODE_J: + return key.CodeJ + case C.AKEYCODE_K: + return key.CodeK + case C.AKEYCODE_L: + return key.CodeL + case C.AKEYCODE_M: + return key.CodeM + case C.AKEYCODE_N: + return key.CodeN + case C.AKEYCODE_O: + return key.CodeO + case C.AKEYCODE_P: + return key.CodeP + case C.AKEYCODE_Q: + return key.CodeQ + case C.AKEYCODE_R: + return key.CodeR + case C.AKEYCODE_S: + return key.CodeS + case C.AKEYCODE_T: + return key.CodeT + case C.AKEYCODE_U: + return key.CodeU + case C.AKEYCODE_V: + return key.CodeV + case C.AKEYCODE_W: + return key.CodeW + case C.AKEYCODE_X: + return key.CodeX + case C.AKEYCODE_Y: + return key.CodeY + case C.AKEYCODE_Z: + return key.CodeZ + case C.AKEYCODE_COMMA: + return key.CodeComma + case C.AKEYCODE_PERIOD: + return key.CodeFullStop + case C.AKEYCODE_ALT_LEFT: + return key.CodeLeftAlt + case C.AKEYCODE_ALT_RIGHT: + return key.CodeRightAlt + case C.AKEYCODE_SHIFT_LEFT: + return key.CodeLeftShift + case C.AKEYCODE_SHIFT_RIGHT: + return key.CodeRightShift + case C.AKEYCODE_TAB: + return key.CodeTab + case C.AKEYCODE_SPACE: + return key.CodeSpacebar + case C.AKEYCODE_SYM: + case C.AKEYCODE_EXPLORER: + case C.AKEYCODE_ENVELOPE: + case C.AKEYCODE_ENTER: + return key.CodeReturnEnter + case C.AKEYCODE_DEL: + return key.CodeDeleteBackspace + case C.AKEYCODE_GRAVE: + return key.CodeGraveAccent + case C.AKEYCODE_MINUS: + return key.CodeHyphenMinus + case C.AKEYCODE_EQUALS: + return key.CodeEqualSign + case C.AKEYCODE_LEFT_BRACKET: + return key.CodeLeftSquareBracket + case C.AKEYCODE_RIGHT_BRACKET: + return key.CodeRightSquareBracket + case C.AKEYCODE_BACKSLASH: + return key.CodeBackslash + case C.AKEYCODE_SEMICOLON: + return key.CodeSemicolon + case C.AKEYCODE_APOSTROPHE: + return key.CodeApostrophe + case C.AKEYCODE_SLASH: + return key.CodeSlash + case C.AKEYCODE_AT: + case C.AKEYCODE_NUM: + case C.AKEYCODE_HEADSETHOOK: + case C.AKEYCODE_FOCUS: + case C.AKEYCODE_PLUS: + case C.AKEYCODE_MENU: + case C.AKEYCODE_NOTIFICATION: + case C.AKEYCODE_SEARCH: + case C.AKEYCODE_MEDIA_PLAY_PAUSE: + case C.AKEYCODE_MEDIA_STOP: + case C.AKEYCODE_MEDIA_NEXT: + case C.AKEYCODE_MEDIA_PREVIOUS: + case C.AKEYCODE_MEDIA_REWIND: + case C.AKEYCODE_MEDIA_FAST_FORWARD: + case C.AKEYCODE_MUTE: + case C.AKEYCODE_PAGE_UP: + return key.CodePageUp + case C.AKEYCODE_PAGE_DOWN: + return key.CodePageDown + case C.AKEYCODE_PICTSYMBOLS: + case C.AKEYCODE_SWITCH_CHARSET: + case C.AKEYCODE_BUTTON_A: + case C.AKEYCODE_BUTTON_B: + case C.AKEYCODE_BUTTON_C: + case C.AKEYCODE_BUTTON_X: + case C.AKEYCODE_BUTTON_Y: + case C.AKEYCODE_BUTTON_Z: + case C.AKEYCODE_BUTTON_L1: + case C.AKEYCODE_BUTTON_R1: + case C.AKEYCODE_BUTTON_L2: + case C.AKEYCODE_BUTTON_R2: + case C.AKEYCODE_BUTTON_THUMBL: + case C.AKEYCODE_BUTTON_THUMBR: + case C.AKEYCODE_BUTTON_START: + case C.AKEYCODE_BUTTON_SELECT: + case C.AKEYCODE_BUTTON_MODE: + case C.AKEYCODE_ESCAPE: + return key.CodeEscape + case C.AKEYCODE_FORWARD_DEL: + return key.CodeDeleteForward + case C.AKEYCODE_CTRL_LEFT: + return key.CodeLeftControl + case C.AKEYCODE_CTRL_RIGHT: + return key.CodeRightControl + case C.AKEYCODE_CAPS_LOCK: + return key.CodeCapsLock + case C.AKEYCODE_SCROLL_LOCK: + case C.AKEYCODE_META_LEFT: + return key.CodeLeftGUI + case C.AKEYCODE_META_RIGHT: + return key.CodeRightGUI + case C.AKEYCODE_FUNCTION: + case C.AKEYCODE_SYSRQ: + case C.AKEYCODE_BREAK: + case C.AKEYCODE_MOVE_HOME: + case C.AKEYCODE_MOVE_END: + case C.AKEYCODE_INSERT: + return key.CodeInsert + case C.AKEYCODE_FORWARD: + case C.AKEYCODE_MEDIA_PLAY: + case C.AKEYCODE_MEDIA_PAUSE: + case C.AKEYCODE_MEDIA_CLOSE: + case C.AKEYCODE_MEDIA_EJECT: + case C.AKEYCODE_MEDIA_RECORD: + case C.AKEYCODE_F1: + return key.CodeF1 + case C.AKEYCODE_F2: + return key.CodeF2 + case C.AKEYCODE_F3: + return key.CodeF3 + case C.AKEYCODE_F4: + return key.CodeF4 + case C.AKEYCODE_F5: + return key.CodeF5 + case C.AKEYCODE_F6: + return key.CodeF6 + case C.AKEYCODE_F7: + return key.CodeF7 + case C.AKEYCODE_F8: + return key.CodeF8 + case C.AKEYCODE_F9: + return key.CodeF9 + case C.AKEYCODE_F10: + return key.CodeF10 + case C.AKEYCODE_F11: + return key.CodeF11 + case C.AKEYCODE_F12: + return key.CodeF12 + case C.AKEYCODE_NUM_LOCK: + return key.CodeKeypadNumLock + case C.AKEYCODE_NUMPAD_0: + return key.CodeKeypad0 + case C.AKEYCODE_NUMPAD_1: + return key.CodeKeypad1 + case C.AKEYCODE_NUMPAD_2: + return key.CodeKeypad2 + case C.AKEYCODE_NUMPAD_3: + return key.CodeKeypad3 + case C.AKEYCODE_NUMPAD_4: + return key.CodeKeypad4 + case C.AKEYCODE_NUMPAD_5: + return key.CodeKeypad5 + case C.AKEYCODE_NUMPAD_6: + return key.CodeKeypad6 + case C.AKEYCODE_NUMPAD_7: + return key.CodeKeypad7 + case C.AKEYCODE_NUMPAD_8: + return key.CodeKeypad8 + case C.AKEYCODE_NUMPAD_9: + return key.CodeKeypad9 + case C.AKEYCODE_NUMPAD_DIVIDE: + return key.CodeKeypadSlash + case C.AKEYCODE_NUMPAD_MULTIPLY: + return key.CodeKeypadAsterisk + case C.AKEYCODE_NUMPAD_SUBTRACT: + return key.CodeKeypadHyphenMinus + case C.AKEYCODE_NUMPAD_ADD: + return key.CodeKeypadPlusSign + case C.AKEYCODE_NUMPAD_DOT: + return key.CodeKeypadFullStop + case C.AKEYCODE_NUMPAD_COMMA: + case C.AKEYCODE_NUMPAD_ENTER: + return key.CodeKeypadEnter + case C.AKEYCODE_NUMPAD_EQUALS: + return key.CodeKeypadEqualSign + case C.AKEYCODE_NUMPAD_LEFT_PAREN: + case C.AKEYCODE_NUMPAD_RIGHT_PAREN: + case C.AKEYCODE_VOLUME_MUTE: + return key.CodeMute + case C.AKEYCODE_INFO: + case C.AKEYCODE_CHANNEL_UP: + case C.AKEYCODE_CHANNEL_DOWN: + case C.AKEYCODE_ZOOM_IN: + case C.AKEYCODE_ZOOM_OUT: + case C.AKEYCODE_TV: + case C.AKEYCODE_WINDOW: + case C.AKEYCODE_GUIDE: + case C.AKEYCODE_DVR: + case C.AKEYCODE_BOOKMARK: + case C.AKEYCODE_CAPTIONS: + case C.AKEYCODE_SETTINGS: + case C.AKEYCODE_TV_POWER: + case C.AKEYCODE_TV_INPUT: + case C.AKEYCODE_STB_POWER: + case C.AKEYCODE_STB_INPUT: + case C.AKEYCODE_AVR_POWER: + case C.AKEYCODE_AVR_INPUT: + case C.AKEYCODE_PROG_RED: + case C.AKEYCODE_PROG_GREEN: + case C.AKEYCODE_PROG_YELLOW: + case C.AKEYCODE_PROG_BLUE: + case C.AKEYCODE_APP_SWITCH: + case C.AKEYCODE_BUTTON_1: + case C.AKEYCODE_BUTTON_2: + case C.AKEYCODE_BUTTON_3: + case C.AKEYCODE_BUTTON_4: + case C.AKEYCODE_BUTTON_5: + case C.AKEYCODE_BUTTON_6: + case C.AKEYCODE_BUTTON_7: + case C.AKEYCODE_BUTTON_8: + case C.AKEYCODE_BUTTON_9: + case C.AKEYCODE_BUTTON_10: + case C.AKEYCODE_BUTTON_11: + case C.AKEYCODE_BUTTON_12: + case C.AKEYCODE_BUTTON_13: + case C.AKEYCODE_BUTTON_14: + case C.AKEYCODE_BUTTON_15: + case C.AKEYCODE_BUTTON_16: + case C.AKEYCODE_LANGUAGE_SWITCH: + case C.AKEYCODE_MANNER_MODE: + case C.AKEYCODE_3D_MODE: + case C.AKEYCODE_CONTACTS: + case C.AKEYCODE_CALENDAR: + case C.AKEYCODE_MUSIC: + case C.AKEYCODE_CALCULATOR: + } + /* Defined in an NDK API version beyond what we use today: + C.AKEYCODE_ASSIST + C.AKEYCODE_BRIGHTNESS_DOWN + C.AKEYCODE_BRIGHTNESS_UP + C.AKEYCODE_EISU + C.AKEYCODE_HENKAN + C.AKEYCODE_KANA + C.AKEYCODE_KATAKANA_HIRAGANA + C.AKEYCODE_MEDIA_AUDIO_TRACK + C.AKEYCODE_MUHENKAN + C.AKEYCODE_RO + C.AKEYCODE_YEN + C.AKEYCODE_ZENKAKU_HANKAKU + */ + return key.CodeUnknown +} diff --git a/app/app.go b/app/app.go new file mode 100644 index 000000000..19efb07f1 --- /dev/null +++ b/app/app.go @@ -0,0 +1,214 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux || darwin || windows +// +build linux darwin windows + +package app + +import ( + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/size" + "golang.org/x/mobile/gl" + _ "golang.org/x/mobile/internal/mobileinit" +) + +// Main is called by the main.main function to run the mobile application. +// +// It calls f on the App, in a separate goroutine, as some OS-specific +// libraries require being on 'the main thread'. +func Main(f func(App)) { + main(f) +} + +// App is how a GUI mobile application interacts with the OS. +type App interface { + // Events returns the events channel. It carries events from the system to + // the app. The type of such events include: + // - lifecycle.Event + // - mouse.Event + // - paint.Event + // - size.Event + // - touch.Event + // from the golang.org/x/mobile/event/etc packages. Other packages may + // define other event types that are carried on this channel. + Events() <-chan interface{} + + // Send sends an event on the events channel. It does not block. + Send(event interface{}) + + // Publish flushes any pending drawing commands, such as OpenGL calls, and + // swaps the back buffer to the screen. + Publish() PublishResult + + // TODO: replace filters (and the Events channel) with a NextEvent method? + + // Filter calls each registered event filter function in sequence. + Filter(event interface{}) interface{} + + // RegisterFilter registers a event filter function to be called by Filter. The + // function can return a different event, or return nil to consume the event, + // but the function can also return its argument unchanged, where its purpose + // is to trigger a side effect rather than modify the event. + RegisterFilter(f func(interface{}) interface{}) +} + +// PublishResult is the result of an App.Publish call. +type PublishResult struct { + // BackBufferPreserved is whether the contents of the back buffer was + // preserved. If false, the contents are undefined. + BackBufferPreserved bool +} + +var theApp = &app{ + eventsOut: make(chan interface{}), + lifecycleStage: lifecycle.StageDead, + publish: make(chan struct{}), + publishResult: make(chan PublishResult), +} + +func init() { + theApp.eventsIn = pump(theApp.eventsOut) + theApp.glctx, theApp.worker = gl.NewContext() +} + +func (a *app) sendLifecycle(to lifecycle.Stage) { + if a.lifecycleStage == to { + return + } + a.eventsIn <- lifecycle.Event{ + From: a.lifecycleStage, + To: to, + DrawContext: a.glctx, + } + a.lifecycleStage = to +} + +type app struct { + filters []func(interface{}) interface{} + + eventsOut chan interface{} + eventsIn chan interface{} + lifecycleStage lifecycle.Stage + publish chan struct{} + publishResult chan PublishResult + + glctx gl.Context + worker gl.Worker +} + +func (a *app) Events() <-chan interface{} { + return a.eventsOut +} + +func (a *app) Send(event interface{}) { + a.eventsIn <- event +} + +func (a *app) Publish() PublishResult { + // gl.Flush is a lightweight (on modern GL drivers) blocking call + // that ensures all GL functions pending in the gl package have + // been passed onto the GL driver before the app package attempts + // to swap the screen buffer. + // + // This enforces that the final receive (for this paint cycle) on + // gl.WorkAvailable happens before the send on endPaint. + a.glctx.Flush() + a.publish <- struct{}{} + return <-a.publishResult +} + +func (a *app) Filter(event interface{}) interface{} { + for _, f := range a.filters { + event = f(event) + } + return event +} + +func (a *app) RegisterFilter(f func(interface{}) interface{}) { + a.filters = append(a.filters, f) +} + +type stopPumping struct{} + +// pump returns a channel src such that sending on src will eventually send on +// dst, in order, but that src will always be ready to send/receive soon, even +// if dst currently isn't. It is effectively an infinitely buffered channel. +// +// In particular, goroutine A sending on src will not deadlock even if goroutine +// B that's responsible for receiving on dst is currently blocked trying to +// send to A on a separate channel. +// +// Send a stopPumping on the src channel to close the dst channel after all queued +// events are sent on dst. After that, other goroutines can still send to src, +// so that such sends won't block forever, but such events will be ignored. +func pump(dst chan interface{}) (src chan interface{}) { + src = make(chan interface{}) + go func() { + // initialSize is the initial size of the circular buffer. It must be a + // power of 2. + const initialSize = 16 + i, j, buf, mask := 0, 0, make([]interface{}, initialSize), initialSize-1 + + srcActive := true + for { + maybeDst := dst + if i == j { + maybeDst = nil + } + if maybeDst == nil && !srcActive { + // Pump is stopped and empty. + break + } + + select { + case maybeDst <- buf[i&mask]: + buf[i&mask] = nil + i++ + + case e := <-src: + if _, ok := e.(stopPumping); ok { + srcActive = false + continue + } + + if !srcActive { + continue + } + + // Allocate a bigger buffer if necessary. + if i+len(buf) == j { + b := make([]interface{}, 2*len(buf)) + n := copy(b, buf[j&mask:]) + copy(b[n:], buf[:j&mask]) + i, j = 0, len(buf) + buf, mask = b, len(b)-1 + } + + buf[j&mask] = e + j++ + } + } + + close(dst) + // Block forever. + for range src { + } + }() + return src +} + +// TODO: do this for all build targets, not just linux (x11 and Android)? If +// so, should package gl instead of this package call RegisterFilter?? +// +// TODO: does Android need this?? It seems to work without it (Nexus 7, +// KitKat). If only x11 needs this, should we move this to x11.go?? +func (a *app) registerGLViewportFilter() { + a.RegisterFilter(func(e interface{}) interface{} { + if e, ok := e.(size.Event); ok { + a.glctx.Viewport(0, 0, e.WidthPx, e.HeightPx) + } + return e + }) +} diff --git a/app/app_test.go b/app/app_test.go new file mode 100644 index 000000000..91742192b --- /dev/null +++ b/app/app_test.go @@ -0,0 +1,238 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package app_test + +import ( + "fmt" + "image" + "image/color" + _ "image/png" + "io/ioutil" + "net" + "os" + "os/exec" + "strings" + "testing" + "time" + + "golang.org/x/mobile/app/internal/apptest" + "golang.org/x/mobile/event/size" +) + +// TestAndroidApp tests the lifecycle, event, and window semantics of a +// simple android app. +// +// Beyond testing the app package, the goal is to eventually have +// helper libraries that make tests like these easy to write. Hopefully +// having a user of such a fictional package will help illuminate the way. +func TestAndroidApp(t *testing.T) { + t.Skip("see issue #23835") + if _, err := exec.Command("which", "adb").CombinedOutput(); err != nil { + t.Skip("command adb not found, skipping") + } + devicesTxt, err := exec.Command("adb", "devices").CombinedOutput() + if err != nil { + t.Errorf("adb devices failed: %v: %v", err, devicesTxt) + } + deviceCount := 0 + for _, d := range strings.Split(strings.TrimSpace(string(devicesTxt)), "\n") { + if strings.Contains(d, "List of devices") { + continue + } + // TODO(crawshaw): I believe some unusable devices can appear in the + // list with note on them, but I cannot reproduce this right now. + deviceCount++ + } + if deviceCount == 0 { + t.Skip("no android devices attached") + } + + run(t, "gomobile", "version") + + origWD, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + + tmpdir, err := ioutil.TempDir("", "app-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + if err := os.Chdir(tmpdir); err != nil { + t.Fatal(err) + } + defer os.Chdir(origWD) + + run(t, "gomobile", "install", "golang.org/x/mobile/app/internal/testapp") + + ln, err := net.Listen("tcp4", "localhost:0") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + localaddr := fmt.Sprintf("tcp:%d", ln.Addr().(*net.TCPAddr).Port) + t.Logf("local address: %s", localaddr) + + exec.Command("adb", "reverse", "--remove", "tcp:"+apptest.Port).Run() // ignore failure + run(t, "adb", "reverse", "tcp:"+apptest.Port, localaddr) + + const ( + KeycodePower = "26" + KeycodeUnlock = "82" + ) + + run(t, "adb", "shell", "input", "keyevent", KeycodePower) + run(t, "adb", "shell", "input", "keyevent", KeycodeUnlock) + + const ( + rotationPortrait = "0" + rotationLandscape = "1" + ) + + rotate := func(rotation string) { + run(t, "adb", "shell", "content", "insert", "--uri", "content://settings/system", "--bind", "name:s:user_rotation", "--bind", "value:i:"+rotation) + } + + // turn off automatic rotation and start in portrait + run(t, "adb", "shell", "content", "insert", "--uri", "content://settings/system", "--bind", "name:s:accelerometer_rotation", "--bind", "value:i:0") + rotate(rotationPortrait) + + // start testapp + run(t, + "adb", "shell", "am", "start", "-n", + "org.golang.testapp/org.golang.app.GoNativeActivity", + ) + + var conn net.Conn + connDone := make(chan struct{}) + go func() { + conn, err = ln.Accept() + connDone <- struct{}{} + }() + + select { + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for testapp to dial host") + case <-connDone: + if err != nil { + t.Fatalf("ln.Accept: %v", err) + } + } + defer conn.Close() + comm := &apptest.Comm{ + Conn: conn, + Fatalf: t.Fatalf, + Printf: t.Logf, + } + + var pixelsPerPt float32 + var orientation size.Orientation + + comm.Recv("hello_from_testapp") + comm.Send("hello_from_host") + comm.Recv("lifecycle_visible") + comm.Recv("size", &pixelsPerPt, &orientation) + if pixelsPerPt < 0.1 { + t.Fatalf("bad pixelsPerPt: %f", pixelsPerPt) + } + + // A single paint event is sent when the lifecycle enters + // StageVisible, and after the end of a touch event. + var color string + comm.Recv("paint", &color) + // Ignore the first paint color, it may be slow making it to the screen. + + rotate(rotationLandscape) + comm.Recv("size", &pixelsPerPt, &orientation) + if want := size.OrientationLandscape; orientation != want { + t.Errorf("want orientation %d, got %d", want, orientation) + } + + var x, y int + var ty string + + tap(t, 50, 260) + comm.Recv("touch", &ty, &x, &y) + if ty != "begin" || x != 50 || y != 260 { + t.Errorf("want touch begin(50, 260), got %s(%d,%d)", ty, x, y) + } + comm.Recv("touch", &ty, &x, &y) + if ty != "end" || x != 50 || y != 260 { + t.Errorf("want touch end(50, 260), got %s(%d,%d)", ty, x, y) + } + + comm.Recv("paint", &color) + if gotColor := currentColor(t); color != gotColor { + t.Errorf("app reports color %q, but saw %q", color, gotColor) + } + + rotate(rotationPortrait) + comm.Recv("size", &pixelsPerPt, &orientation) + if want := size.OrientationPortrait; orientation != want { + t.Errorf("want orientation %d, got %d", want, orientation) + } + + tap(t, 50, 260) + comm.Recv("touch", &ty, &x, &y) // touch begin + comm.Recv("touch", &ty, &x, &y) // touch end + comm.Recv("paint", &color) + if gotColor := currentColor(t); color != gotColor { + t.Errorf("app reports color %q, but saw %q", color, gotColor) + } + + // TODO: lifecycle testing (NOTE: adb shell input keyevent 4 is the back button) +} + +func currentColor(t *testing.T) string { + file := fmt.Sprintf("app-screen-%d.png", time.Now().Unix()) + + run(t, "adb", "shell", "screencap", "-p", "/data/local/tmp/"+file) + run(t, "adb", "pull", "/data/local/tmp/"+file) + run(t, "adb", "shell", "rm", "/data/local/tmp/"+file) + defer os.Remove(file) + + f, err := os.Open(file) + if err != nil { + t.Errorf("currentColor: cannot open screencap: %v", err) + return "" + } + m, _, err := image.Decode(f) + if err != nil { + t.Errorf("currentColor: cannot decode screencap: %v", err) + return "" + } + var center color.Color + { + b := m.Bounds() + x, y := b.Min.X+(b.Max.X-b.Min.X)/2, b.Min.Y+(b.Max.Y-b.Min.Y)/2 + center = m.At(x, y) + } + r, g, b, _ := center.RGBA() + switch { + case r == 0xffff && g == 0x0000 && b == 0x0000: + return "red" + case r == 0x0000 && g == 0xffff && b == 0x0000: + return "green" + case r == 0x0000 && g == 0x0000 && b == 0xffff: + return "blue" + default: + return fmt.Sprintf("indeterminate: %v", center) + } +} + +func tap(t *testing.T, x, y int) { + run(t, "adb", "shell", "input", "tap", fmt.Sprintf("%d", x), fmt.Sprintf("%d", y)) +} + +func run(t *testing.T, cmdName string, arg ...string) { + cmd := exec.Command(cmdName, arg...) + t.Log(strings.Join(cmd.Args, " ")) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%s %v: %s", strings.Join(cmd.Args, " "), err, out) + } +} diff --git a/app/darwin_desktop.go b/app/darwin_desktop.go new file mode 100644 index 000000000..337717531 --- /dev/null +++ b/app/darwin_desktop.go @@ -0,0 +1,496 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && !ios +// +build darwin,!ios + +package app + +// Simple on-screen app debugging for OS X. Not an officially supported +// development target for apps, as screens with mice are very different +// than screens with touch panels. + +/* +#cgo CFLAGS: -x objective-c -DGL_SILENCE_DEPRECATION +#cgo LDFLAGS: -framework Cocoa -framework OpenGL +#import // for HIToolbox/Events.h +#import +#include + +void runApp(void); +void stopApp(void); +void makeCurrentContext(GLintptr); +uint64 threadID(); +*/ +import "C" +import ( + "log" + "runtime" + "sync" + + "golang.org/x/mobile/event/key" + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/paint" + "golang.org/x/mobile/event/size" + "golang.org/x/mobile/event/touch" + "golang.org/x/mobile/geom" +) + +var initThreadID uint64 + +func init() { + // Lock the goroutine responsible for initialization to an OS thread. + // This means the goroutine running main (and calling runApp below) + // is locked to the OS thread that started the program. This is + // necessary for the correct delivery of Cocoa events to the process. + // + // A discussion on this topic: + // https://groups.google.com/forum/#!msg/golang-nuts/IiWZ2hUuLDA/SNKYYZBelsYJ + runtime.LockOSThread() + initThreadID = uint64(C.threadID()) +} + +func main(f func(App)) { + if tid := uint64(C.threadID()); tid != initThreadID { + log.Fatalf("app.Main called on thread %d, but app.init ran on %d", tid, initThreadID) + } + + go func() { + f(theApp) + C.stopApp() + }() + + C.runApp() +} + +// loop is the primary drawing loop. +// +// After Cocoa has captured the initial OS thread for processing Cocoa +// events in runApp, it starts loop on another goroutine. It is locked +// to an OS thread for its OpenGL context. +// +// The loop processes GL calls until a publish event appears. +// Then it runs any remaining GL calls and flushes the screen. +// +// As NSOpenGLCPSwapInterval is set to 1, the call to CGLFlushDrawable +// blocks until the screen refresh. +func (a *app) loop(ctx C.GLintptr) { + runtime.LockOSThread() + C.makeCurrentContext(ctx) + + workAvailable := a.worker.WorkAvailable() + + for { + select { + case <-workAvailable: + a.worker.DoWork() + case <-theApp.publish: + loop1: + for { + select { + case <-workAvailable: + a.worker.DoWork() + default: + break loop1 + } + } + C.CGLFlushDrawable(C.CGLGetCurrentContext()) + theApp.publishResult <- PublishResult{} + select { + case drawDone <- struct{}{}: + default: + } + } + } +} + +var drawDone = make(chan struct{}) + +// drawgl is used by Cocoa to occasionally request screen updates. +// +//export drawgl +func drawgl() { + switch theApp.lifecycleStage { + case lifecycle.StageFocused, lifecycle.StageVisible: + theApp.Send(paint.Event{ + External: true, + }) + <-drawDone + } +} + +//export startloop +func startloop(ctx C.GLintptr) { + go theApp.loop(ctx) +} + +var windowHeightPx float32 + +//export setGeom +func setGeom(pixelsPerPt float32, widthPx, heightPx int) { + windowHeightPx = float32(heightPx) + theApp.eventsIn <- size.Event{ + WidthPx: widthPx, + HeightPx: heightPx, + WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt), + HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt), + PixelsPerPt: pixelsPerPt, + } +} + +var touchEvents struct { + sync.Mutex + pending []touch.Event +} + +func sendTouch(t touch.Type, x, y float32) { + theApp.eventsIn <- touch.Event{ + X: x, + Y: windowHeightPx - y, + Sequence: 0, + Type: t, + } +} + +//export eventMouseDown +func eventMouseDown(x, y float32) { sendTouch(touch.TypeBegin, x, y) } + +//export eventMouseDragged +func eventMouseDragged(x, y float32) { sendTouch(touch.TypeMove, x, y) } + +//export eventMouseEnd +func eventMouseEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) } + +//export lifecycleDead +func lifecycleDead() { theApp.sendLifecycle(lifecycle.StageDead) } + +//export eventKey +func eventKey(runeVal int32, direction uint8, code uint16, flags uint32) { + var modifiers key.Modifiers + for _, mod := range mods { + if flags&mod.flags == mod.flags { + modifiers |= mod.mod + } + } + + theApp.eventsIn <- key.Event{ + Rune: convRune(rune(runeVal)), + Code: convVirtualKeyCode(code), + Modifiers: modifiers, + Direction: key.Direction(direction), + } +} + +//export eventFlags +func eventFlags(flags uint32) { + for _, mod := range mods { + if flags&mod.flags == mod.flags && lastFlags&mod.flags != mod.flags { + eventKey(-1, uint8(key.DirPress), mod.code, flags) + } + if lastFlags&mod.flags == mod.flags && flags&mod.flags != mod.flags { + eventKey(-1, uint8(key.DirRelease), mod.code, flags) + } + } + lastFlags = flags +} + +var lastFlags uint32 + +var mods = [...]struct { + flags uint32 + code uint16 + mod key.Modifiers +}{ + // Left and right variants of modifier keys have their own masks, + // but they are not documented. These were determined empirically. + {1<<17 | 0x102, C.kVK_Shift, key.ModShift}, + {1<<17 | 0x104, C.kVK_RightShift, key.ModShift}, + {1<<18 | 0x101, C.kVK_Control, key.ModControl}, + // TODO key.ControlRight + {1<<19 | 0x120, C.kVK_Option, key.ModAlt}, + {1<<19 | 0x140, C.kVK_RightOption, key.ModAlt}, + {1<<20 | 0x108, C.kVK_Command, key.ModMeta}, + {1<<20 | 0x110, C.kVK_Command, key.ModMeta}, // TODO: missing kVK_RightCommand +} + +//export lifecycleAlive +func lifecycleAlive() { theApp.sendLifecycle(lifecycle.StageAlive) } + +//export lifecycleVisible +func lifecycleVisible() { + theApp.sendLifecycle(lifecycle.StageVisible) +} + +//export lifecycleFocused +func lifecycleFocused() { theApp.sendLifecycle(lifecycle.StageFocused) } + +// convRune marks the Carbon/Cocoa private-range unicode rune representing +// a non-unicode key event to -1, used for Rune in the key package. +// +// http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT +func convRune(r rune) rune { + if '\uE000' <= r && r <= '\uF8FF' { + return -1 + } + return r +} + +// convVirtualKeyCode converts a Carbon/Cocoa virtual key code number +// into the standard keycodes used by the key package. +// +// To get a sense of the key map, see the diagram on +// +// http://boredzo.org/blog/archives/2007-05-22/virtual-key-codes +func convVirtualKeyCode(vkcode uint16) key.Code { + switch vkcode { + case C.kVK_ANSI_A: + return key.CodeA + case C.kVK_ANSI_B: + return key.CodeB + case C.kVK_ANSI_C: + return key.CodeC + case C.kVK_ANSI_D: + return key.CodeD + case C.kVK_ANSI_E: + return key.CodeE + case C.kVK_ANSI_F: + return key.CodeF + case C.kVK_ANSI_G: + return key.CodeG + case C.kVK_ANSI_H: + return key.CodeH + case C.kVK_ANSI_I: + return key.CodeI + case C.kVK_ANSI_J: + return key.CodeJ + case C.kVK_ANSI_K: + return key.CodeK + case C.kVK_ANSI_L: + return key.CodeL + case C.kVK_ANSI_M: + return key.CodeM + case C.kVK_ANSI_N: + return key.CodeN + case C.kVK_ANSI_O: + return key.CodeO + case C.kVK_ANSI_P: + return key.CodeP + case C.kVK_ANSI_Q: + return key.CodeQ + case C.kVK_ANSI_R: + return key.CodeR + case C.kVK_ANSI_S: + return key.CodeS + case C.kVK_ANSI_T: + return key.CodeT + case C.kVK_ANSI_U: + return key.CodeU + case C.kVK_ANSI_V: + return key.CodeV + case C.kVK_ANSI_W: + return key.CodeW + case C.kVK_ANSI_X: + return key.CodeX + case C.kVK_ANSI_Y: + return key.CodeY + case C.kVK_ANSI_Z: + return key.CodeZ + case C.kVK_ANSI_1: + return key.Code1 + case C.kVK_ANSI_2: + return key.Code2 + case C.kVK_ANSI_3: + return key.Code3 + case C.kVK_ANSI_4: + return key.Code4 + case C.kVK_ANSI_5: + return key.Code5 + case C.kVK_ANSI_6: + return key.Code6 + case C.kVK_ANSI_7: + return key.Code7 + case C.kVK_ANSI_8: + return key.Code8 + case C.kVK_ANSI_9: + return key.Code9 + case C.kVK_ANSI_0: + return key.Code0 + // TODO: move the rest of these codes to constants in key.go + // if we are happy with them. + case C.kVK_Return: + return key.CodeReturnEnter + case C.kVK_Escape: + return key.CodeEscape + case C.kVK_Delete: + return key.CodeDeleteBackspace + case C.kVK_Tab: + return key.CodeTab + case C.kVK_Space: + return key.CodeSpacebar + case C.kVK_ANSI_Minus: + return key.CodeHyphenMinus + case C.kVK_ANSI_Equal: + return key.CodeEqualSign + case C.kVK_ANSI_LeftBracket: + return key.CodeLeftSquareBracket + case C.kVK_ANSI_RightBracket: + return key.CodeRightSquareBracket + case C.kVK_ANSI_Backslash: + return key.CodeBackslash + // 50: Keyboard Non-US "#" and ~ + case C.kVK_ANSI_Semicolon: + return key.CodeSemicolon + case C.kVK_ANSI_Quote: + return key.CodeApostrophe + case C.kVK_ANSI_Grave: + return key.CodeGraveAccent + case C.kVK_ANSI_Comma: + return key.CodeComma + case C.kVK_ANSI_Period: + return key.CodeFullStop + case C.kVK_ANSI_Slash: + return key.CodeSlash + case C.kVK_CapsLock: + return key.CodeCapsLock + case C.kVK_F1: + return key.CodeF1 + case C.kVK_F2: + return key.CodeF2 + case C.kVK_F3: + return key.CodeF3 + case C.kVK_F4: + return key.CodeF4 + case C.kVK_F5: + return key.CodeF5 + case C.kVK_F6: + return key.CodeF6 + case C.kVK_F7: + return key.CodeF7 + case C.kVK_F8: + return key.CodeF8 + case C.kVK_F9: + return key.CodeF9 + case C.kVK_F10: + return key.CodeF10 + case C.kVK_F11: + return key.CodeF11 + case C.kVK_F12: + return key.CodeF12 + // 70: PrintScreen + // 71: Scroll Lock + // 72: Pause + // 73: Insert + case C.kVK_Home: + return key.CodeHome + case C.kVK_PageUp: + return key.CodePageUp + case C.kVK_ForwardDelete: + return key.CodeDeleteForward + case C.kVK_End: + return key.CodeEnd + case C.kVK_PageDown: + return key.CodePageDown + case C.kVK_RightArrow: + return key.CodeRightArrow + case C.kVK_LeftArrow: + return key.CodeLeftArrow + case C.kVK_DownArrow: + return key.CodeDownArrow + case C.kVK_UpArrow: + return key.CodeUpArrow + case C.kVK_ANSI_KeypadClear: + return key.CodeKeypadNumLock + case C.kVK_ANSI_KeypadDivide: + return key.CodeKeypadSlash + case C.kVK_ANSI_KeypadMultiply: + return key.CodeKeypadAsterisk + case C.kVK_ANSI_KeypadMinus: + return key.CodeKeypadHyphenMinus + case C.kVK_ANSI_KeypadPlus: + return key.CodeKeypadPlusSign + case C.kVK_ANSI_KeypadEnter: + return key.CodeKeypadEnter + case C.kVK_ANSI_Keypad1: + return key.CodeKeypad1 + case C.kVK_ANSI_Keypad2: + return key.CodeKeypad2 + case C.kVK_ANSI_Keypad3: + return key.CodeKeypad3 + case C.kVK_ANSI_Keypad4: + return key.CodeKeypad4 + case C.kVK_ANSI_Keypad5: + return key.CodeKeypad5 + case C.kVK_ANSI_Keypad6: + return key.CodeKeypad6 + case C.kVK_ANSI_Keypad7: + return key.CodeKeypad7 + case C.kVK_ANSI_Keypad8: + return key.CodeKeypad8 + case C.kVK_ANSI_Keypad9: + return key.CodeKeypad9 + case C.kVK_ANSI_Keypad0: + return key.CodeKeypad0 + case C.kVK_ANSI_KeypadDecimal: + return key.CodeKeypadFullStop + case C.kVK_ANSI_KeypadEquals: + return key.CodeKeypadEqualSign + case C.kVK_F13: + return key.CodeF13 + case C.kVK_F14: + return key.CodeF14 + case C.kVK_F15: + return key.CodeF15 + case C.kVK_F16: + return key.CodeF16 + case C.kVK_F17: + return key.CodeF17 + case C.kVK_F18: + return key.CodeF18 + case C.kVK_F19: + return key.CodeF19 + case C.kVK_F20: + return key.CodeF20 + // 116: Keyboard Execute + case C.kVK_Help: + return key.CodeHelp + // 118: Keyboard Menu + // 119: Keyboard Select + // 120: Keyboard Stop + // 121: Keyboard Again + // 122: Keyboard Undo + // 123: Keyboard Cut + // 124: Keyboard Copy + // 125: Keyboard Paste + // 126: Keyboard Find + case C.kVK_Mute: + return key.CodeMute + case C.kVK_VolumeUp: + return key.CodeVolumeUp + case C.kVK_VolumeDown: + return key.CodeVolumeDown + // 130: Keyboard Locking Caps Lock + // 131: Keyboard Locking Num Lock + // 132: Keyboard Locking Scroll Lock + // 133: Keyboard Comma + // 134: Keyboard Equal Sign + // ...: Bunch of stuff + case C.kVK_Control: + return key.CodeLeftControl + case C.kVK_Shift: + return key.CodeLeftShift + case C.kVK_Option: + return key.CodeLeftAlt + case C.kVK_Command: + return key.CodeLeftGUI + case C.kVK_RightControl: + return key.CodeRightControl + case C.kVK_RightShift: + return key.CodeRightShift + case C.kVK_RightOption: + return key.CodeRightAlt + // TODO key.CodeRightGUI + default: + return key.CodeUnknown + } +} diff --git a/app/darwin_desktop.m b/app/darwin_desktop.m new file mode 100644 index 000000000..071124f6e --- /dev/null +++ b/app/darwin_desktop.m @@ -0,0 +1,251 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && !ios +// +build darwin +// +build !ios + +#include "_cgo_export.h" +#include +#include + +#import +#import +#import + +void makeCurrentContext(GLintptr context) { + NSOpenGLContext* ctx = (NSOpenGLContext*)context; + [ctx makeCurrentContext]; +} + +uint64 threadID() { + uint64 id; + if (pthread_threadid_np(pthread_self(), &id)) { + abort(); + } + return id; +} + +@interface MobileGLView : NSOpenGLView +{ +} +@end + +@implementation MobileGLView +- (void)prepareOpenGL { + [super prepareOpenGL]; + [self setWantsBestResolutionOpenGLSurface:YES]; + GLint swapInt = 1; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; +#pragma clang diagnostic pop + + // Using attribute arrays in OpenGL 3.3 requires the use of a VBA. + // But VBAs don't exist in ES 2. So we bind a default one. + GLuint vba; + glGenVertexArrays(1, &vba); + glBindVertexArray(vba); + + startloop((GLintptr)[self openGLContext]); +} + +- (void)reshape { + [super reshape]; + + // Calculate screen PPI. + // + // Note that the backingScaleFactor converts from logical + // pixels to actual pixels, but both of these units vary + // independently from real world size. E.g. + // + // 13" Retina Macbook Pro, 2560x1600, 227ppi, backingScaleFactor=2, scale=3.15 + // 15" Retina Macbook Pro, 2880x1800, 220ppi, backingScaleFactor=2, scale=3.06 + // 27" iMac, 2560x1440, 109ppi, backingScaleFactor=1, scale=1.51 + // 27" Retina iMac, 5120x2880, 218ppi, backingScaleFactor=2, scale=3.03 + NSScreen *screen = [NSScreen mainScreen]; + double screenPixW = [screen frame].size.width * [screen backingScaleFactor]; + + CGDirectDisplayID display = (CGDirectDisplayID)[[[screen deviceDescription] valueForKey:@"NSScreenNumber"] intValue]; + CGSize screenSizeMM = CGDisplayScreenSize(display); // in millimeters + float ppi = 25.4 * screenPixW / screenSizeMM.width; + float pixelsPerPt = ppi/72.0; + + // The width and height reported to the geom package are the + // bounds of the OpenGL view. Several steps are necessary. + // First, [self bounds] gives us the number of logical pixels + // in the view. Multiplying this by the backingScaleFactor + // gives us the number of actual pixels. + NSRect r = [self bounds]; + int w = r.size.width * [screen backingScaleFactor]; + int h = r.size.height * [screen backingScaleFactor]; + + setGeom(pixelsPerPt, w, h); +} + +- (void)drawRect:(NSRect)theRect { + // Called during resize. This gets rid of flicker when resizing. + drawgl(); +} + +- (void)mouseDown:(NSEvent *)theEvent { + double scale = [[NSScreen mainScreen] backingScaleFactor]; + NSPoint p = [theEvent locationInWindow]; + eventMouseDown(p.x * scale, p.y * scale); +} + +- (void)mouseUp:(NSEvent *)theEvent { + double scale = [[NSScreen mainScreen] backingScaleFactor]; + NSPoint p = [theEvent locationInWindow]; + eventMouseEnd(p.x * scale, p.y * scale); +} + +- (void)mouseDragged:(NSEvent *)theEvent { + double scale = [[NSScreen mainScreen] backingScaleFactor]; + NSPoint p = [theEvent locationInWindow]; + eventMouseDragged(p.x * scale, p.y * scale); +} + +- (void)windowDidBecomeKey:(NSNotification *)notification { + lifecycleFocused(); +} + +- (void)windowDidResignKey:(NSNotification *)notification { + if (![NSApp isHidden]) { + lifecycleVisible(); + } +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + lifecycleAlive(); + [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; + [self.window makeKeyAndOrderFront:self]; + lifecycleVisible(); +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + lifecycleDead(); +} + +- (void)applicationDidHide:(NSNotification *)aNotification { + lifecycleAlive(); +} + +- (void)applicationWillUnhide:(NSNotification *)notification { + lifecycleVisible(); +} + +- (void)windowWillClose:(NSNotification *)notification { + lifecycleAlive(); +} +@end + +@interface MobileResponder : NSResponder +{ +} +@end + +@implementation MobileResponder +- (void)keyDown:(NSEvent *)theEvent { + [self key:theEvent]; +} +- (void)keyUp:(NSEvent *)theEvent { + [self key:theEvent]; +} +- (void)key:(NSEvent *)theEvent { + NSRange range = [theEvent.characters rangeOfComposedCharacterSequenceAtIndex:0]; + + uint8_t buf[4] = {0, 0, 0, 0}; + if (![theEvent.characters getBytes:buf + maxLength:4 + usedLength:nil + encoding:NSUTF32LittleEndianStringEncoding + options:NSStringEncodingConversionAllowLossy + range:range + remainingRange:nil]) { + NSLog(@"failed to read key event %@", theEvent); + return; + } + + uint32_t rune = (uint32_t)buf[0]<<0 | (uint32_t)buf[1]<<8 | (uint32_t)buf[2]<<16 | (uint32_t)buf[3]<<24; + + uint8_t direction; + if ([theEvent isARepeat]) { + direction = 0; + } else if (theEvent.type == NSEventTypeKeyDown) { + direction = 1; + } else { + direction = 2; + } + eventKey((int32_t)rune, direction, theEvent.keyCode, theEvent.modifierFlags); +} + +- (void)flagsChanged:(NSEvent *)theEvent { + eventFlags(theEvent.modifierFlags); +} +@end + +void +runApp(void) { + [NSAutoreleasePool new]; + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + id menuBar = [[NSMenu new] autorelease]; + id menuItem = [[NSMenuItem new] autorelease]; + [menuBar addItem:menuItem]; + [NSApp setMainMenu:menuBar]; + + id menu = [[NSMenu new] autorelease]; + id name = [[NSProcessInfo processInfo] processName]; + + id hideMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Hide" + action:@selector(hide:) keyEquivalent:@"h"] + autorelease]; + [menu addItem:hideMenuItem]; + + id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Quit" + action:@selector(terminate:) keyEquivalent:@"q"] + autorelease]; + [menu addItem:quitMenuItem]; + [menuItem setSubmenu:menu]; + + NSRect rect = NSMakeRect(0, 0, 600, 800); + + NSWindow* window = [[[NSWindow alloc] initWithContentRect:rect + styleMask:NSWindowStyleMaskTitled + backing:NSBackingStoreBuffered + defer:NO] + autorelease]; + window.styleMask |= NSWindowStyleMaskResizable; + window.styleMask |= NSWindowStyleMaskMiniaturizable; + window.styleMask |= NSWindowStyleMaskClosable; + window.title = name; + [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; + + NSOpenGLPixelFormatAttribute attr[] = { + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 16, + NSOpenGLPFAAccelerated, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAAllowOfflineRenderers, + 0 + }; + id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; + MobileGLView* view = [[MobileGLView alloc] initWithFrame:rect pixelFormat:pixFormat]; + [window setContentView:view]; + [window setDelegate:view]; + [NSApp setDelegate:view]; + + window.nextResponder = [[[MobileResponder alloc] init] autorelease]; + + [NSApp run]; +} + +void stopApp(void) { + [NSApp terminate:nil]; +} diff --git a/app/darwin_ios.go b/app/darwin_ios.go new file mode 100644 index 000000000..8fb30fe82 --- /dev/null +++ b/app/darwin_ios.go @@ -0,0 +1,216 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && ios +// +build darwin,ios + +package app + +/* +#cgo CFLAGS: -x objective-c -DGL_SILENCE_DEPRECATION -DGLES_SILENCE_DEPRECATION +#cgo LDFLAGS: -framework Foundation -framework UIKit -framework GLKit -framework OpenGLES -framework QuartzCore +#include +#include +#include +#include +#import + +extern struct utsname sysInfo; + +void runApp(void); +void makeCurrentContext(GLintptr ctx); +void swapBuffers(GLintptr ctx); +uint64_t threadID(); +*/ +import "C" +import ( + "log" + "runtime" + "strings" + "sync" + + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/paint" + "golang.org/x/mobile/event/size" + "golang.org/x/mobile/event/touch" + "golang.org/x/mobile/geom" +) + +var initThreadID uint64 + +func init() { + // Lock the goroutine responsible for initialization to an OS thread. + // This means the goroutine running main (and calling the run function + // below) is locked to the OS thread that started the program. This is + // necessary for the correct delivery of UIKit events to the process. + // + // A discussion on this topic: + // https://groups.google.com/forum/#!msg/golang-nuts/IiWZ2hUuLDA/SNKYYZBelsYJ + runtime.LockOSThread() + initThreadID = uint64(C.threadID()) +} + +func main(f func(App)) { + if tid := uint64(C.threadID()); tid != initThreadID { + log.Fatalf("app.Run called on thread %d, but app.init ran on %d", tid, initThreadID) + } + + go func() { + f(theApp) + // TODO(crawshaw): trigger runApp to return + }() + C.runApp() + panic("unexpected return from app.runApp") +} + +var pixelsPerPt float32 +var screenScale int // [UIScreen mainScreen].scale, either 1, 2, or 3. + +//export setScreen +func setScreen(scale int) { + C.uname(&C.sysInfo) + name := C.GoString(&C.sysInfo.machine[0]) + + var v float32 + + switch { + case strings.HasPrefix(name, "iPhone"): + v = 163 + case strings.HasPrefix(name, "iPad"): + // TODO: is there a better way to distinguish the iPad Mini? + switch name { + case "iPad2,5", "iPad2,6", "iPad2,7", "iPad4,4", "iPad4,5", "iPad4,6", "iPad4,7": + v = 163 // iPad Mini + default: + v = 132 + } + default: + v = 163 // names like i386 and x86_64 are the simulator + } + + if v == 0 { + log.Printf("unknown machine: %s", name) + v = 163 // emergency fallback + } + + pixelsPerPt = v * float32(scale) / 72 + screenScale = scale +} + +//export updateConfig +func updateConfig(width, height, orientation int32) { + o := size.OrientationUnknown + switch orientation { + case C.UIDeviceOrientationPortrait, C.UIDeviceOrientationPortraitUpsideDown: + o = size.OrientationPortrait + case C.UIDeviceOrientationLandscapeLeft, C.UIDeviceOrientationLandscapeRight: + o = size.OrientationLandscape + } + widthPx := screenScale * int(width) + heightPx := screenScale * int(height) + theApp.eventsIn <- size.Event{ + WidthPx: widthPx, + HeightPx: heightPx, + WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt), + HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt), + PixelsPerPt: pixelsPerPt, + Orientation: o, + } + theApp.eventsIn <- paint.Event{External: true} +} + +// touchIDs is the current active touches. The position in the array +// is the ID, the value is the UITouch* pointer value. +// +// It is widely reported that the iPhone can handle up to 5 simultaneous +// touch events, while the iPad can handle 11. +var touchIDs [11]uintptr + +var touchEvents struct { + sync.Mutex + pending []touch.Event +} + +//export sendTouch +func sendTouch(cTouch, cTouchType uintptr, x, y float32) { + id := -1 + for i, val := range touchIDs { + if val == cTouch { + id = i + break + } + } + if id == -1 { + for i, val := range touchIDs { + if val == 0 { + touchIDs[i] = cTouch + id = i + break + } + } + if id == -1 { + panic("out of touchIDs") + } + } + + t := touch.Type(cTouchType) + if t == touch.TypeEnd { + touchIDs[id] = 0 + } + + theApp.eventsIn <- touch.Event{ + X: x, + Y: y, + Sequence: touch.Sequence(id), + Type: t, + } +} + +//export lifecycleDead +func lifecycleDead() { theApp.sendLifecycle(lifecycle.StageDead) } + +//export lifecycleAlive +func lifecycleAlive() { theApp.sendLifecycle(lifecycle.StageAlive) } + +//export lifecycleVisible +func lifecycleVisible() { theApp.sendLifecycle(lifecycle.StageVisible) } + +//export lifecycleFocused +func lifecycleFocused() { theApp.sendLifecycle(lifecycle.StageFocused) } + +//export startloop +func startloop(ctx C.GLintptr) { + go theApp.loop(ctx) +} + +// loop is the primary drawing loop. +// +// After UIKit has captured the initial OS thread for processing UIKit +// events in runApp, it starts loop on another goroutine. It is locked +// to an OS thread for its OpenGL context. +func (a *app) loop(ctx C.GLintptr) { + runtime.LockOSThread() + C.makeCurrentContext(ctx) + + workAvailable := a.worker.WorkAvailable() + + for { + select { + case <-workAvailable: + a.worker.DoWork() + case <-theApp.publish: + loop1: + for { + select { + case <-workAvailable: + a.worker.DoWork() + default: + break loop1 + } + } + C.swapBuffers(ctx) + theApp.publishResult <- PublishResult{} + } + } +} diff --git a/app/darwin_ios.m b/app/darwin_ios.m new file mode 100644 index 000000000..21d73a5dc --- /dev/null +++ b/app/darwin_ios.m @@ -0,0 +1,167 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && ios +// +build darwin +// +build ios + +#include "_cgo_export.h" +#include +#include +#include + +#import +#import + +struct utsname sysInfo; + +@interface GoAppAppController : GLKViewController +@end + +@interface GoAppAppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@property (strong, nonatomic) GoAppAppController *controller; +@end + +@implementation GoAppAppDelegate +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + lifecycleAlive(); + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.controller = [[GoAppAppController alloc] initWithNibName:nil bundle:nil]; + self.window.rootViewController = self.controller; + [self.window makeKeyAndVisible]; + return YES; +} + +- (void)applicationDidBecomeActive:(UIApplication * )application { + lifecycleFocused(); +} + +- (void)applicationWillResignActive:(UIApplication *)application { + lifecycleVisible(); +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + lifecycleAlive(); +} + +- (void)applicationWillTerminate:(UIApplication *)application { + lifecycleDead(); +} +@end + +@interface GoAppAppController () +@property (strong, nonatomic) EAGLContext *context; +@property (strong, nonatomic) GLKView *glview; +@end + +@implementation GoAppAppController +- (void)viewWillAppear:(BOOL)animated +{ + // TODO: replace by swapping out GLKViewController for a UIVIewController. + [super viewWillAppear:animated]; + self.paused = YES; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + self.glview = (GLKView*)self.view; + self.glview.drawableDepthFormat = GLKViewDrawableDepthFormat24; + self.glview.multipleTouchEnabled = true; // TODO expose setting to user. + self.glview.context = self.context; + self.glview.userInteractionEnabled = YES; + self.glview.enableSetNeedsDisplay = YES; // only invoked once + + // Do not use the GLKViewController draw loop. + self.paused = YES; + self.resumeOnDidBecomeActive = NO; + self.preferredFramesPerSecond = 0; + + int scale = 1; + if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)]) { + scale = (int)[UIScreen mainScreen].scale; // either 1.0, 2.0, or 3.0. + } + setScreen(scale); + + CGSize size = [UIScreen mainScreen].bounds.size; + UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + updateConfig((int)size.width, (int)size.height, orientation); +} + +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + [coordinator animateAlongsideTransition:^(id context) { + // TODO(crawshaw): come up with a plan to handle animations. + } completion:^(id context) { + UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + updateConfig((int)size.width, (int)size.height, orientation); + }]; +} + +- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { + // Now that we have been asked to do the first draw, disable any + // future draw and hand control over to the Go paint.Event cycle. + self.glview.enableSetNeedsDisplay = NO; + startloop((GLintptr)self.context); +} + +#define TOUCH_TYPE_BEGIN 0 // touch.TypeBegin +#define TOUCH_TYPE_MOVE 1 // touch.TypeMove +#define TOUCH_TYPE_END 2 // touch.TypeEnd + +static void sendTouches(int change, NSSet* touches) { + CGFloat scale = [UIScreen mainScreen].scale; + for (UITouch* touch in touches) { + CGPoint p = [touch locationInView:touch.view]; + sendTouch((GoUintptr)touch, (GoUintptr)change, p.x*scale, p.y*scale); + } +} + +- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { + sendTouches(TOUCH_TYPE_BEGIN, touches); +} + +- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { + sendTouches(TOUCH_TYPE_MOVE, touches); +} + +- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { + sendTouches(TOUCH_TYPE_END, touches); +} + +- (void)touchesCanceled:(NSSet*)touches withEvent:(UIEvent*)event { + sendTouches(TOUCH_TYPE_END, touches); +} +@end + +void runApp(void) { + char* argv[] = {}; + @autoreleasepool { + UIApplicationMain(0, argv, nil, NSStringFromClass([GoAppAppDelegate class])); + } +} + +void makeCurrentContext(GLintptr context) { + EAGLContext* ctx = (EAGLContext*)context; + if (![EAGLContext setCurrentContext:ctx]) { + // TODO(crawshaw): determine how terrible this is. Exit? + NSLog(@"failed to set current context"); + } +} + +void swapBuffers(GLintptr context) { + __block EAGLContext* ctx = (EAGLContext*)context; + dispatch_sync(dispatch_get_main_queue(), ^{ + [EAGLContext setCurrentContext:ctx]; + [ctx presentRenderbuffer:GL_RENDERBUFFER]; + }); +} + +uint64_t threadID() { + uint64_t id; + if (pthread_threadid_np(pthread_self(), &id)) { + abort(); + } + return id; +} diff --git a/app/doc.go b/app/doc.go new file mode 100644 index 000000000..02bd6db80 --- /dev/null +++ b/app/doc.go @@ -0,0 +1,88 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package app lets you write portable all-Go apps for Android and iOS. + +There are typically two ways to use Go on Android and iOS. The first +is to write a Go library and use `gomobile bind` to generate language +bindings for Java and Objective-C. Building a library does not +require the app package. The `gomobile bind` command produces output +that you can include in an Android Studio or Xcode project. For more +on language bindings, see https://golang.org/x/mobile/cmd/gobind. + +The second way is to write an app entirely in Go. The APIs are limited +to those that are portable between both Android and iOS, in particular +OpenGL, audio, and other Android NDK-like APIs. An all-Go app should +use this app package to initialize the app, manage its lifecycle, and +receive events. + +# Building apps + +Apps written entirely in Go have a main function, and can be built +with `gomobile build`, which directly produces runnable output for +Android and iOS. + +The gomobile tool can get installed with go get. For reference, see +https://golang.org/x/mobile/cmd/gomobile. + +For detailed instructions and documentation, see +https://golang.org/wiki/Mobile. + +# Event processing in Native Apps + +The Go runtime is initialized on Android when NativeActivity onCreate is +called, and on iOS when the process starts. In both cases, Go init functions +run before the app lifecycle has started. + +An app is expected to call the Main function in main.main. When the function +exits, the app exits. Inside the func passed to Main, call Filter on every +event received, and then switch on its type. Registered filters run when the +event is received, not when it is sent, so that filters run in the same +goroutine as other code that calls OpenGL. + + package main + + import ( + "log" + + "golang.org/x/mobile/app" + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/paint" + ) + + func main() { + app.Main(func(a app.App) { + for e := range a.Events() { + switch e := a.Filter(e).(type) { + case lifecycle.Event: + // ... + case paint.Event: + log.Print("Call OpenGL here.") + a.Publish() + } + } + }) + } + +An event is represented by the empty interface type interface{}. Any value can +be an event. Commonly used types include Event types defined by the following +packages: + - golang.org/x/mobile/event/lifecycle + - golang.org/x/mobile/event/mouse + - golang.org/x/mobile/event/paint + - golang.org/x/mobile/event/size + - golang.org/x/mobile/event/touch + +For example, touch.Event is the type that represents touch events. Other +packages may define their own events, and send them on an app's event channel. + +Other packages can also register event filters, e.g. to manage resources in +response to lifecycle events. Such packages should call: + + app.RegisterFilter(etc) + +in an init function inside that package. +*/ +package app // import "golang.org/x/mobile/app" diff --git a/app/internal/apptest/apptest.go b/app/internal/apptest/apptest.go new file mode 100644 index 000000000..480677367 --- /dev/null +++ b/app/internal/apptest/apptest.go @@ -0,0 +1,67 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package apptest provides utilities for testing an app. +// +// It is extremely incomplete, hence it being internal. +// For starters, it should support iOS. +package apptest + +import ( + "bufio" + "bytes" + "fmt" + "net" +) + +// Port is the TCP port used to communicate with the test app. +// +// TODO(crawshaw): find a way to make this configurable. adb am extras? +const Port = "12533" + +// Comm is a simple text-based communication protocol. +// +// Assumes all sides are friendly and cooperative and that the +// communication is over at the first sign of trouble. +type Comm struct { + Conn net.Conn + Fatalf func(format string, args ...interface{}) + Printf func(format string, args ...interface{}) + + scanner *bufio.Scanner +} + +func (c *Comm) Send(cmd string, args ...interface{}) { + buf := new(bytes.Buffer) + buf.WriteString(cmd) + for _, arg := range args { + buf.WriteRune(' ') + fmt.Fprintf(buf, "%v", arg) + } + buf.WriteRune('\n') + b := buf.Bytes() + c.Printf("comm.send: %s\n", b) + if _, err := c.Conn.Write(b); err != nil { + c.Fatalf("failed to send %s: %v", b, err) + } +} + +func (c *Comm) Recv(cmd string, a ...interface{}) { + if c.scanner == nil { + c.scanner = bufio.NewScanner(c.Conn) + } + if !c.scanner.Scan() { + c.Fatalf("failed to recv %q: %v", cmd, c.scanner.Err()) + } + text := c.scanner.Text() + c.Printf("comm.recv: %s\n", text) + var recvCmd string + args := append([]interface{}{&recvCmd}, a...) + if _, err := fmt.Sscan(text, args...); err != nil { + c.Fatalf("cannot scan recv command %s: %q: %v", cmd, text, err) + } + if cmd != recvCmd { + c.Fatalf("expecting recv %q, got %v", cmd, text) + } +} diff --git a/app/internal/callfn/callfn.go b/app/internal/callfn/callfn.go new file mode 100644 index 000000000..7a3d0506e --- /dev/null +++ b/app/internal/callfn/callfn.go @@ -0,0 +1,18 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build android && (arm || 386 || amd64 || arm64) +// +build android +// +build arm 386 amd64 arm64 + +// Package callfn provides an android entry point. +// +// It is a separate package from app because it contains Go assembly, +// which does not compile in a package using cgo. +package callfn + +// CallFn calls a zero-argument function by its program counter. +// It is only intended for calling main.main. Using it for +// anything else will not end well. +func CallFn(fn uintptr) diff --git a/app/internal/callfn/callfn_386.s b/app/internal/callfn/callfn_386.s new file mode 100644 index 000000000..d2bb54f1e --- /dev/null +++ b/app/internal/callfn/callfn_386.s @@ -0,0 +1,11 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" +#include "funcdata.h" + +TEXT ·CallFn(SB),$0-4 + MOVL fn+0(FP), AX + CALL AX + RET diff --git a/app/internal/callfn/callfn_amd64.s b/app/internal/callfn/callfn_amd64.s new file mode 100644 index 000000000..8769604ab --- /dev/null +++ b/app/internal/callfn/callfn_amd64.s @@ -0,0 +1,11 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" +#include "funcdata.h" + +TEXT ·CallFn(SB),$0-8 + MOVQ fn+0(FP), AX + CALL AX + RET diff --git a/app/internal/callfn/callfn_arm.s b/app/internal/callfn/callfn_arm.s new file mode 100644 index 000000000..d71f748d9 --- /dev/null +++ b/app/internal/callfn/callfn_arm.s @@ -0,0 +1,11 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" +#include "funcdata.h" + +TEXT ·CallFn(SB),$0-4 + MOVW fn+0(FP), R0 + BL (R0) + RET diff --git a/app/internal/callfn/callfn_arm64.s b/app/internal/callfn/callfn_arm64.s new file mode 100644 index 000000000..545ad5007 --- /dev/null +++ b/app/internal/callfn/callfn_arm64.s @@ -0,0 +1,11 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" +#include "funcdata.h" + +TEXT ·CallFn(SB),$0-8 + MOVD fn+0(FP), R0 + BL (R0) + RET diff --git a/app/internal/testapp/AndroidManifest.xml b/app/internal/testapp/AndroidManifest.xml new file mode 100644 index 000000000..824d88073 --- /dev/null +++ b/app/internal/testapp/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + diff --git a/app/internal/testapp/testapp.go b/app/internal/testapp/testapp.go new file mode 100644 index 000000000..eb850955b --- /dev/null +++ b/app/internal/testapp/testapp.go @@ -0,0 +1,95 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || linux +// +build darwin linux + +// Small test app used by app/app_test.go. +package main + +import ( + "log" + "net" + + "golang.org/x/mobile/app" + "golang.org/x/mobile/app/internal/apptest" + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/paint" + "golang.org/x/mobile/event/size" + "golang.org/x/mobile/event/touch" + "golang.org/x/mobile/gl" +) + +func main() { + app.Main(func(a app.App) { + var ( + glctx gl.Context + visible bool + ) + + addr := "127.0.0.1:" + apptest.Port + log.Printf("addr: %s", addr) + + conn, err := net.Dial("tcp", addr) + if err != nil { + log.Fatal(err) + } + defer conn.Close() + log.Printf("dialled") + comm := &apptest.Comm{ + Conn: conn, + Fatalf: log.Panicf, + Printf: log.Printf, + } + + comm.Send("hello_from_testapp") + comm.Recv("hello_from_host") + + color := "red" + sendPainting := false + for e := range a.Events() { + switch e := a.Filter(e).(type) { + case lifecycle.Event: + switch e.Crosses(lifecycle.StageVisible) { + case lifecycle.CrossOn: + comm.Send("lifecycle_visible") + sendPainting = true + visible = true + glctx, _ = e.DrawContext.(gl.Context) + case lifecycle.CrossOff: + comm.Send("lifecycle_not_visible") + visible = false + } + case size.Event: + comm.Send("size", e.PixelsPerPt, e.Orientation) + case paint.Event: + if visible { + if color == "red" { + glctx.ClearColor(1, 0, 0, 1) + } else { + glctx.ClearColor(0, 1, 0, 1) + } + glctx.Clear(gl.COLOR_BUFFER_BIT) + a.Publish() + } + if sendPainting { + comm.Send("paint", color) + sendPainting = false + } + case touch.Event: + comm.Send("touch", e.Type, e.X, e.Y) + if e.Type == touch.TypeEnd { + if color == "red" { + color = "green" + } else { + color = "red" + } + sendPainting = true + // Send a paint event so the screen gets redrawn. + a.Send(paint.Event{}) + } + } + } + }) +} diff --git a/app/shiny.go b/app/shiny.go new file mode 100644 index 000000000..dd1722a27 --- /dev/null +++ b/app/shiny.go @@ -0,0 +1,84 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build windows +// +build windows + +package app + +import ( + "log" + + "golang.org/x/exp/shiny/driver/gldriver" + "golang.org/x/exp/shiny/screen" + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/mouse" + "golang.org/x/mobile/event/touch" + "golang.org/x/mobile/gl" +) + +func main(f func(a App)) { + gldriver.Main(func(s screen.Screen) { + w, err := s.NewWindow(nil) + if err != nil { + log.Fatal(err) + } + defer w.Release() + + theApp.glctx = nil + theApp.worker = nil // handled by shiny + + go func() { + for range theApp.publish { + res := w.Publish() + theApp.publishResult <- PublishResult{ + BackBufferPreserved: res.BackBufferPreserved, + } + } + }() + + donec := make(chan struct{}) + go func() { + // close the donec channel in a defer statement + // so that we could still be able to return even + // if f panics. + defer close(donec) + + f(theApp) + }() + + for { + select { + case <-donec: + return + default: + theApp.Send(convertEvent(w.NextEvent())) + } + } + }) +} + +func convertEvent(e interface{}) interface{} { + switch e := e.(type) { + case lifecycle.Event: + if theApp.glctx == nil { + theApp.glctx = e.DrawContext.(gl.Context) + } + case mouse.Event: + te := touch.Event{ + X: e.X, + Y: e.Y, + } + switch e.Direction { + case mouse.DirNone: + te.Type = touch.TypeMove + case mouse.DirPress: + te.Type = touch.TypeBegin + case mouse.DirRelease: + te.Type = touch.TypeEnd + } + return te + } + return e +} diff --git a/app/x11.c b/app/x11.c new file mode 100644 index 000000000..755bb2448 --- /dev/null +++ b/app/x11.c @@ -0,0 +1,175 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && !android +// +build linux,!android + +#include "_cgo_export.h" +#include +#include +#include +#include +#include +#include + +static Atom wm_delete_window; + +static Window +new_window(Display *x_dpy, EGLDisplay e_dpy, int w, int h, EGLContext *ctx, EGLSurface *surf) { + static const EGLint attribs[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_DEPTH_SIZE, 16, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_NONE + }; + EGLConfig config; + EGLint num_configs; + if (!eglChooseConfig(e_dpy, attribs, &config, 1, &num_configs)) { + fprintf(stderr, "eglChooseConfig failed\n"); + exit(1); + } + EGLint vid; + if (!eglGetConfigAttrib(e_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { + fprintf(stderr, "eglGetConfigAttrib failed\n"); + exit(1); + } + + XVisualInfo visTemplate; + visTemplate.visualid = vid; + int num_visuals; + XVisualInfo *visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals); + if (!visInfo) { + fprintf(stderr, "XGetVisualInfo failed\n"); + exit(1); + } + + Window root = RootWindow(x_dpy, DefaultScreen(x_dpy)); + XSetWindowAttributes attr; + + attr.colormap = XCreateColormap(x_dpy, root, visInfo->visual, AllocNone); + if (!attr.colormap) { + fprintf(stderr, "XCreateColormap failed\n"); + exit(1); + } + + attr.event_mask = StructureNotifyMask | ExposureMask | + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; + Window win = XCreateWindow( + x_dpy, root, 0, 0, w, h, 0, visInfo->depth, InputOutput, + visInfo->visual, CWColormap | CWEventMask, &attr); + XFree(visInfo); + + XSizeHints sizehints; + sizehints.width = w; + sizehints.height = h; + sizehints.flags = USSize; + XSetNormalHints(x_dpy, win, &sizehints); + XSetStandardProperties(x_dpy, win, "App", "App", None, (char **)NULL, 0, &sizehints); + + static const EGLint ctx_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + *ctx = eglCreateContext(e_dpy, config, EGL_NO_CONTEXT, ctx_attribs); + if (!*ctx) { + fprintf(stderr, "eglCreateContext failed\n"); + exit(1); + } + *surf = eglCreateWindowSurface(e_dpy, config, win, NULL); + if (!*surf) { + fprintf(stderr, "eglCreateWindowSurface failed\n"); + exit(1); + } + return win; +} + +Display *x_dpy; +EGLDisplay e_dpy; +EGLContext e_ctx; +EGLSurface e_surf; +Window win; + +void +createWindow(void) { + x_dpy = XOpenDisplay(NULL); + if (!x_dpy) { + fprintf(stderr, "XOpenDisplay failed\n"); + exit(1); + } + e_dpy = eglGetDisplay(x_dpy); + if (!e_dpy) { + fprintf(stderr, "eglGetDisplay failed\n"); + exit(1); + } + EGLint e_major, e_minor; + if (!eglInitialize(e_dpy, &e_major, &e_minor)) { + fprintf(stderr, "eglInitialize failed\n"); + exit(1); + } + eglBindAPI(EGL_OPENGL_ES_API); + win = new_window(x_dpy, e_dpy, 600, 800, &e_ctx, &e_surf); + + wm_delete_window = XInternAtom(x_dpy, "WM_DELETE_WINDOW", True); + if (wm_delete_window != None) { + XSetWMProtocols(x_dpy, win, &wm_delete_window, 1); + } + + XMapWindow(x_dpy, win); + if (!eglMakeCurrent(e_dpy, e_surf, e_surf, e_ctx)) { + fprintf(stderr, "eglMakeCurrent failed\n"); + exit(1); + } + + // Window size and DPI should be initialized before starting app. + XEvent ev; + while (1) { + if (XCheckMaskEvent(x_dpy, StructureNotifyMask, &ev) == False) { + continue; + } + if (ev.type == ConfigureNotify) { + onResize(ev.xconfigure.width, ev.xconfigure.height); + break; + } + } +} + +void +processEvents(void) { + while (XPending(x_dpy)) { + XEvent ev; + XNextEvent(x_dpy, &ev); + switch (ev.type) { + case ButtonPress: + onTouchBegin((float)ev.xbutton.x, (float)ev.xbutton.y); + break; + case ButtonRelease: + onTouchEnd((float)ev.xbutton.x, (float)ev.xbutton.y); + break; + case MotionNotify: + onTouchMove((float)ev.xmotion.x, (float)ev.xmotion.y); + break; + case ConfigureNotify: + onResize(ev.xconfigure.width, ev.xconfigure.height); + break; + case ClientMessage: + if (wm_delete_window != None && (Atom)ev.xclient.data.l[0] == wm_delete_window) { + onStop(); + return; + } + break; + } + } +} + +void +swapBuffers(void) { + if (eglSwapBuffers(e_dpy, e_surf) == EGL_FALSE) { + fprintf(stderr, "eglSwapBuffer failed\n"); + exit(1); + } +} diff --git a/app/x11.go b/app/x11.go new file mode 100644 index 000000000..ec8c90a54 --- /dev/null +++ b/app/x11.go @@ -0,0 +1,127 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && !android +// +build linux,!android + +package app + +/* +Simple on-screen app debugging for X11. Not an officially supported +development target for apps, as screens with mice are very different +than screens with touch panels. +*/ + +/* +#cgo LDFLAGS: -lEGL -lGLESv2 -lX11 + +void createWindow(void); +void processEvents(void); +void swapBuffers(void); +*/ +import "C" +import ( + "runtime" + "time" + + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/paint" + "golang.org/x/mobile/event/size" + "golang.org/x/mobile/event/touch" + "golang.org/x/mobile/geom" +) + +func init() { + theApp.registerGLViewportFilter() +} + +func main(f func(App)) { + runtime.LockOSThread() + + workAvailable := theApp.worker.WorkAvailable() + + C.createWindow() + + // TODO: send lifecycle events when e.g. the X11 window is iconified or moved off-screen. + theApp.sendLifecycle(lifecycle.StageFocused) + + // TODO: translate X11 expose events to shiny paint events, instead of + // sending this synthetic paint event as a hack. + theApp.eventsIn <- paint.Event{} + + donec := make(chan struct{}) + go func() { + // close the donec channel in a defer statement + // so that we could still be able to return even + // if f panics. + defer close(donec) + + f(theApp) + }() + + // TODO: can we get the actual vsync signal? + ticker := time.NewTicker(time.Second / 60) + defer ticker.Stop() + var tc <-chan time.Time + + for { + select { + case <-donec: + return + case <-workAvailable: + theApp.worker.DoWork() + case <-theApp.publish: + C.swapBuffers() + tc = ticker.C + case <-tc: + tc = nil + theApp.publishResult <- PublishResult{} + } + C.processEvents() + } +} + +//export onResize +func onResize(w, h int) { + // TODO(nigeltao): don't assume 72 DPI. DisplayWidth and DisplayWidthMM + // is probably the best place to start looking. + pixelsPerPt := float32(1) + theApp.eventsIn <- size.Event{ + WidthPx: w, + HeightPx: h, + WidthPt: geom.Pt(w), + HeightPt: geom.Pt(h), + PixelsPerPt: pixelsPerPt, + } +} + +func sendTouch(t touch.Type, x, y float32) { + theApp.eventsIn <- touch.Event{ + X: x, + Y: y, + Sequence: 0, // TODO: button?? + Type: t, + } +} + +//export onTouchBegin +func onTouchBegin(x, y float32) { sendTouch(touch.TypeBegin, x, y) } + +//export onTouchMove +func onTouchMove(x, y float32) { sendTouch(touch.TypeMove, x, y) } + +//export onTouchEnd +func onTouchEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) } + +var stopped bool + +//export onStop +func onStop() { + if stopped { + return + } + stopped = true + theApp.sendLifecycle(lifecycle.StageDead) + theApp.eventsIn <- stopPumping{} +} diff --git a/asset/asset.go b/asset/asset.go new file mode 100644 index 000000000..5ed3a5c5a --- /dev/null +++ b/asset/asset.go @@ -0,0 +1,25 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || linux || windows +// +build darwin linux windows + +package asset + +import "io" + +// Open opens a named asset. +// +// Errors are of type *os.PathError. +// +// This must not be called from init when used in android apps. +func Open(name string) (File, error) { + return openAsset(name) +} + +// File is an open asset. +type File interface { + io.ReadSeeker + io.Closer +} diff --git a/asset/asset_android.go b/asset/asset_android.go new file mode 100644 index 000000000..0aad2566c --- /dev/null +++ b/asset/asset_android.go @@ -0,0 +1,109 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package asset + +/* +#cgo LDFLAGS: -landroid +#include +#include +#include +#include + +static AAssetManager* asset_manager_init(uintptr_t java_vm, uintptr_t jni_env, jobject ctx) { + JavaVM* vm = (JavaVM*)java_vm; + JNIEnv* env = (JNIEnv*)jni_env; + + // Equivalent to: + // assetManager = ctx.getResources().getAssets(); + jclass ctx_clazz = (*env)->FindClass(env, "android/content/Context"); + jmethodID getres_id = (*env)->GetMethodID(env, ctx_clazz, "getResources", "()Landroid/content/res/Resources;"); + jobject res = (*env)->CallObjectMethod(env, ctx, getres_id); + jclass res_clazz = (*env)->FindClass(env, "android/content/res/Resources"); + jmethodID getam_id = (*env)->GetMethodID(env, res_clazz, "getAssets", "()Landroid/content/res/AssetManager;"); + jobject am = (*env)->CallObjectMethod(env, res, getam_id); + + // Pin the AssetManager and load an AAssetManager from it. + am = (*env)->NewGlobalRef(env, am); + return AAssetManager_fromJava(env, am); +} +*/ +import "C" +import ( + "fmt" + "io" + "log" + "os" + "sync" + "unsafe" + + "golang.org/x/mobile/internal/mobileinit" +) + +var assetOnce sync.Once + +// asset_manager is the asset manager of the app. +var assetManager *C.AAssetManager + +func assetInit() { + err := mobileinit.RunOnJVM(func(vm, env, ctx uintptr) error { + assetManager = C.asset_manager_init(C.uintptr_t(vm), C.uintptr_t(env), C.jobject(ctx)) + return nil + }) + if err != nil { + log.Fatalf("asset: %v", err) + } +} + +func openAsset(name string) (File, error) { + assetOnce.Do(assetInit) + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + a := &asset{ + ptr: C.AAssetManager_open(assetManager, cname, C.AASSET_MODE_UNKNOWN), + name: name, + } + if a.ptr == nil { + return nil, a.errorf("open", "bad asset") + } + return a, nil +} + +type asset struct { + ptr *C.AAsset + name string +} + +func (a *asset) errorf(op string, format string, v ...interface{}) error { + return &os.PathError{ + Op: op, + Path: a.name, + Err: fmt.Errorf(format, v...), + } +} + +func (a *asset) Read(p []byte) (n int, err error) { + n = int(C.AAsset_read(a.ptr, unsafe.Pointer(&p[0]), C.size_t(len(p)))) + if n == 0 && len(p) > 0 { + return 0, io.EOF + } + if n < 0 { + return 0, a.errorf("read", "negative bytes: %d", n) + } + return n, nil +} + +func (a *asset) Seek(offset int64, whence int) (int64, error) { + // TODO(crawshaw): use AAsset_seek64 if it is available. + off := C.AAsset_seek(a.ptr, C.off_t(offset), C.int(whence)) + if off == -1 { + return 0, a.errorf("seek", "bad result for offset=%d, whence=%d", offset, whence) + } + return int64(off), nil +} + +func (a *asset) Close() error { + C.AAsset_close(a.ptr) + return nil +} diff --git a/asset/asset_darwin_armx.go b/asset/asset_darwin_armx.go new file mode 100644 index 000000000..3eac25b04 --- /dev/null +++ b/asset/asset_darwin_armx.go @@ -0,0 +1,25 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && (arm || arm64) +// +build darwin +// +build arm arm64 + +package asset + +import ( + "os" + "path/filepath" +) + +func openAsset(name string) (File, error) { + if !filepath.IsAbs(name) { + name = filepath.Join("assets", name) + } + f, err := os.Open(name) + if err != nil { + return nil, err + } + return f, nil +} diff --git a/asset/asset_desktop.go b/asset/asset_desktop.go new file mode 100644 index 000000000..a36099504 --- /dev/null +++ b/asset/asset_desktop.go @@ -0,0 +1,24 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (linux && !android) || (darwin && !arm && !arm64) || windows +// +build linux,!android darwin,!arm,!arm64 windows + +package asset + +import ( + "os" + "path/filepath" +) + +func openAsset(name string) (File, error) { + if !filepath.IsAbs(name) { + name = filepath.Join("assets", name) + } + f, err := os.Open(name) + if err != nil { + return nil, err + } + return f, nil +} diff --git a/asset/doc.go b/asset/doc.go new file mode 100644 index 000000000..b40d4a44d --- /dev/null +++ b/asset/doc.go @@ -0,0 +1,17 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package asset provides access to application-bundled assets. +// +// On Android, assets are accessed via android.content.res.AssetManager. +// These files are stored in the assets/ directory of the app. Any raw asset +// can be accessed by its direct relative name. For example assets/img.png +// can be opened with Open("img.png"). +// +// On iOS an asset is a resource stored in the application bundle. +// Resources can be loaded using the same relative paths. +// +// For consistency when debugging on a desktop, assets are read from a +// directory named assets under the current working directory. +package asset // import "golang.org/x/mobile/asset" diff --git a/bind/bind.go b/bind/bind.go new file mode 100644 index 000000000..e5690835e --- /dev/null +++ b/bind/bind.go @@ -0,0 +1,59 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bind implements a code generator for gobind. +// +// See the documentation on the gobind command for usage details +// and the list of currently supported types. +// (http://godoc.org/golang.org/x/mobile/cmd/gobind) +package bind // import "golang.org/x/mobile/bind" + +// TODO(crawshaw): slice support +// TODO(crawshaw): channel support + +import ( + "bytes" + "go/format" + "go/token" + "go/types" + "io" +) + +const gobindPreamble = "// Code generated by gobind. DO NOT EDIT.\n\n" + +type ( + GeneratorConfig struct { + Writer io.Writer + Fset *token.FileSet + Pkg *types.Package + AllPkg []*types.Package + } + + fileType int +) + +// GenGo generates a Go stub to support foreign language APIs. +func GenGo(conf *GeneratorConfig) error { + buf := new(bytes.Buffer) + g := &goGen{ + Generator: &Generator{ + Printer: &Printer{Buf: buf, IndentEach: []byte("\t")}, + Fset: conf.Fset, + AllPkg: conf.AllPkg, + Pkg: conf.Pkg, + }, + } + g.Init() + if err := g.gen(); err != nil { + return err + } + src := buf.Bytes() + srcf, err := format.Source(src) + if err != nil { + conf.Writer.Write(src) // for debugging + return err + } + _, err = conf.Writer.Write(srcf) + return err +} diff --git a/bind/bind_test.go b/bind/bind_test.go new file mode 100644 index 000000000..fae951b31 --- /dev/null +++ b/bind/bind_test.go @@ -0,0 +1,700 @@ +package bind + +import ( + "bytes" + "flag" + "go/ast" + "go/build" + "go/format" + "go/importer" + "go/parser" + "go/token" + "go/types" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path" + "path/filepath" + "runtime" + "strings" + "testing" + + "golang.org/x/mobile/internal/importers" + "golang.org/x/mobile/internal/importers/java" + "golang.org/x/mobile/internal/importers/objc" +) + +func init() { + log.SetFlags(log.Lshortfile) +} + +var updateFlag = flag.Bool("update", false, "Update the golden files.") + +var tests = []string{ + "", // The universe package with the error type. + "testdata/basictypes.go", + "testdata/structs.go", + "testdata/interfaces.go", + "testdata/issue10788.go", + "testdata/issue12328.go", + "testdata/issue12403.go", + "testdata/issue29559.go", + "testdata/keywords.go", + "testdata/try.go", + "testdata/vars.go", + "testdata/ignore.go", + "testdata/doc.go", + "testdata/underscores.go", +} + +var javaTests = []string{ + "testdata/java.go", + "testdata/classes.go", +} + +var objcTests = []string{ + "testdata/objc.go", + "testdata/objcw.go", +} + +var fset = token.NewFileSet() + +func fileRefs(t *testing.T, filename string, pkgPrefix string) *importers.References { + f, err := parser.ParseFile(fset, filename, nil, parser.AllErrors) + if err != nil { + t.Fatalf("%s: %v", filename, err) + } + refs, err := importers.AnalyzeFile(f, pkgPrefix) + if err != nil { + t.Fatalf("%s: %v", filename, err) + } + fakePath := path.Dir(filename) + for i := range refs.Embedders { + refs.Embedders[i].PkgPath = fakePath + } + return refs +} + +func typeCheck(t *testing.T, filename string, gopath string) (*types.Package, *ast.File) { + f, err := parser.ParseFile(fset, filename, nil, parser.AllErrors|parser.ParseComments) + if err != nil { + t.Fatalf("%s: %v", filename, err) + } + + pkgName := filepath.Base(filename) + pkgName = strings.TrimSuffix(pkgName, ".go") + + // typecheck and collect typechecker errors + var conf types.Config + conf.Error = func(err error) { + t.Error(err) + } + if gopath != "" { + conf.Importer = importer.Default() + oldDefault := build.Default + defer func() { build.Default = oldDefault }() + build.Default.GOPATH = gopath + } + pkg, err := conf.Check(pkgName, fset, []*ast.File{f}, nil) + if err != nil { + t.Fatal(err) + } + return pkg, f +} + +// diff runs the command "diff a b" and returns its output +func diff(a, b string) string { + var buf bytes.Buffer + var cmd *exec.Cmd + switch runtime.GOOS { + case "plan9": + cmd = exec.Command("/bin/diff", "-c", a, b) + default: + cmd = exec.Command("/usr/bin/diff", "-u", a, b) + } + cmd.Stdout = &buf + cmd.Stderr = &buf + cmd.Run() + return buf.String() +} + +func writeTempFile(t *testing.T, name string, contents []byte) string { + f, err := ioutil.TempFile("", name) + if err != nil { + t.Fatal(err) + } + if _, err := f.Write(contents); err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } + return f.Name() +} + +func TestGenObjc(t *testing.T) { + for _, filename := range tests { + var pkg *types.Package + var file *ast.File + if filename != "" { + pkg, file = typeCheck(t, filename, "") + } + + var buf bytes.Buffer + g := &ObjcGen{ + Generator: &Generator{ + Printer: &Printer{Buf: &buf, IndentEach: []byte("\t")}, + Fset: fset, + Files: []*ast.File{file}, + Pkg: pkg, + }, + } + if pkg != nil { + g.AllPkg = []*types.Package{pkg} + } + g.Init(nil) + + testcases := []struct { + suffix string + gen func() error + }{ + { + ".objc.h.golden", + g.GenH, + }, + { + ".objc.m.golden", + g.GenM, + }, + { + ".objc.go.h.golden", + g.GenGoH, + }, + } + for _, tc := range testcases { + buf.Reset() + if err := tc.gen(); err != nil { + t.Errorf("%s: %v", filename, err) + continue + } + out := writeTempFile(t, "generated"+tc.suffix, buf.Bytes()) + defer os.Remove(out) + var golden string + if filename != "" { + golden = filename[:len(filename)-len(".go")] + } else { + golden = "testdata/universe" + } + golden += tc.suffix + if diffstr := diff(golden, out); diffstr != "" { + t.Errorf("%s: does not match Objective-C golden:\n%s", filename, diffstr) + if *updateFlag { + t.Logf("Updating %s...", golden) + err := exec.Command("/bin/cp", out, golden).Run() + if err != nil { + t.Errorf("Update failed: %s", err) + } + } + } + } + } +} + +func genObjcPackages(t *testing.T, dir string, cg *ObjcWrapper) { + pkgBase := filepath.Join(dir, "src", "ObjC") + if err := os.MkdirAll(pkgBase, 0700); err != nil { + t.Fatal(err) + } + for i, jpkg := range cg.Packages() { + pkgDir := filepath.Join(pkgBase, jpkg) + if err := os.MkdirAll(pkgDir, 0700); err != nil { + t.Fatal(err) + } + pkgFile := filepath.Join(pkgDir, "package.go") + cg.Buf.Reset() + cg.GenPackage(i) + if err := ioutil.WriteFile(pkgFile, cg.Buf.Bytes(), 0600); err != nil { + t.Fatal(err) + } + } + cg.Buf.Reset() + cg.GenInterfaces() + clsFile := filepath.Join(pkgBase, "interfaces.go") + if err := ioutil.WriteFile(clsFile, cg.Buf.Bytes(), 0600); err != nil { + t.Fatal(err) + } + + gocmd := filepath.Join(runtime.GOROOT(), "bin", "go") + cmd := exec.Command( + gocmd, + "install", + "-pkgdir="+filepath.Join(dir, "pkg", build.Default.GOOS+"_"+build.Default.GOARCH), + "ObjC/...", + ) + cmd.Env = append(os.Environ(), "GOPATH="+dir, "GO111MODULE=off") + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("failed to go install the generated ObjC wrappers: %v: %s", err, string(out)) + } +} + +func genJavaPackages(t *testing.T, dir string, cg *ClassGen) { + buf := cg.Buf + cg.Buf = new(bytes.Buffer) + pkgBase := filepath.Join(dir, "src", "Java") + if err := os.MkdirAll(pkgBase, 0700); err != nil { + t.Fatal(err) + } + for i, jpkg := range cg.Packages() { + pkgDir := filepath.Join(pkgBase, jpkg) + if err := os.MkdirAll(pkgDir, 0700); err != nil { + t.Fatal(err) + } + pkgFile := filepath.Join(pkgDir, "package.go") + cg.Buf.Reset() + cg.GenPackage(i) + if err := ioutil.WriteFile(pkgFile, cg.Buf.Bytes(), 0600); err != nil { + t.Fatal(err) + } + io.Copy(buf, cg.Buf) + } + cg.Buf.Reset() + cg.GenInterfaces() + clsFile := filepath.Join(pkgBase, "interfaces.go") + if err := ioutil.WriteFile(clsFile, cg.Buf.Bytes(), 0600); err != nil { + t.Fatal(err) + } + io.Copy(buf, cg.Buf) + cg.Buf = buf + + gocmd := filepath.Join(runtime.GOROOT(), "bin", "go") + cmd := exec.Command( + gocmd, + "install", + "-pkgdir="+filepath.Join(dir, "pkg", build.Default.GOOS+"_"+build.Default.GOARCH), + "Java/...", + ) + cmd.Env = append(os.Environ(), "GOPATH="+dir, "GO111MODULE=off") + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("failed to go install the generated Java wrappers: %v: %s", err, string(out)) + } +} + +func TestGenJava(t *testing.T) { + allTests := tests + if java.IsAvailable() { + allTests = append(append([]string{}, allTests...), javaTests...) + } + for _, filename := range allTests { + var pkg *types.Package + var file *ast.File + var buf bytes.Buffer + var cg *ClassGen + var classes []*java.Class + if filename != "" { + refs := fileRefs(t, filename, "Java/") + imp := &java.Importer{} + var err error + classes, err = imp.Import(refs) + if err != nil { + t.Fatal(err) + } + tmpGopath := "" + if len(classes) > 0 { + tmpGopath, err = ioutil.TempDir(os.TempDir(), "gomobile-bind-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpGopath) + cg = &ClassGen{ + Printer: &Printer{ + IndentEach: []byte("\t"), + Buf: new(bytes.Buffer), + }, + } + cg.Init(classes, refs.Embedders) + genJavaPackages(t, tmpGopath, cg) + cg.Buf = &buf + } + pkg, file = typeCheck(t, filename, tmpGopath) + } + g := &JavaGen{ + Generator: &Generator{ + Printer: &Printer{Buf: &buf, IndentEach: []byte(" ")}, + Fset: fset, + Files: []*ast.File{file}, + Pkg: pkg, + }, + } + if pkg != nil { + g.AllPkg = []*types.Package{pkg} + } + g.Init(classes) + testCases := []struct { + suffix string + gen func() error + }{ + { + ".java.golden", + func() error { + for i := range g.ClassNames() { + if err := g.GenClass(i); err != nil { + return err + } + } + return g.GenJava() + }, + }, + { + ".java.c.golden", + func() error { + if cg != nil { + cg.GenC() + } + return g.GenC() + }, + }, + { + ".java.h.golden", + func() error { + if cg != nil { + cg.GenH() + } + return g.GenH() + }, + }, + } + + for _, tc := range testCases { + buf.Reset() + if err := tc.gen(); err != nil { + t.Errorf("%s: %v", filename, err) + continue + } + out := writeTempFile(t, "generated"+tc.suffix, buf.Bytes()) + defer os.Remove(out) + var golden string + if filename != "" { + golden = filename[:len(filename)-len(".go")] + } else { + golden = "testdata/universe" + } + golden += tc.suffix + if diffstr := diff(golden, out); diffstr != "" { + t.Errorf("%s: does not match Java golden:\n%s", filename, diffstr) + + if *updateFlag { + t.Logf("Updating %s...", golden) + if err := exec.Command("/bin/cp", out, golden).Run(); err != nil { + t.Errorf("Update failed: %s", err) + } + } + + } + } + } +} + +func TestGenGo(t *testing.T) { + for _, filename := range tests { + var buf bytes.Buffer + var pkg *types.Package + if filename != "" { + pkg, _ = typeCheck(t, filename, "") + } + testGenGo(t, filename, &buf, pkg) + } +} + +func TestGenGoJavaWrappers(t *testing.T) { + if !java.IsAvailable() { + t.Skipf("java is not available") + } + for _, filename := range javaTests { + var buf bytes.Buffer + refs := fileRefs(t, filename, "Java/") + imp := &java.Importer{} + classes, err := imp.Import(refs) + if err != nil { + t.Fatal(err) + } + tmpGopath, err := ioutil.TempDir(os.TempDir(), "gomobile-bind-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpGopath) + cg := &ClassGen{ + Printer: &Printer{ + IndentEach: []byte("\t"), + Buf: &buf, + }, + } + cg.Init(classes, refs.Embedders) + genJavaPackages(t, tmpGopath, cg) + pkg, _ := typeCheck(t, filename, tmpGopath) + cg.GenGo() + testGenGo(t, filename, &buf, pkg) + } +} + +func TestGenGoObjcWrappers(t *testing.T) { + if runtime.GOOS != "darwin" { + t.Skipf("can only generate objc wrappers on darwin") + } + for _, filename := range objcTests { + var buf bytes.Buffer + refs := fileRefs(t, filename, "ObjC/") + types, err := objc.Import(refs) + if err != nil { + t.Fatal(err) + } + tmpGopath, err := ioutil.TempDir(os.TempDir(), "gomobile-bind-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpGopath) + cg := &ObjcWrapper{ + Printer: &Printer{ + IndentEach: []byte("\t"), + Buf: &buf, + }, + } + var genNames []string + for _, emb := range refs.Embedders { + genNames = append(genNames, emb.Name) + } + cg.Init(types, genNames) + genObjcPackages(t, tmpGopath, cg) + pkg, _ := typeCheck(t, filename, tmpGopath) + cg.GenGo() + testGenGo(t, filename, &buf, pkg) + } +} + +func testGenGo(t *testing.T, filename string, buf *bytes.Buffer, pkg *types.Package) { + conf := &GeneratorConfig{ + Writer: buf, + Fset: fset, + Pkg: pkg, + } + if pkg != nil { + conf.AllPkg = []*types.Package{pkg} + } + if err := GenGo(conf); err != nil { + t.Errorf("%s: %v", filename, err) + return + } + // TODO(hyangah): let GenGo format the generated go files. + out := writeTempFile(t, "go", gofmt(t, buf.Bytes())) + defer os.Remove(out) + + golden := filename + if golden == "" { + golden = "testdata/universe" + } + golden += ".golden" + + goldenContents, err := ioutil.ReadFile(golden) + if err != nil { + t.Fatalf("failed to read golden file: %v", err) + } + + // format golden file using the current go version's formatting rule. + formattedGolden := writeTempFile(t, "go", gofmt(t, goldenContents)) + defer os.Remove(formattedGolden) + + if diffstr := diff(formattedGolden, out); diffstr != "" { + t.Errorf("%s: does not match Go golden:\n%s", filename, diffstr) + + if *updateFlag { + t.Logf("Updating %s...", golden) + if err := exec.Command("/bin/cp", out, golden).Run(); err != nil { + t.Errorf("Update failed: %s", err) + } + } + } +} + +// gofmt formats the collection of Go source files auto-generated by gobind. +func gofmt(t *testing.T, src []byte) []byte { + t.Helper() + buf := &bytes.Buffer{} + mark := []byte(gobindPreamble) + for i, c := range bytes.Split(src, mark) { + if i == 0 { + buf.Write(c) + continue + } + tmp := append(mark, c...) + out, err := format.Source(tmp) + if err != nil { + t.Fatalf("failed to format Go file: error=%v\n----\n%s\n----", err, tmp) + } + if _, err := buf.Write(out); err != nil { + t.Fatalf("failed to write formatted file to buffer: %v", err) + } + } + return buf.Bytes() +} + +func TestCustomPrefix(t *testing.T) { + const datafile = "testdata/customprefix.go" + pkg, file := typeCheck(t, datafile, "") + + type testCase struct { + golden string + gen func(w io.Writer) error + } + var buf bytes.Buffer + jg := &JavaGen{ + JavaPkg: "com.example", + Generator: &Generator{ + Printer: &Printer{Buf: &buf, IndentEach: []byte(" ")}, + Fset: fset, + AllPkg: []*types.Package{pkg}, + Files: []*ast.File{file}, + Pkg: pkg, + }, + } + jg.Init(nil) + testCases := []testCase{ + { + "testdata/customprefix.java.golden", + func(w io.Writer) error { + buf.Reset() + for i := range jg.ClassNames() { + if err := jg.GenClass(i); err != nil { + return err + } + } + if err := jg.GenJava(); err != nil { + return err + } + _, err := io.Copy(w, &buf) + return err + }, + }, + { + "testdata/customprefix.java.h.golden", + func(w io.Writer) error { + buf.Reset() + if err := jg.GenH(); err != nil { + return err + } + _, err := io.Copy(w, &buf) + return err + }, + }, + { + "testdata/customprefix.java.c.golden", + func(w io.Writer) error { + buf.Reset() + if err := jg.GenC(); err != nil { + return err + } + _, err := io.Copy(w, &buf) + return err + }, + }, + } + for _, pref := range []string{"EX", ""} { + og := &ObjcGen{ + Prefix: pref, + Generator: &Generator{ + Printer: &Printer{Buf: &buf, IndentEach: []byte(" ")}, + Fset: fset, + AllPkg: []*types.Package{pkg}, + Pkg: pkg, + }, + } + og.Init(nil) + testCases = append(testCases, []testCase{ + { + "testdata/customprefix" + pref + ".objc.go.h.golden", + func(w io.Writer) error { + buf.Reset() + if err := og.GenGoH(); err != nil { + return err + } + _, err := io.Copy(w, &buf) + return err + }, + }, + { + "testdata/customprefix" + pref + ".objc.h.golden", + func(w io.Writer) error { + buf.Reset() + if err := og.GenH(); err != nil { + return err + } + _, err := io.Copy(w, &buf) + return err + }, + }, + { + "testdata/customprefix" + pref + ".objc.m.golden", + func(w io.Writer) error { + buf.Reset() + if err := og.GenM(); err != nil { + return err + } + _, err := io.Copy(w, &buf) + return err + }, + }, + }...) + } + + for _, tc := range testCases { + var buf bytes.Buffer + if err := tc.gen(&buf); err != nil { + t.Errorf("generating %s: %v", tc.golden, err) + continue + } + out := writeTempFile(t, "generated", buf.Bytes()) + defer os.Remove(out) + if diffstr := diff(tc.golden, out); diffstr != "" { + t.Errorf("%s: generated file does not match:\b%s", tc.golden, diffstr) + if *updateFlag { + t.Logf("Updating %s...", tc.golden) + err := exec.Command("/bin/cp", out, tc.golden).Run() + if err != nil { + t.Errorf("Update failed: %s", err) + } + } + } + } +} + +func TestLowerFirst(t *testing.T) { + testCases := []struct { + in, want string + }{ + {"", ""}, + {"Hello", "hello"}, + {"HelloGopher", "helloGopher"}, + {"hello", "hello"}, + {"ID", "id"}, + {"IDOrName", "idOrName"}, + {"ΓειαΣας", "γειαΣας"}, + } + + for _, tc := range testCases { + if got := lowerFirst(tc.in); got != tc.want { + t.Errorf("lowerFirst(%q) = %q; want %q", tc.in, got, tc.want) + } + } +} + +// Test that typeName work for anonymous qualified fields. +func TestSelectorExprTypeName(t *testing.T) { + e, err := parser.ParseExprFrom(fset, "", "struct { bytes.Buffer }", 0) + if err != nil { + t.Fatal(err) + } + ft := e.(*ast.StructType).Fields.List[0].Type + if got, want := typeName(ft), "Buffer"; got != want { + t.Errorf("got: %q; want %q", got, want) + } +} diff --git a/bind/gen.go b/bind/gen.go new file mode 100644 index 000000000..4fedfbeb5 --- /dev/null +++ b/bind/gen.go @@ -0,0 +1,575 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bind + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "go/types" + "io" + "regexp" + "strings" + "unicode" + "unicode/utf8" +) + +type ( + ErrorList []error + + // varMode describes the lifetime of an argument or + // return value. Modes are used to guide the conversion + // of string and byte slice values across the language + // barrier. The same conversion mode must be used for + // both the conversion before a foreign call and the + // corresponding conversion after the call. + // See the mode* constants for a description of + // each mode. + varMode int +) + +const ( + // modeTransient are for function arguments that + // are not used after the function returns. + // Transient byte slices don't need copying + // when passed across the language barrier. + modeTransient varMode = iota + // modeRetained are for returned values and for function + // arguments that are used after the function returns. + // Retained byte slices need an intermediate copy. + modeRetained +) + +func (list ErrorList) Error() string { + buf := new(bytes.Buffer) + for i, err := range list { + if i > 0 { + buf.WriteRune('\n') + } + io.WriteString(buf, err.Error()) + } + return buf.String() +} + +// interfaceInfo comes from Init and collects the auxiliary information +// needed to generate bindings for an exported Go interface in a bound +// package. +type interfaceInfo struct { + obj *types.TypeName + t *types.Interface + summary ifaceSummary +} + +// structInfo comes from Init and collects the auxiliary information +// needed to generate bindings for an exported Go struct in a bound +// package. +type structInfo struct { + obj *types.TypeName + t *types.Struct +} + +// Generator contains the common Go package information +// needed for the specific Go, Java, ObjC generators. +// +// After setting Printer, Fset, AllPkg, Pkg, the Init +// method is used to initialize the auxiliary information +// about the package to be generated, Pkg. +type Generator struct { + *Printer + Fset *token.FileSet + AllPkg []*types.Package + Files []*ast.File + Pkg *types.Package + err ErrorList + + // fields set by init. + pkgName string + pkgPrefix string + funcs []*types.Func + constants []*types.Const + vars []*types.Var + + interfaces []interfaceInfo + structs []structInfo + otherNames []*types.TypeName + // allIntf contains interfaces from all bound packages. + allIntf []interfaceInfo + + docs pkgDocs +} + +// A pkgDocs maps the name of each exported package-level declaration to its extracted documentation. +type pkgDocs map[string]*pkgDoc + +type pkgDoc struct { + doc string + // Struct or interface fields and methods. + members map[string]string +} + +// pkgPrefix returns a prefix that disambiguates symbol names for binding +// multiple packages. +// +// TODO(elias.naur): Avoid (and test) name clashes from multiple packages +// with the same name. Perhaps use the index from the order the package is +// generated. +func pkgPrefix(pkg *types.Package) string { + // The error type has no package + if pkg == nil { + return "" + } + return pkg.Name() +} + +func (g *Generator) Init() { + if g.Pkg != nil { + g.pkgName = g.Pkg.Name() + } + g.pkgPrefix = pkgPrefix(g.Pkg) + + if g.Pkg != nil { + g.parseDocs() + scope := g.Pkg.Scope() + hasExported := false + for _, name := range scope.Names() { + obj := scope.Lookup(name) + if !obj.Exported() { + continue + } + hasExported = true + switch obj := obj.(type) { + case *types.Func: + if isCallable(obj) { + g.funcs = append(g.funcs, obj) + } + case *types.TypeName: + named, ok := obj.Type().(*types.Named) + if !ok { + continue + } + switch t := named.Underlying().(type) { + case *types.Struct: + g.structs = append(g.structs, structInfo{obj, t}) + case *types.Interface: + g.interfaces = append(g.interfaces, interfaceInfo{obj, t, makeIfaceSummary(t)}) + default: + g.otherNames = append(g.otherNames, obj) + } + case *types.Const: + g.constants = append(g.constants, obj) + case *types.Var: + g.vars = append(g.vars, obj) + default: + g.errorf("unsupported exported type for %s: %T", obj.Name(), obj) + } + } + if !hasExported { + g.errorf("no exported names in the package %q", g.Pkg.Path()) + } + } else { + // Bind the single supported type from the universe scope, error. + errType := types.Universe.Lookup("error").(*types.TypeName) + t := errType.Type().Underlying().(*types.Interface) + g.interfaces = append(g.interfaces, interfaceInfo{errType, t, makeIfaceSummary(t)}) + } + for _, p := range g.AllPkg { + scope := p.Scope() + for _, name := range scope.Names() { + obj := scope.Lookup(name) + if !obj.Exported() { + continue + } + if obj, ok := obj.(*types.TypeName); ok { + named, ok := obj.Type().(*types.Named) + if !ok { + continue + } + if t, ok := named.Underlying().(*types.Interface); ok { + g.allIntf = append(g.allIntf, interfaceInfo{obj, t, makeIfaceSummary(t)}) + } + } + } + } +} + +// parseDocs extracts documentation from a package in a form useful for lookups. +func (g *Generator) parseDocs() { + d := make(pkgDocs) + for _, f := range g.Files { + for _, decl := range f.Decls { + switch decl := decl.(type) { + case *ast.GenDecl: + for _, spec := range decl.Specs { + switch spec := spec.(type) { + case *ast.TypeSpec: + d.addType(spec, decl.Doc) + case *ast.ValueSpec: + d.addValue(spec, decl.Doc) + } + } + case *ast.FuncDecl: + d.addFunc(decl) + } + } + } + g.docs = d +} + +func (d pkgDocs) addValue(t *ast.ValueSpec, outerDoc *ast.CommentGroup) { + for _, n := range t.Names { + if !ast.IsExported(n.Name) { + continue + } + doc := t.Doc + if doc == nil { + doc = outerDoc + } + if doc != nil { + d[n.Name] = &pkgDoc{doc: doc.Text()} + } + } +} + +func (d pkgDocs) addFunc(f *ast.FuncDecl) { + doc := f.Doc + if doc == nil { + return + } + fn := f.Name.Name + if !ast.IsExported(fn) { + return + } + if r := f.Recv; r != nil { + // f is a method. + n := typeName(r.List[0].Type) + pd, exists := d[n] + if !exists { + pd = &pkgDoc{members: make(map[string]string)} + d[n] = pd + } + pd.members[fn] = doc.Text() + } else { + // f is a function. + d[fn] = &pkgDoc{doc: doc.Text()} + } +} + +func (d pkgDocs) addType(t *ast.TypeSpec, outerDoc *ast.CommentGroup) { + if !ast.IsExported(t.Name.Name) { + return + } + doc := t.Doc + if doc == nil { + doc = outerDoc + } + pd := d[t.Name.Name] + pd = &pkgDoc{members: make(map[string]string)} + d[t.Name.Name] = pd + if doc != nil { + pd.doc = doc.Text() + } + var fields *ast.FieldList + switch t := t.Type.(type) { + case *ast.StructType: + fields = t.Fields + case *ast.InterfaceType: + fields = t.Methods + } + if fields != nil { + for _, field := range fields.List { + if field.Doc != nil { + if field.Names == nil { + // Anonymous field. Extract name from its type. + if n := typeName(field.Type); ast.IsExported(n) { + pd.members[n] = field.Doc.Text() + } + } + for _, n := range field.Names { + if ast.IsExported(n.Name) { + pd.members[n.Name] = field.Doc.Text() + } + } + } + } + } +} + +// typeName returns the type name T for expressions on the +// T, *T, **T (etc.) form. +func typeName(t ast.Expr) string { + switch t := t.(type) { + case *ast.StarExpr: + return typeName(t.X) + case *ast.Ident: + return t.Name + case *ast.SelectorExpr: + return t.Sel.Name + default: + return "" + } +} + +func (d *pkgDoc) Doc() string { + if d == nil { + return "" + } + return d.doc +} + +func (d *pkgDoc) Member(n string) string { + if d == nil { + return "" + } + return d.members[n] +} + +// constructorType returns the type T for a function of the forms: +// +// func NewT...(...) *T +// func NewT...(...) (*T, error) +func (g *Generator) constructorType(f *types.Func) *types.TypeName { + sig := f.Type().(*types.Signature) + res := sig.Results() + if res.Len() != 1 && !(res.Len() == 2 && isErrorType(res.At(1).Type())) { + return nil + } + rt := res.At(0).Type() + pt, ok := rt.(*types.Pointer) + if !ok { + return nil + } + nt, ok := pt.Elem().(*types.Named) + if !ok { + return nil + } + obj := nt.Obj() + if !strings.HasPrefix(f.Name(), "New"+obj.Name()) { + return nil + } + return obj +} + +func toCFlag(v bool) int { + if v { + return 1 + } + return 0 +} + +func (g *Generator) errorf(format string, args ...interface{}) { + g.err = append(g.err, fmt.Errorf(format, args...)) +} + +// cgoType returns the name of a Cgo type suitable for converting a value of +// the given type. +func (g *Generator) cgoType(t types.Type) string { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.Bool, types.UntypedBool: + return "char" + case types.Int: + return "nint" + case types.Int8: + return "int8_t" + case types.Int16: + return "int16_t" + case types.Int32, types.UntypedRune: // types.Rune + return "int32_t" + case types.Int64, types.UntypedInt: + return "int64_t" + case types.Uint8: // types.Byte + return "uint8_t" + // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: + case types.Float32: + return "float" + case types.Float64, types.UntypedFloat: + return "double" + case types.String: + return "nstring" + default: + g.errorf("unsupported basic type: %s", t) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + return "nbyteslice" + default: + g.errorf("unsupported slice type: %s", t) + } + default: + g.errorf("unsupported slice type: %s", t) + } + case *types.Pointer: + if _, ok := t.Elem().(*types.Named); ok { + return g.cgoType(t.Elem()) + } + g.errorf("unsupported pointer to type: %s", t) + case *types.Named: + return "int32_t" + default: + g.errorf("unsupported type: %s", t) + } + return "TODO" +} + +func (g *Generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool, g_paramName func(*types.Tuple, int) string) { + sig := m.Type().(*types.Signature) + params := sig.Params() + res := sig.Results() + + if res.Len() == 0 { + g.Printf("void ") + } else { + if res.Len() == 1 { + g.Printf("%s ", g.cgoType(res.At(0).Type())) + } else { + if header { + g.Printf("typedef struct cproxy%s_%s_%s_return {\n", g.pkgPrefix, iName, m.Name()) + g.Indent() + for i := 0; i < res.Len(); i++ { + t := res.At(i).Type() + g.Printf("%s r%d;\n", g.cgoType(t), i) + } + g.Outdent() + g.Printf("} cproxy%s_%s_%s_return;\n", g.pkgPrefix, iName, m.Name()) + } + g.Printf("struct cproxy%s_%s_%s_return ", g.pkgPrefix, iName, m.Name()) + } + } + g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name()) + for i := 0; i < params.Len(); i++ { + t := params.At(i).Type() + g.Printf(", %s %s", g.cgoType(t), g_paramName(params, i)) + } + g.Printf(")") + if header { + g.Printf(";\n") + } else { + g.Printf(" {\n") + } +} + +func (g *Generator) validPkg(pkg *types.Package) bool { + for _, p := range g.AllPkg { + if p == pkg { + return true + } + } + return false +} + +// isSigSupported reports whether the generators can handle a given +// function signature. +func (g *Generator) isSigSupported(t types.Type) bool { + sig := t.(*types.Signature) + params := sig.Params() + for i := 0; i < params.Len(); i++ { + if !g.isSupported(params.At(i).Type()) { + return false + } + } + res := sig.Results() + for i := 0; i < res.Len(); i++ { + if !g.isSupported(res.At(i).Type()) { + return false + } + } + return true +} + +// isSupported reports whether the generators can handle the type. +func (g *Generator) isSupported(t types.Type) bool { + if isErrorType(t) || isWrapperType(t) { + return true + } + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.Bool, types.UntypedBool, + types.Int, + types.Int8, types.Uint8, // types.Byte + types.Int16, + types.Int32, types.UntypedRune, // types.Rune + types.Int64, types.UntypedInt, + types.Float32, + types.Float64, types.UntypedFloat, + types.String, types.UntypedString: + return true + } + return false + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + return e.Kind() == types.Uint8 + } + case *types.Pointer: + switch t := t.Elem().(type) { + case *types.Named: + return g.validPkg(t.Obj().Pkg()) + } + case *types.Named: + switch t.Underlying().(type) { + case *types.Interface, *types.Pointer: + return g.validPkg(t.Obj().Pkg()) + } + } + return false +} + +var paramRE = regexp.MustCompile(`^p[0-9]*$`) + +// basicParamName replaces incompatible name with a p0-pN name. +// Missing names, or existing names of the form p[0-9] are incompatible. +func basicParamName(params *types.Tuple, pos int) string { + name := params.At(pos).Name() + if name == "" || name[0] == '_' || paramRE.MatchString(name) { + name = fmt.Sprintf("p%d", pos) + } + return name +} + +func lowerFirst(s string) string { + if s == "" { + return "" + } + + var conv []rune + for len(s) > 0 { + r, n := utf8.DecodeRuneInString(s) + if !unicode.IsUpper(r) { + if l := len(conv); l > 1 { + conv[l-1] = unicode.ToUpper(conv[l-1]) + } + return string(conv) + s + } + conv = append(conv, unicode.ToLower(r)) + s = s[n:] + } + return string(conv) +} + +// newNameSanitizer returns a functions that replaces all dashes and dots +// with underscores, as well as avoiding reserved words by suffixing such +// identifiers with underscores. +func newNameSanitizer(res []string) func(s string) string { + reserved := make(map[string]bool) + for _, word := range res { + reserved[word] = true + } + symbols := strings.NewReplacer( + "-", "_", + ".", "_", + ) + return func(s string) string { + if reserved[s] { + return s + "_" + } + return symbols.Replace(s) + } +} diff --git a/bind/genclasses.go b/bind/genclasses.go new file mode 100644 index 000000000..8746ab27e --- /dev/null +++ b/bind/genclasses.go @@ -0,0 +1,948 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bind + +import ( + "fmt" + "path" + "reflect" + "strings" + "unicode" + "unicode/utf8" + + "golang.org/x/mobile/internal/importers" + "golang.org/x/mobile/internal/importers/java" +) + +type ( + // ClassGen generates Go and C stubs for Java classes so import statements + // on the form + // + // + // import "Java/classpath/to/Class" + // + // will work. + ClassGen struct { + *Printer + // JavaPkg is the Java package prefix for the generated classes. The prefix is prepended to the Go + // package name to create the full Java package name. + JavaPkg string + imported map[string]struct{} + // The list of imported Java classes + classes []*java.Class + // The list of Go package paths with Java interfaces inside + jpkgs []string + // For each Go package path, the list of Java classes. + typePkgs map[string][]*java.Class + // For each Go package path, the Java class with static functions + // or constants. + clsPkgs map[string]*java.Class + // goClsMap is the map of Java class names to Go type names, qualified with package name. Go types + // that implement Java classes need Super methods and Unwrap methods. + goClsMap map[string]string + // goClsImports is the list of imports of user packages that contains the Go types implementing Java + // classes. + goClsImports []string + } +) + +func (g *ClassGen) isSupported(t *java.Type) bool { + switch t.Kind { + case java.Array: + // TODO: Support all array types + return t.Elem.Kind == java.Byte + default: + return true + } +} + +func (g *ClassGen) isFuncSetSupported(fs *java.FuncSet) bool { + for _, f := range fs.Funcs { + if g.isFuncSupported(f) { + return true + } + } + return false +} + +func (g *ClassGen) isFuncSupported(f *java.Func) bool { + for _, a := range f.Params { + if !g.isSupported(a) { + return false + } + } + if f.Ret != nil { + return g.isSupported(f.Ret) + } + return true +} + +func (g *ClassGen) goType(t *java.Type, local bool) string { + if t == nil { + // interface{} is used for parameters types for overloaded methods + // where no common ancestor type exists. + return "interface{}" + } + switch t.Kind { + case java.Int: + return "int32" + case java.Boolean: + return "bool" + case java.Short: + return "int16" + case java.Char: + return "uint16" + case java.Byte: + return "byte" + case java.Long: + return "int64" + case java.Float: + return "float32" + case java.Double: + return "float64" + case java.String: + return "string" + case java.Array: + return "[]" + g.goType(t.Elem, local) + case java.Object: + name := goClsName(t.Class) + if !local { + name = "Java." + name + } + return name + default: + panic("invalid kind") + } +} + +// Init initializes the class wrapper generator. Classes is the +// list of classes to wrap, goClasses is the list of Java classes +// implemented in Go. +func (g *ClassGen) Init(classes []*java.Class, goClasses []importers.Struct) { + g.goClsMap = make(map[string]string) + impMap := make(map[string]struct{}) + for _, s := range goClasses { + n := s.Pkg + "." + s.Name + jn := n + if g.JavaPkg != "" { + jn = g.JavaPkg + "." + jn + } + g.goClsMap[jn] = n + if _, exists := impMap[s.PkgPath]; !exists { + impMap[s.PkgPath] = struct{}{} + g.goClsImports = append(g.goClsImports, s.PkgPath) + } + } + g.classes = classes + g.imported = make(map[string]struct{}) + g.typePkgs = make(map[string][]*java.Class) + g.clsPkgs = make(map[string]*java.Class) + pkgSet := make(map[string]struct{}) + for _, cls := range classes { + g.imported[cls.Name] = struct{}{} + clsPkg := strings.Replace(cls.Name, ".", "/", -1) + g.clsPkgs[clsPkg] = cls + typePkg := path.Dir(clsPkg) + g.typePkgs[typePkg] = append(g.typePkgs[typePkg], cls) + if _, exists := pkgSet[clsPkg]; !exists { + pkgSet[clsPkg] = struct{}{} + g.jpkgs = append(g.jpkgs, clsPkg) + } + if _, exists := pkgSet[typePkg]; !exists { + pkgSet[typePkg] = struct{}{} + g.jpkgs = append(g.jpkgs, typePkg) + } + } +} + +// Packages return the list of Go packages to be generated. +func (g *ClassGen) Packages() []string { + return g.jpkgs +} + +func (g *ClassGen) GenPackage(idx int) { + jpkg := g.jpkgs[idx] + g.Printf(gobindPreamble) + g.Printf("package %s\n\n", path.Base(jpkg)) + g.Printf("import \"Java\"\n\n") + g.Printf("const _ = Java.Dummy\n\n") + for _, cls := range g.typePkgs[jpkg] { + g.Printf("type %s Java.%s\n", cls.PkgName, goClsName(cls.Name)) + } + if cls, ok := g.clsPkgs[jpkg]; ok { + g.Printf("const (\n") + g.Indent() + // Constants + for _, v := range cls.Vars { + if g.isSupported(v.Type) && v.Constant() { + g.Printf("%s = %s\n", initialUpper(v.Name), v.Val) + } + } + g.Outdent() + g.Printf(")\n\n") + + g.Printf("var (\n") + g.Indent() + // Functions + loop: + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if f.Public && g.isFuncSupported(f) { + g.Printf("%s func", fs.GoName) + g.genFuncDecl(false, fs) + g.Printf("\n") + continue loop + } + } + } + g.Printf("// Cast takes a proxy for a Java object and converts it to a %s proxy.\n", cls.Name) + g.Printf("// Cast panics if the argument is not a proxy or if the underlying object does\n") + g.Printf("// not extend or implement %s.\n", cls.Name) + g.Printf("Cast func(v interface{}) Java.%s\n", goClsName(cls.Name)) + g.Outdent() + g.Printf(")\n\n") + } +} + +func (g *ClassGen) GenGo() { + g.Printf(classesGoHeader) + for _, cls := range g.classes { + pkgName := strings.Replace(cls.Name, ".", "/", -1) + g.Printf("import %q\n", "Java/"+pkgName) + } + for _, imp := range g.goClsImports { + g.Printf("import %q\n", imp) + } + if len(g.classes) > 0 { + g.Printf("import \"unsafe\"\n\n") + g.Printf("import \"reflect\"\n\n") + g.Printf("import \"fmt\"\n\n") + } + g.Printf("type proxy interface { Bind_proxy_refnum__() int32 }\n\n") + g.Printf("// Suppress unused package error\n\n") + g.Printf("var _ = _seq.FromRefNum\n") + g.Printf("const _ = Java.Dummy\n\n") + g.Printf("//export initClasses\n") + g.Printf("func initClasses() {\n") + g.Indent() + g.Printf("C.init_proxies()\n") + for _, cls := range g.classes { + g.Printf("init_%s()\n", cls.JNIName) + } + g.Outdent() + g.Printf("}\n\n") + for _, cls := range g.classes { + g.genGo(cls) + } +} + +func (g *ClassGen) GenH() { + g.Printf(classesHHeader) + for _, tn := range []string{"jint", "jboolean", "jshort", "jchar", "jbyte", "jlong", "jfloat", "jdouble", "nstring", "nbyteslice"} { + g.Printf("typedef struct ret_%s {\n", tn) + g.Printf(" %s res;\n", tn) + g.Printf(" jint exc;\n") + g.Printf("} ret_%s;\n", tn) + } + g.Printf("\n") + for _, cls := range g.classes { + for _, fs := range cls.AllMethods { + for _, f := range fs.Funcs { + if !g.isFuncSupported(f) { + continue + } + g.Printf("extern ") + g.genCMethodDecl("cproxy", cls.JNIName, f) + g.Printf(";\n") + if _, ok := g.goClsMap[cls.Name]; ok { + g.Printf("extern ") + g.genCMethodDecl("csuper", cls.JNIName, f) + g.Printf(";\n") + } + } + } + } + for _, cls := range g.classes { + g.genH(cls) + } +} + +func (g *ClassGen) GenC() { + g.Printf(classesCHeader) + for _, cls := range g.classes { + g.Printf("static jclass class_%s;\n", cls.JNIName) + if _, ok := g.goClsMap[cls.Name]; ok { + g.Printf("static jclass sclass_%s;\n", cls.JNIName) + } + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if !f.Public || !g.isFuncSupported(f) { + continue + } + g.Printf("static jmethodID m_s_%s_%s;\n", cls.JNIName, f.JNIName) + } + } + for _, fs := range cls.AllMethods { + for _, f := range fs.Funcs { + if g.isFuncSupported(f) { + g.Printf("static jmethodID m_%s_%s;\n", cls.JNIName, f.JNIName) + if _, ok := g.goClsMap[cls.Name]; ok { + g.Printf("static jmethodID sm_%s_%s;\n", cls.JNIName, f.JNIName) + } + } + } + } + g.genC(cls) + } + g.Printf("\n") + g.Printf("void init_proxies() {\n") + g.Indent() + g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(g.classes)) + g.Printf("jclass clazz;\n") + for _, cls := range g.classes { + g.Printf("clazz = go_seq_find_class(%q);\n", strings.Replace(cls.FindName, ".", "/", -1)) + g.Printf("if (clazz != NULL) {\n") + g.Indent() + g.Printf("class_%s = (*env)->NewGlobalRef(env, clazz);\n", cls.JNIName) + if _, ok := g.goClsMap[cls.Name]; ok { + g.Printf("sclass_%s = (*env)->GetSuperclass(env, clazz);\n", cls.JNIName) + g.Printf("sclass_%s = (*env)->NewGlobalRef(env, sclass_%s);\n", cls.JNIName, cls.JNIName) + } + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if !f.Public || !g.isFuncSupported(f) { + continue + } + g.Printf("m_s_%s_%s = ", cls.JNIName, f.JNIName) + if f.Constructor { + g.Printf("go_seq_get_method_id(clazz, \"\", %q);\n", f.Desc) + } else { + g.Printf("go_seq_get_static_method_id(clazz, %q, %q);\n", f.Name, f.Desc) + } + } + } + for _, fs := range cls.AllMethods { + for _, f := range fs.Funcs { + if g.isFuncSupported(f) { + g.Printf("m_%s_%s = go_seq_get_method_id(clazz, %q, %q);\n", cls.JNIName, f.JNIName, f.Name, f.Desc) + if _, ok := g.goClsMap[cls.Name]; ok { + g.Printf("sm_%s_%s = go_seq_get_method_id(sclass_%s, %q, %q);\n", cls.JNIName, f.JNIName, cls.JNIName, f.Name, f.Desc) + } + } + } + } + g.Outdent() + g.Printf("}\n") + } + g.Printf("go_seq_pop_local_frame(env);\n") + g.Outdent() + g.Printf("}\n\n") + for _, cls := range g.classes { + for _, fs := range cls.AllMethods { + for _, f := range fs.Funcs { + if !g.isFuncSupported(f) { + continue + } + g.genCMethodDecl("cproxy", cls.JNIName, f) + g.genCMethodBody(cls, f, false) + if _, ok := g.goClsMap[cls.Name]; ok { + g.genCMethodDecl("csuper", cls.JNIName, f) + g.genCMethodBody(cls, f, true) + } + } + } + } +} + +func (g *ClassGen) GenInterfaces() { + g.Printf(classesPkgHeader) + for _, cls := range g.classes { + g.genInterface(cls) + } +} + +func (g *ClassGen) genCMethodBody(cls *java.Class, f *java.Func, virtual bool) { + g.Printf(" {\n") + g.Indent() + // Add 1 for the 'this' argument + g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)+1) + g.Printf("// Must be a Java object\n") + g.Printf("jobject _this = go_seq_from_refnum(env, this, NULL, NULL);\n") + for i, a := range f.Params { + g.genCToJava(fmt.Sprintf("a%d", i), a) + } + if f.Ret != nil { + g.Printf("%s res = ", f.Ret.JNIType()) + } + g.Printf("(*env)->Call") + if virtual { + g.Printf("Nonvirtual") + } + if f.Ret != nil { + g.Printf(f.Ret.JNICallType()) + } else { + g.Printf("Void") + } + g.Printf("Method(env, _this, ") + if virtual { + g.Printf("sclass_%s, sm_%s_%s", cls.JNIName, cls.JNIName, f.JNIName) + } else { + g.Printf("m_%s_%s", cls.JNIName, f.JNIName) + } + for i := range f.Params { + g.Printf(", _a%d", i) + } + g.Printf(");\n") + g.Printf("jobject _exc = go_seq_get_exception(env);\n") + g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n") + if f.Ret != nil { + g.genCRetClear("res", f.Ret, "_exc") + g.genJavaToC("res", f.Ret) + } + g.Printf("go_seq_pop_local_frame(env);\n") + if f.Ret != nil { + g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType()) + g.Printf("return __res;\n") + } else { + g.Printf("return _exc_ref;\n") + } + g.Outdent() + g.Printf("}\n\n") +} + +func initialUpper(s string) string { + if s == "" { + return "" + } + r, n := utf8.DecodeRuneInString(s) + return string(unicode.ToUpper(r)) + s[n:] +} + +func (g *ClassGen) genFuncDecl(local bool, fs *java.FuncSet) { + g.Printf("(") + for i, a := range fs.Params { + if i > 0 { + g.Printf(", ") + } + g.Printf("a%d ", i) + if i == len(fs.Params)-1 && fs.Variadic { + g.Printf("...") + } + g.Printf(g.goType(a, local)) + } + g.Printf(")") + if fs.Throws { + if fs.HasRet { + g.Printf(" (%s, error)", g.goType(fs.Ret, local)) + } else { + g.Printf(" error") + } + } else if fs.HasRet { + g.Printf(" %s", g.goType(fs.Ret, local)) + } +} + +func (g *ClassGen) genC(cls *java.Class) { + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if !f.Public || !g.isFuncSupported(f) { + continue + } + g.genCFuncDecl(cls.JNIName, f) + g.Printf(" {\n") + g.Indent() + g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)) + for i, a := range f.Params { + g.genCToJava(fmt.Sprintf("a%d", i), a) + } + if f.Constructor { + g.Printf("jobject res = (*env)->NewObject(env") + } else if f.Ret != nil { + g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType()) + } else { + g.Printf("(*env)->CallStaticVoidMethod(env") + } + g.Printf(", class_%s, m_s_%s_%s", cls.JNIName, cls.JNIName, f.JNIName) + for i := range f.Params { + g.Printf(", _a%d", i) + } + g.Printf(");\n") + g.Printf("jobject _exc = go_seq_get_exception(env);\n") + g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n") + if f.Ret != nil { + g.genCRetClear("res", f.Ret, "_exc") + g.genJavaToC("res", f.Ret) + } + g.Printf("go_seq_pop_local_frame(env);\n") + if f.Ret != nil { + g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType()) + g.Printf("return __res;\n") + } else { + g.Printf("return _exc_ref;\n") + } + g.Outdent() + g.Printf("}\n\n") + } + } +} + +func (g *ClassGen) genH(cls *java.Class) { + for _, fs := range cls.Funcs { + for _, f := range fs.Funcs { + if !f.Public || !g.isFuncSupported(f) { + continue + } + g.Printf("extern ") + g.genCFuncDecl(cls.JNIName, f) + g.Printf(";\n") + } + } +} + +func (g *ClassGen) genCMethodDecl(prefix, jniName string, f *java.Func) { + if f.Ret != nil { + g.Printf("ret_%s", f.Ret.CType()) + } else { + // Return only the exception, if any + g.Printf("jint") + } + g.Printf(" %s_%s_%s(jint this", prefix, jniName, f.JNIName) + for i, a := range f.Params { + g.Printf(", %s a%d", a.CType(), i) + } + g.Printf(")") +} + +func (g *ClassGen) genCFuncDecl(jniName string, f *java.Func) { + if f.Ret != nil { + g.Printf("ret_%s", f.Ret.CType()) + } else { + // Return only the exception, if any + g.Printf("jint") + } + g.Printf(" cproxy_s_%s_%s(", jniName, f.JNIName) + for i, a := range f.Params { + if i > 0 { + g.Printf(", ") + } + g.Printf("%s a%d", a.CType(), i) + } + g.Printf(")") +} + +func (g *ClassGen) genGo(cls *java.Class) { + g.Printf("var class_%s C.jclass\n\n", cls.JNIName) + g.Printf("func init_%s() {\n", cls.JNIName) + g.Indent() + g.Printf("cls := C.CString(%q)\n", strings.Replace(cls.FindName, ".", "/", -1)) + g.Printf("clazz := C.go_seq_find_class(cls)\n") + g.Printf("C.free(unsafe.Pointer(cls))\n") + // Before Go 1.11 clazz was a pointer value, an uintptr after. + g.Printf("if uintptr(clazz) == 0 {\n") + g.Printf(" return\n") + g.Printf("}\n") + g.Printf("class_%s = clazz\n", cls.JNIName) + for _, fs := range cls.Funcs { + var supported bool + for _, f := range fs.Funcs { + if f.Public && g.isFuncSupported(f) { + supported = true + break + } + } + if !supported { + continue + } + g.Printf("%s.%s = func", cls.PkgName, fs.GoName) + g.genFuncDecl(false, fs) + g.genFuncBody(cls, fs, "cproxy_s", true) + } + g.Printf("%s.Cast = func(v interface{}) Java.%s {\n", cls.PkgName, goClsName(cls.Name)) + g.Indent() + g.Printf("t := reflect.TypeOf((*proxy_class_%s)(nil))\n", cls.JNIName) + g.Printf("cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_%s)\n", cls.JNIName) + g.Printf("ref := C.jint(_seq.ToRefNum(cv))\n") + g.Printf("if C.go_seq_isinstanceof(ref, class_%s) != 1 {\n", cls.JNIName) + g.Printf(" panic(fmt.Errorf(\"%%T is not an instance of %%s\", v, %q))\n", cls.Name) + g.Printf("}\n") + g.Printf("return cv\n") + g.Outdent() + g.Printf("}\n") + g.Outdent() + g.Printf("}\n\n") + g.Printf("type proxy_class_%s _seq.Ref\n\n", cls.JNIName) + g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 {\n", cls.JNIName) + g.Indent() + g.Printf("return (*_seq.Ref)(p).Bind_IncNum()\n") + g.Outdent() + g.Printf("}\n\n") + for _, fs := range cls.AllMethods { + if !g.isFuncSetSupported(fs) { + continue + } + g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, fs.GoName) + g.genFuncDecl(false, fs) + g.genFuncBody(cls, fs, "cproxy", false) + } + if cls.Throwable { + g.Printf("func (p *proxy_class_%s) Error() string {\n", cls.JNIName) + g.Printf(" return p.ToString()\n") + g.Printf("}\n") + } + if goName, ok := g.goClsMap[cls.Name]; ok { + g.Printf("func (p *proxy_class_%s) Super() Java.%s {\n", cls.JNIName, goClsName(cls.Name)) + g.Printf(" return &super_%s{p}\n", cls.JNIName) + g.Printf("}\n\n") + g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", cls.JNIName) + g.Printf("func (p *proxy_class_%s) Unwrap() interface{} {\n", cls.JNIName) + g.Indent() + g.Printf("goRefnum := C.go_seq_unwrap(C.jint(p.Bind_proxy_refnum__()))\n") + g.Printf("return _seq.FromRefNum(int32(goRefnum)).Get().(*%s)\n", goName) + g.Outdent() + g.Printf("}\n\n") + for _, fs := range cls.AllMethods { + if !g.isFuncSetSupported(fs) { + continue + } + g.Printf("func (p *super_%s) %s", cls.JNIName, fs.GoName) + g.genFuncDecl(false, fs) + g.genFuncBody(cls, fs, "csuper", false) + } + } +} + +// genFuncBody generated a Go function body for a FuncSet. It resolves overloading dynamically, +// by inspecting the number of arguments (if the FuncSet contains varying parameter counts), +// and their types. +func (g *ClassGen) genFuncBody(cls *java.Class, fs *java.FuncSet, prefix string, static bool) { + maxp := len(fs.Funcs[0].Params) + minp := maxp + // sort the function variants into argument sizes. + buckets := make(map[int][]*java.Func) + numF := 0 + for _, f := range fs.Funcs { + if !g.isFuncSupported(f) { + continue + } + numF++ + n := len(f.Params) + if n < minp { + minp = n + } else if n > maxp { + maxp = n + } + buckets[n] = append(buckets[n], f) + } + g.Printf(" {\n") + g.Indent() + if len(buckets) != 1 { + // Switch over the number of arguments. + g.Printf("switch %d + len(a%d) {\n", minp, minp) + } + for i := minp; i <= maxp; i++ { + funcs := buckets[i] + if len(funcs) == 0 { + continue + } + if len(buckets) != 1 { + g.Printf("case %d:\n", i) + g.Indent() + } + for _, f := range funcs { + if len(funcs) > 1 { + g.Printf("{\n") + g.Indent() + } + var argNames []string + var preds []string + for i, a := range f.Params { + var ct *java.Type + var argName string + if i >= minp { + argName = fmt.Sprintf("a%d[%d]", minp, i-minp) + ct = fs.Params[minp] + } else { + argName = fmt.Sprintf("a%d", i) + ct = fs.Params[i] + } + if !reflect.DeepEqual(ct, a) { + g.Printf("_a%d, ok%d := %s.(%s)\n", i, i, argName, g.goType(a, false)) + argName = fmt.Sprintf("_a%d", i) + preds = append(preds, fmt.Sprintf("ok%d", i)) + } + argNames = append(argNames, argName) + } + if len(preds) > 0 { + g.Printf("if %s {\n", strings.Join(preds, " && ")) + g.Indent() + } + for i, a := range f.Params { + g.genWrite(fmt.Sprintf("__a%d", i), argNames[i], a, modeTransient) + } + g.Printf("res := C.%s_%s_%s(", prefix, cls.JNIName, f.JNIName) + if !static { + g.Printf("C.jint(p.Bind_proxy_refnum__())") + } + for i := range f.Params { + if !static || i > 0 { + g.Printf(", ") + } + g.Printf("__a%d", i) + } + g.Printf(")\n") + g.genFuncRet(fs, f, numF > 1) + if len(preds) > 0 { + g.Outdent() + g.Printf("}\n") + } + if len(funcs) > 1 { + g.Outdent() + g.Printf("}\n") + } + } + if len(buckets) != 1 { + g.Outdent() + } + } + if len(buckets) != 1 { + g.Printf("}\n") + } + if numF > 1 { + g.Printf("panic(\"no overloaded method found for %s.%s that matched the arguments\")\n", cls.Name, fs.Name) + } + g.Outdent() + g.Printf("}\n\n") +} + +func (g *ClassGen) genFuncRet(fs *java.FuncSet, f *java.Func, mustReturn bool) { + if f.Ret != nil { + g.genRead("_res", "res.res", f.Ret, modeRetained) + g.genRefRead("_exc", "res.exc", "error", "proxy_error", true) + } else { + g.genRefRead("_exc", "res", "error", "proxy_error", true) + } + if !fs.Throws { + g.Printf("if (_exc != nil) { panic(_exc) }\n") + if fs.HasRet { + if f.Ret != nil { + g.Printf("return _res\n") + } else { + // The variant doesn't return a value, but the common + // signature does. Use nil as a placeholder return value. + g.Printf("return nil\n") + } + } else if mustReturn { + // If there are overloaded variants, return here to avoid the fallback + // panic generated in genFuncBody. + g.Printf("return\n") + } + } else { + if fs.HasRet { + if f.Ret != nil { + g.Printf("return _res, _exc\n") + } else { + // As above, use a nil placeholder return value. + g.Printf("return nil, _exc\n") + } + } else { + g.Printf("return _exc\n") + } + } +} + +func (g *ClassGen) genRead(to, from string, t *java.Type, mode varMode) { + switch t.Kind { + case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double: + g.Printf("%s := %s(%s)\n", to, g.goType(t, false), from) + case java.Boolean: + g.Printf("%s := %s != C.JNI_FALSE\n", to, from) + case java.String: + g.Printf("%s := decodeString(%s)\n", to, from) + case java.Array: + if t.Elem.Kind != java.Byte { + panic("unsupported array type") + } + g.Printf("%s := toSlice(%s, %v)\n", to, from, mode == modeRetained) + case java.Object: + _, hasProxy := g.imported[t.Class] + g.genRefRead(to, from, g.goType(t, false), "proxy_class_"+flattenName(t.Class), hasProxy) + default: + panic("invalid kind") + } +} + +func (g *ClassGen) genRefRead(to, from string, intfName, proxyName string, hasProxy bool) { + g.Printf("var %s %s\n", to, intfName) + g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", to, from) + g.Printf("if %s_ref != nil {\n", to) + g.Printf(" if %s < 0 { // go object\n", from) + g.Printf(" %s = %s_ref.Get().(%s)\n", to, to, intfName) + g.Printf(" } else { // foreign object\n") + if hasProxy { + g.Printf(" %s = (*%s)(%s_ref)\n", to, proxyName, to) + } else { + g.Printf(" %s = %s_ref\n", to, to) + } + g.Printf(" }\n") + g.Printf("}\n") +} + +func (g *ClassGen) genWrite(dst, v string, t *java.Type, mode varMode) { + switch t.Kind { + case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double: + g.Printf("%s := C.%s(%s)\n", dst, t.CType(), v) + case java.Boolean: + g.Printf("%s := C.jboolean(C.JNI_FALSE)\n", dst) + g.Printf("if %s {\n", v) + g.Printf(" %s = C.jboolean(C.JNI_TRUE)\n", dst) + g.Printf("}\n") + case java.String: + g.Printf("%s := encodeString(%s)\n", dst, v) + case java.Array: + if t.Elem.Kind != java.Byte { + panic("unsupported array type") + } + g.Printf("%s := fromSlice(%s, %v)\n", dst, v, mode == modeRetained) + case java.Object: + g.Printf("var %s C.jint = _seq.NullRefNum\n", dst) + g.Printf("if %s != nil {\n", v) + g.Printf(" %s = C.jint(_seq.ToRefNum(%s))\n", dst, v) + g.Printf("}\n") + default: + panic("invalid kind") + } +} + +// genCRetClear clears the result value from a JNI call if an exception was +// raised. +func (g *ClassGen) genCRetClear(v string, t *java.Type, exc string) { + g.Printf("if (%s != NULL) {\n", exc) + g.Indent() + switch t.Kind { + case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean: + g.Printf("%s = 0;\n", v) + default: + // Assume a nullable type. It will break if we missed a type. + g.Printf("%s = NULL;\n", v) + } + g.Outdent() + g.Printf("}\n") +} + +func (g *ClassGen) genJavaToC(v string, t *java.Type) { + switch t.Kind { + case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean: + g.Printf("%s _%s = %s;\n", t.JNIType(), v, v) + case java.String: + g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", v, v) + case java.Array: + if t.Elem.Kind != java.Byte { + panic("unsupported array type") + } + g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, 1);\n", v, v) + case java.Object: + g.Printf("jint _%s = go_seq_to_refnum(env, %s);\n", v, v) + default: + panic("invalid kind") + } +} + +func (g *ClassGen) genCToJava(v string, t *java.Type) { + switch t.Kind { + case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean: + g.Printf("%s _%s = %s;\n", t.JNIType(), v, v) + case java.String: + g.Printf("jstring _%s = go_seq_to_java_string(env, %s);\n", v, v) + case java.Array: + if t.Elem.Kind != java.Byte { + panic("unsupported array type") + } + g.Printf("jbyteArray _%s = go_seq_to_java_bytearray(env, %s, 0);\n", v, v) + case java.Object: + g.Printf("jobject _%s = go_seq_from_refnum(env, %s, NULL, NULL);\n", v, v) + default: + panic("invalid kind") + } +} + +func goClsName(n string) string { + return initialUpper(strings.Replace(n, ".", "_", -1)) +} + +func (g *ClassGen) genInterface(cls *java.Class) { + g.Printf("type %s interface {\n", goClsName(cls.Name)) + g.Indent() + // Methods + for _, fs := range cls.AllMethods { + if !g.isFuncSetSupported(fs) { + continue + } + g.Printf(fs.GoName) + g.genFuncDecl(true, fs) + g.Printf("\n") + } + if goName, ok := g.goClsMap[cls.Name]; ok { + g.Printf("Super() %s\n", goClsName(cls.Name)) + g.Printf("// Unwrap returns the Go object this Java instance\n") + g.Printf("// is wrapping.\n") + g.Printf("// The return value is a %s, but the delclared type is\n", goName) + g.Printf("// interface{} to avoid import cycles.\n") + g.Printf("Unwrap() interface{}\n") + } + if cls.Throwable { + g.Printf("Error() string\n") + } + g.Outdent() + g.Printf("}\n\n") +} + +// Flatten java class names. "java.package.Class$Inner" is converted to +// "java_package_Class_Inner" +func flattenName(n string) string { + return strings.Replace(strings.Replace(n, ".", "_", -1), "$", "_", -1) +} + +var ( + classesPkgHeader = gobindPreamble + ` +package Java + +// Used to silence this package not used errors +const Dummy = 0 + +` + classesCHeader = gobindPreamble + ` +#include +#include "seq.h" +#include "classes.h" + +` + classesHHeader = gobindPreamble + ` +#include +#include "seq.h" + +extern void init_proxies(); + +` + + javaImplHeader = gobindPreamble + + classesGoHeader = gobindPreamble + ` +package main + +/* +#include // for free() +#include +#include "seq.h" +#include "classes.h" +*/ +import "C" + +import ( + "Java" + _seq "golang.org/x/mobile/bind/seq" +) + +` +) diff --git a/bind/gengo.go b/bind/gengo.go new file mode 100644 index 000000000..8087c7ad2 --- /dev/null +++ b/bind/gengo.go @@ -0,0 +1,593 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bind + +import ( + "bytes" + "fmt" + "go/types" + "strings" +) + +type goGen struct { + *Generator + + // imports is the list of imports, in the form + // "the/package/path" + // + // or + // + // name "the/package/path" + // + // in case of duplicates. + imports []string + // The set of taken import names. + importNames map[string]struct{} + // importMap is a map from packages to their names. The name of a package is the last + // segment of its path, with duplicates resolved by appending a underscore and a unique + // number. + importMap map[*types.Package]string +} + +const ( + goPreamble = gobindPreamble + `// Package main is an autogenerated binder stub for package %[1]s. +// +// autogenerated by gobind -lang=go %[2]s +package main + +/* +#include +#include +#include "seq.h" +#include "%[1]s.h" + +*/ +import "C" + +` +) + +func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { + sig := o.Type().(*types.Signature) + params := sig.Params() + for i := 0; i < params.Len(); i++ { + p := params.At(i) + pn := "param_" + g.paramName(params, i) + g.genRead("_"+pn, pn, p.Type(), modeTransient) + } + + res := sig.Results() + if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) { + g.errorf("functions and methods must return either zero or one values, and optionally an error") + return + } + if res.Len() > 0 { + for i := 0; i < res.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("res_%d", i) + } + g.Printf(" := ") + } + + g.Printf("%s%s(", selectorLHS, o.Name()) + for i := 0; i < params.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("_param_%s", g.paramName(params, i)) + } + g.Printf(")\n") + + for i := 0; i < res.Len(); i++ { + pn := fmt.Sprintf("res_%d", i) + g.genWrite("_"+pn, pn, res.At(i).Type(), modeRetained) + } + if res.Len() > 0 { + g.Printf("return ") + for i := 0; i < res.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("_res_%d", i) + } + g.Printf("\n") + } +} + +func (g *goGen) genWrite(toVar, fromVar string, t types.Type, mode varMode) { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("%s := encodeString(%s)\n", toVar, fromVar) + case types.Bool: + g.Printf("var %s C.%s = 0\n", toVar, g.cgoType(t)) + g.Printf("if %s { %s = 1 }\n", fromVar, toVar) + default: + g.Printf("%s := C.%s(%s)\n", toVar, g.cgoType(t), fromVar) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("%s := fromSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } + case *types.Pointer: + // TODO(crawshaw): test *int + // TODO(crawshaw): test **Generator + switch t := t.Elem().(type) { + case *types.Named: + g.genToRefNum(toVar, fromVar) + default: + g.errorf("unsupported type %s", t) + } + case *types.Named: + switch u := t.Underlying().(type) { + case *types.Interface, *types.Pointer: + g.genToRefNum(toVar, fromVar) + default: + g.errorf("unsupported, direct named type %s: %s", t, u) + } + default: + g.errorf("unsupported type %s", t) + } +} + +// genToRefNum generates Go code for converting a variable to its refnum. +// Note that the nil-check cannot be lifted into seq.ToRefNum, because a nil +// struct pointer does not convert to a nil interface. +func (g *goGen) genToRefNum(toVar, fromVar string) { + g.Printf("var %s C.int32_t = _seq.NullRefNum\n", toVar) + g.Printf("if %s != nil {\n", fromVar) + g.Printf(" %s = C.int32_t(_seq.ToRefNum(%s))\n", toVar, fromVar) + g.Printf("}\n") +} + +func (g *goGen) genFuncSignature(o *types.Func, objName string) { + g.Printf("//export proxy%s_%s_%s\n", g.pkgPrefix, objName, o.Name()) + g.Printf("func proxy%s_%s_%s(", g.pkgPrefix, objName, o.Name()) + if objName != "" { + g.Printf("refnum C.int32_t") + } + sig := o.Type().(*types.Signature) + params := sig.Params() + for i := 0; i < params.Len(); i++ { + if objName != "" || i > 0 { + g.Printf(", ") + } + p := params.At(i) + g.Printf("param_%s C.%s", g.paramName(params, i), g.cgoType(p.Type())) + } + g.Printf(") ") + res := sig.Results() + if res.Len() > 0 { + g.Printf("(") + for i := 0; i < res.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("C.%s", g.cgoType(res.At(i).Type())) + } + g.Printf(") ") + } + g.Printf("{\n") +} + +func (g *goGen) paramName(params *types.Tuple, pos int) string { + return basicParamName(params, pos) +} + +func (g *goGen) genFunc(o *types.Func) { + if !g.isSigSupported(o.Type()) { + g.Printf("// skipped function %s with unsupported parameter or result types\n", o.Name()) + return + } + g.genFuncSignature(o, "") + g.Indent() + g.genFuncBody(o, g.pkgName(g.Pkg)) + g.Outdent() + g.Printf("}\n\n") +} + +func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) { + fields := exportedFields(T) + methods := exportedMethodSet(types.NewPointer(obj.Type())) + + for _, f := range fields { + if t := f.Type(); !g.isSupported(t) { + g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t) + continue + } + g.Printf("//export proxy%s_%s_%s_Set\n", g.pkgPrefix, obj.Name(), f.Name()) + g.Printf("func proxy%s_%s_%s_Set(refnum C.int32_t, v C.%s) {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type())) + g.Indent() + g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") + g.genRead("_v", "v", f.Type(), modeRetained) + g.Printf("ref.Get().(*%s%s).%s = _v\n", g.pkgName(g.Pkg), obj.Name(), f.Name()) + g.Outdent() + g.Printf("}\n\n") + + g.Printf("//export proxy%s_%s_%s_Get\n", g.pkgPrefix, obj.Name(), f.Name()) + g.Printf("func proxy%s_%s_%s_Get(refnum C.int32_t) C.%s {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type())) + g.Indent() + g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") + g.Printf("v := ref.Get().(*%s%s).%s\n", g.pkgName(g.Pkg), obj.Name(), f.Name()) + g.genWrite("_v", "v", f.Type(), modeRetained) + g.Printf("return _v\n") + g.Outdent() + g.Printf("}\n\n") + } + + for _, m := range methods { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) + continue + } + g.genFuncSignature(m, obj.Name()) + g.Indent() + g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") + g.Printf("v := ref.Get().(*%s%s)\n", g.pkgName(g.Pkg), obj.Name()) + g.genFuncBody(m, "v.") + g.Outdent() + g.Printf("}\n\n") + } + // Export constructor for ObjC and Java default no-arg constructors + g.Printf("//export new_%s_%s\n", g.Pkg.Name(), obj.Name()) + g.Printf("func new_%s_%s() C.int32_t {\n", g.Pkg.Name(), obj.Name()) + g.Indent() + g.Printf("return C.int32_t(_seq.ToRefNum(new(%s%s)))\n", g.pkgName(g.Pkg), obj.Name()) + g.Outdent() + g.Printf("}\n") +} + +func (g *goGen) genVar(o *types.Var) { + if t := o.Type(); !g.isSupported(t) { + g.Printf("// skipped variable %s with unsupported type %s\n\n", o.Name(), t) + return + } + // TODO(hyangah): non-struct pointer types (*int), struct type. + + v := fmt.Sprintf("%s%s", g.pkgName(g.Pkg), o.Name()) + + // var I int + // + // func var_setI(v int) + g.Printf("//export var_set%s_%s\n", g.pkgPrefix, o.Name()) + g.Printf("func var_set%s_%s(v C.%s) {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type())) + g.Indent() + g.genRead("_v", "v", o.Type(), modeRetained) + g.Printf("%s = _v\n", v) + g.Outdent() + g.Printf("}\n") + + // func var_getI() int + g.Printf("//export var_get%s_%s\n", g.pkgPrefix, o.Name()) + g.Printf("func var_get%s_%s() C.%s {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type())) + g.Indent() + g.Printf("v := %s\n", v) + g.genWrite("_v", "v", o.Type(), modeRetained) + g.Printf("return _v\n") + g.Outdent() + g.Printf("}\n") +} + +func (g *goGen) genInterface(obj *types.TypeName) { + iface := obj.Type().(*types.Named).Underlying().(*types.Interface) + + summary := makeIfaceSummary(iface) + + // Define the entry points. + for _, m := range summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) + continue + } + g.genFuncSignature(m, obj.Name()) + g.Indent() + g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") + g.Printf("v := ref.Get().(%s%s)\n", g.pkgName(g.Pkg), obj.Name()) + g.genFuncBody(m, "v.") + g.Outdent() + g.Printf("}\n\n") + } + + // Define a proxy interface. + if !summary.implementable { + // The interface defines an unexported method or a method that + // uses an unexported type. We cannot generate a proxy object + // for such a type. + return + } + g.Printf("type proxy%s_%s _seq.Ref\n\n", g.pkgPrefix, obj.Name()) + + g.Printf("func (p *proxy%s_%s) Bind_proxy_refnum__() int32 {\n", g.pkgPrefix, obj.Name()) + g.Indent() + g.Printf("return (*_seq.Ref)(p).Bind_IncNum()\n") + g.Outdent() + g.Printf("}\n\n") + + for _, m := range summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or result types\n", obj.Name(), m.Name()) + continue + } + sig := m.Type().(*types.Signature) + params := sig.Params() + res := sig.Results() + + if res.Len() > 2 || + (res.Len() == 2 && !isErrorType(res.At(1).Type())) { + g.errorf("functions and methods must return either zero or one value, and optionally an error: %s.%s", obj.Name(), m.Name()) + continue + } + + g.Printf("func (p *proxy%s_%s) %s(", g.pkgPrefix, obj.Name(), m.Name()) + for i := 0; i < params.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("param_%s %s", g.paramName(params, i), g.typeString(params.At(i).Type())) + } + g.Printf(") ") + + if res.Len() == 1 { + g.Printf(g.typeString(res.At(0).Type())) + } else if res.Len() == 2 { + g.Printf("(%s, error)", g.typeString(res.At(0).Type())) + } + g.Printf(" {\n") + g.Indent() + + for i := 0; i < params.Len(); i++ { + pn := "param_" + g.paramName(params, i) + g.genWrite("_"+pn, pn, params.At(i).Type(), modeTransient) + } + + if res.Len() > 0 { + g.Printf("res := ") + } + g.Printf("C.cproxy%s_%s_%s(C.int32_t(p.Bind_proxy_refnum__())", g.pkgPrefix, obj.Name(), m.Name()) + for i := 0; i < params.Len(); i++ { + g.Printf(", _param_%s", g.paramName(params, i)) + } + g.Printf(")\n") + var retName string + if res.Len() > 0 { + if res.Len() == 1 { + T := res.At(0).Type() + g.genRead("_res", "res", T, modeRetained) + retName = "_res" + } else { + var rvs []string + for i := 0; i < res.Len(); i++ { + rv := fmt.Sprintf("res_%d", i) + g.genRead(rv, fmt.Sprintf("res.r%d", i), res.At(i).Type(), modeRetained) + rvs = append(rvs, rv) + } + retName = strings.Join(rvs, ", ") + } + g.Printf("return %s\n", retName) + } + g.Outdent() + g.Printf("}\n\n") + } +} + +func (g *goGen) genRead(toVar, fromVar string, typ types.Type, mode varMode) { + switch t := typ.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("%s := decodeString(%s)\n", toVar, fromVar) + case types.Bool: + g.Printf("%s := %s != 0\n", toVar, fromVar) + default: + g.Printf("%s := %s(%s)\n", toVar, t.Underlying().String(), fromVar) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("%s := toSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } + case *types.Pointer: + switch u := t.Elem().(type) { + case *types.Named: + o := u.Obj() + oPkg := o.Pkg() + if !g.validPkg(oPkg) { + g.errorf("type %s is defined in %s, which is not bound", u, oPkg) + return + } + g.Printf("// Must be a Go object\n") + g.Printf("var %s *%s%s\n", toVar, g.pkgName(oPkg), o.Name()) + g.Printf("if %s_ref := _seq.FromRefNum(int32(%s)); %s_ref != nil {\n", toVar, fromVar, toVar) + g.Printf(" %s = %s_ref.Get().(*%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name()) + g.Printf("}\n") + default: + g.errorf("unsupported pointer type %s", t) + } + case *types.Named: + switch t.Underlying().(type) { + case *types.Interface, *types.Pointer: + hasProxy := true + if iface, ok := t.Underlying().(*types.Interface); ok { + hasProxy = makeIfaceSummary(iface).implementable + } + pkgFirst := typePkgFirstElem(t) + isWrapper := pkgFirst == "Java" || pkgFirst == "ObjC" + o := t.Obj() + oPkg := o.Pkg() + if !isErrorType(t) && !g.validPkg(oPkg) && !isWrapper { + g.errorf("type %s is defined in %s, which is not bound", t, oPkg) + return + } + g.Printf("var %s %s\n", toVar, g.typeString(t)) + g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar) + g.Printf("if %s_ref != nil {\n", toVar) + g.Printf(" if %s < 0 { // go object \n", fromVar) + g.Printf(" %s = %s_ref.Get().(%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name()) + if hasProxy { + g.Printf(" } else { // foreign object \n") + if isWrapper { + var clsName string + switch pkgFirst { + case "Java": + clsName = flattenName(classNameFor(t)) + case "ObjC": + clsName = t.Obj().Name() + } + g.Printf(" %s = (*proxy_class_%s)(%s_ref)\n", toVar, clsName, toVar) + } else { + g.Printf(" %s = (*proxy%s_%s)(%s_ref)\n", toVar, pkgPrefix(oPkg), o.Name(), toVar) + } + } + g.Printf(" }\n") + g.Printf("}\n") + default: + g.errorf("unsupported named type %s", t) + } + default: + g.errorf("unsupported type: %s", typ) + } +} + +func (g *goGen) typeString(typ types.Type) string { + pkg := g.Pkg + + switch t := typ.(type) { + case *types.Named: + obj := t.Obj() + if obj.Pkg() == nil { // e.g. error type is *types.Named. + return types.TypeString(typ, types.RelativeTo(pkg)) + } + oPkg := obj.Pkg() + if !g.validPkg(oPkg) && !isWrapperType(t) { + g.errorf("type %s is defined in %s, which is not bound", t, oPkg) + return "TODO" + } + + switch t.Underlying().(type) { + case *types.Interface, *types.Struct: + return fmt.Sprintf("%s%s", g.pkgName(oPkg), types.TypeString(typ, types.RelativeTo(oPkg))) + default: + g.errorf("unsupported named type %s / %T", t, t) + } + case *types.Pointer: + switch t := t.Elem().(type) { + case *types.Named: + return fmt.Sprintf("*%s", g.typeString(t)) + default: + g.errorf("not yet supported, pointer type %s / %T", t, t) + } + default: + return types.TypeString(typ, types.RelativeTo(pkg)) + } + return "" +} + +// genPreamble generates the preamble. It is generated after everything +// else, where we know which bound packages to import. +func (g *goGen) genPreamble() { + pkgName := "" + pkgPath := "" + if g.Pkg != nil { + pkgName = g.Pkg.Name() + pkgPath = g.Pkg.Path() + } else { + pkgName = "universe" + } + g.Printf(goPreamble, pkgName, pkgPath) + g.Printf("import (\n") + g.Indent() + g.Printf("_seq \"golang.org/x/mobile/bind/seq\"\n") + for _, imp := range g.imports { + g.Printf("%s\n", imp) + } + g.Outdent() + g.Printf(")\n\n") +} + +func (g *goGen) gen() error { + g.importNames = make(map[string]struct{}) + g.importMap = make(map[*types.Package]string) + + // Switch to a temporary buffer so the preamble can be + // written last. + oldBuf := g.Printer.Buf + newBuf := new(bytes.Buffer) + g.Printer.Buf = newBuf + g.Printf("// suppress the error if seq ends up unused\n") + g.Printf("var _ = _seq.FromRefNum\n") + + for _, s := range g.structs { + g.genStruct(s.obj, s.t) + } + for _, intf := range g.interfaces { + g.genInterface(intf.obj) + } + for _, v := range g.vars { + g.genVar(v) + } + for _, f := range g.funcs { + g.genFunc(f) + } + // Switch to the original buffer, write the preamble + // and append the rest of the file. + g.Printer.Buf = oldBuf + g.genPreamble() + g.Printer.Buf.Write(newBuf.Bytes()) + if len(g.err) > 0 { + return g.err + } + return nil +} + +// pkgName returns the package name and adds the package to the list of +// imports. +func (g *goGen) pkgName(pkg *types.Package) string { + // The error type has no package + if pkg == nil { + return "" + } + if name, exists := g.importMap[pkg]; exists { + return name + "." + } + i := 0 + pname := pkg.Name() + name := pkg.Name() + for { + if _, exists := g.importNames[name]; !exists { + g.importNames[name] = struct{}{} + g.importMap[pkg] = name + var imp string + if pname != name { + imp = fmt.Sprintf("%s %q", name, pkg.Path()) + } else { + imp = fmt.Sprintf("%q", pkg.Path()) + } + g.imports = append(g.imports, imp) + break + } + i++ + name = fmt.Sprintf("%s_%d", pname, i) + } + g.importMap[pkg] = name + return name + "." +} diff --git a/bind/genjava.go b/bind/genjava.go new file mode 100644 index 000000000..b197640aa --- /dev/null +++ b/bind/genjava.go @@ -0,0 +1,1732 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bind + +import ( + "fmt" + "go/constant" + "go/types" + "html" + "math" + "reflect" + "regexp" + "strings" + + "golang.org/x/mobile/internal/importers/java" +) + +// TODO(crawshaw): disallow basic android java type names in exported symbols. +// TODO(crawshaw): consider introducing Java functions for casting to and from interfaces at runtime. + +type JavaGen struct { + // JavaPkg is the Java package prefix for the generated classes. The prefix is prepended to the Go + // package name to create the full Java package name. + JavaPkg string + + *Generator + + jstructs map[*types.TypeName]*javaClassInfo + clsMap map[string]*java.Class + // Constructors is a map from Go struct types to a list + // of exported constructor functions for the type, on the form + // func New(...) *Type + constructors map[*types.TypeName][]*types.Func +} + +type javaClassInfo struct { + // The Java class this class extends. + extends *java.Class + // All Java classes and interfaces this class extends and implements. + supers []*java.Class + methods map[string]*java.FuncSet + // Does the class need a default no-arg constructor + genNoargCon bool +} + +// Init intializes the embedded Generator and initializes the Java class information +// needed to generate structs that extend Java classes and interfaces. +func (g *JavaGen) Init(classes []*java.Class) { + g.Generator.Init() + g.clsMap = make(map[string]*java.Class) + for _, cls := range classes { + g.clsMap[cls.Name] = cls + } + g.jstructs = make(map[*types.TypeName]*javaClassInfo) + g.constructors = make(map[*types.TypeName][]*types.Func) + for _, s := range g.structs { + classes := embeddedJavaClasses(s.t) + if len(classes) == 0 { + continue + } + inf := &javaClassInfo{ + methods: make(map[string]*java.FuncSet), + genNoargCon: true, // java.lang.Object has a no-arg constructor + } + for _, n := range classes { + cls := g.clsMap[n] + for _, fs := range cls.AllMethods { + hasMeth := false + for _, f := range fs.Funcs { + if !f.Final { + hasMeth = true + } + } + if hasMeth { + inf.methods[fs.GoName] = fs + } + } + inf.supers = append(inf.supers, cls) + if !cls.Interface { + if inf.extends != nil { + g.errorf("%s embeds more than one Java class; only one is allowed.", s.obj) + } + if cls.Final { + g.errorf("%s embeds final Java class %s", s.obj, cls.Name) + } + inf.extends = cls + inf.genNoargCon = cls.HasNoArgCon + } + } + g.jstructs[s.obj] = inf + } + for _, f := range g.funcs { + if t := g.constructorType(f); t != nil { + jinf := g.jstructs[t] + if jinf != nil { + sig := f.Type().(*types.Signature) + jinf.genNoargCon = jinf.genNoargCon && sig.Params().Len() > 0 + } + g.constructors[t] = append(g.constructors[t], f) + } + } +} + +func (j *javaClassInfo) toJavaType(T types.Type) *java.Type { + switch T := T.(type) { + case *types.Basic: + var kind java.TypeKind + switch T.Kind() { + case types.Bool, types.UntypedBool: + kind = java.Boolean + case types.Uint8: + kind = java.Byte + case types.Int16: + kind = java.Short + case types.Int32, types.UntypedRune: // types.Rune + kind = java.Int + case types.Int64, types.UntypedInt: + kind = java.Long + case types.Float32: + kind = java.Float + case types.Float64, types.UntypedFloat: + kind = java.Double + case types.String, types.UntypedString: + kind = java.String + default: + return nil + } + return &java.Type{Kind: kind} + case *types.Slice: + switch e := T.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + return &java.Type{Kind: java.Array, Elem: &java.Type{Kind: java.Byte}} + } + } + return nil + case *types.Named: + if isJavaType(T) { + return &java.Type{Kind: java.Object, Class: classNameFor(T)} + } + } + return nil +} + +// lookupMethod searches the Java class descriptor for a method +// that matches the Go method. +func (j *javaClassInfo) lookupMethod(m *types.Func, hasThis bool) *java.Func { + jm := j.methods[m.Name()] + if jm == nil { + // If an exact match is not found, try the method with trailing underscores + // stripped. This way, name clashes can be avoided when overriding multiple + // overloaded methods from Go. + base := strings.TrimRight(m.Name(), "_") + jm = j.methods[base] + if jm == nil { + return nil + } + } + // A name match was found. Now use the parameter and return types to locate + // the correct variant. + sig := m.Type().(*types.Signature) + params := sig.Params() + // Convert Go parameter types to their Java counterparts, if possible. + var jparams []*java.Type + i := 0 + if hasThis { + i = 1 + } + for ; i < params.Len(); i++ { + jparams = append(jparams, j.toJavaType(params.At(i).Type())) + } + var ret *java.Type + var throws bool + if results := sig.Results(); results.Len() > 0 { + ret = j.toJavaType(results.At(0).Type()) + if results.Len() > 1 { + throws = isErrorType(results.At(1).Type()) + } + } +loop: + for _, f := range jm.Funcs { + if len(f.Params) != len(jparams) { + continue + } + if throws != (f.Throws != "") { + continue + } + if !reflect.DeepEqual(ret, f.Ret) { + continue + } + for i, p := range f.Params { + if !reflect.DeepEqual(p, jparams[i]) { + continue loop + } + } + return f + } + return nil +} + +// ClassNames returns the list of names of the generated Java classes and interfaces. +func (g *JavaGen) ClassNames() []string { + var names []string + for _, s := range g.structs { + names = append(names, g.javaTypeName(s.obj.Name())) + } + for _, iface := range g.interfaces { + names = append(names, g.javaTypeName(iface.obj.Name())) + } + return names +} + +func (g *JavaGen) GenClass(idx int) error { + ns := len(g.structs) + if idx < ns { + s := g.structs[idx] + g.genStruct(s) + } else { + iface := g.interfaces[idx-ns] + g.genInterface(iface) + } + if len(g.err) > 0 { + return g.err + } + return nil +} + +func (g *JavaGen) genProxyImpl(name string) { + g.Printf("private final int refnum;\n\n") + g.Printf("@Override public final int incRefnum() {\n") + g.Printf(" Seq.incGoRef(refnum, this);\n") + g.Printf(" return refnum;\n") + g.Printf("}\n\n") +} + +func (g *JavaGen) genStruct(s structInfo) { + pkgPath := "" + if g.Pkg != nil { + pkgPath = g.Pkg.Path() + } + n := g.javaTypeName(s.obj.Name()) + g.Printf(javaPreamble, g.javaPkgName(g.Pkg), n, g.gobindOpts(), pkgPath) + + fields := exportedFields(s.t) + methods := exportedMethodSet(types.NewPointer(s.obj.Type())) + + var impls []string + jinf := g.jstructs[s.obj] + if jinf != nil { + impls = append(impls, "Seq.GoObject") + for _, cls := range jinf.supers { + if cls.Interface { + impls = append(impls, g.javaTypeName(cls.Name)) + } + } + } else { + impls = append(impls, "Seq.Proxy") + } + + pT := types.NewPointer(s.obj.Type()) + for _, iface := range g.allIntf { + if types.AssignableTo(pT, iface.obj.Type()) { + n := iface.obj.Name() + if p := iface.obj.Pkg(); p != g.Pkg { + if n == JavaClassName(p) { + n = n + "_" + } + n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n) + } else { + n = g.javaTypeName(n) + } + impls = append(impls, n) + } + } + + doc := g.docs[n] + g.javadoc(doc.Doc()) + g.Printf("public final class %s", n) + if jinf != nil { + if jinf.extends != nil { + g.Printf(" extends %s", g.javaTypeName(jinf.extends.Name)) + } + } + if len(impls) > 0 { + g.Printf(" implements %s", strings.Join(impls, ", ")) + } + g.Printf(" {\n") + g.Indent() + + g.Printf("static { %s.touch(); }\n\n", g.className()) + g.genProxyImpl(n) + cons := g.constructors[s.obj] + for _, f := range cons { + if !g.isConsSigSupported(f.Type()) { + g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", n, f.Name()) + continue + } + g.genConstructor(f, n, jinf != nil) + } + if jinf == nil || jinf.genNoargCon { + // constructor for Go instantiated instances. + g.Printf("%s(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }\n\n", n) + if len(cons) == 0 { + // Generate default no-arg constructor + g.Printf("public %s() { this.refnum = __New(); Seq.trackGoRef(refnum, this); }\n\n", n) + g.Printf("private static native int __New();\n\n") + } + } + + for _, f := range fields { + if t := f.Type(); !g.isSupported(t) { + g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", n, f.Name(), t) + continue + } + + fdoc := doc.Member(f.Name()) + g.javadoc(fdoc) + g.Printf("public final native %s get%s();\n", g.javaType(f.Type()), f.Name()) + g.javadoc(fdoc) + g.Printf("public final native void set%s(%s v);\n\n", f.Name(), g.javaType(f.Type())) + } + + var isStringer bool + for _, m := range methods { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name()) + continue + } + g.javadoc(doc.Member(m.Name())) + var jm *java.Func + hasThis := false + if jinf != nil { + hasThis = g.hasThis(n, m) + jm = jinf.lookupMethod(m, hasThis) + if jm != nil { + g.Printf("@Override ") + } + } + g.Printf("public native ") + g.genFuncSignature(m, jm, hasThis) + t := m.Type().(*types.Signature) + isStringer = isStringer || (m.Name() == "String" && t.Params().Len() == 0 && t.Results().Len() == 1 && + types.Identical(t.Results().At(0).Type(), types.Typ[types.String])) + } + + if jinf == nil { + g.genObjectMethods(n, fields, isStringer) + } + + g.Outdent() + g.Printf("}\n\n") +} + +// isConsSigSupported reports whether the generators can handle a given +// constructor signature. +func (g *JavaGen) isConsSigSupported(t types.Type) bool { + if !g.isSigSupported(t) { + return false + } + // Skip constructors taking a single int32 argument + // since they clash with the proxy constructors that + // take a refnum. + params := t.(*types.Signature).Params() + if params.Len() != 1 { + return true + } + if t, ok := params.At(0).Type().(*types.Basic); ok { + switch t.Kind() { + case types.Int32, types.Uint32: + return false + } + } + return true +} + +// javaTypeName returns the class name of a given Go type name. If +// the type name clashes with the package class name, an underscore is +// appended. +func (g *JavaGen) javaTypeName(n string) string { + if n == JavaClassName(g.Pkg) { + return n + "_" + } + return n +} + +func (g *JavaGen) javadoc(doc string) { + if doc == "" { + return + } + // JavaDoc expects HTML-escaped documentation. + g.Printf("/**\n * %s */\n", html.EscapeString(doc)) +} + +// hasThis reports whether a method has an implicit "this" parameter. +func (g *JavaGen) hasThis(sName string, m *types.Func) bool { + sig := m.Type().(*types.Signature) + params := sig.Params() + if params.Len() == 0 { + return false + } + v := params.At(0) + if v.Name() != "this" { + return false + } + t, ok := v.Type().(*types.Named) + if !ok { + return false + } + obj := t.Obj() + pkg := obj.Pkg() + if pkgFirstElem(pkg) != "Java" { + return false + } + clsName := classNameFor(t) + exp := g.javaPkgName(g.Pkg) + "." + sName + if clsName != exp { + g.errorf("the type %s of the `this` argument to method %s.%s is not %s", clsName, sName, m.Name(), exp) + return false + } + return true +} + +func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) { + g.javadoc(g.docs[f.Name()].Doc()) + g.Printf("public %s(", n) + g.genFuncArgs(f, nil, false) + g.Printf(") {\n") + g.Indent() + sig := f.Type().(*types.Signature) + params := sig.Params() + if jcls { + g.Printf("super(") + for i := 0; i < params.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf(g.paramName(params, i)) + } + g.Printf(");\n") + } + g.Printf("this.refnum = ") + g.Printf("__%s(", f.Name()) + for i := 0; i < params.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf(g.paramName(params, i)) + } + g.Printf(");\n") + g.Printf("Seq.trackGoRef(refnum, this);\n") + g.Outdent() + g.Printf("}\n\n") + g.Printf("private static native int __%s(", f.Name()) + g.genFuncArgs(f, nil, false) + g.Printf(");\n\n") +} + +// genFuncArgs generated Java function arguments declaration for the function f. +// If the supplied overridden java function is supplied, genFuncArgs omits the implicit +// this argument. +func (g *JavaGen) genFuncArgs(f *types.Func, jm *java.Func, hasThis bool) { + sig := f.Type().(*types.Signature) + params := sig.Params() + first := 0 + if hasThis { + // Skip the implicit this argument to the Go method + first = 1 + } + for i := first; i < params.Len(); i++ { + if i > first { + g.Printf(", ") + } + v := params.At(i) + name := g.paramName(params, i) + jt := g.javaType(v.Type()) + g.Printf("%s %s", jt, name) + } +} + +func (g *JavaGen) genObjectMethods(n string, fields []*types.Var, isStringer bool) { + g.Printf("@Override public boolean equals(Object o) {\n") + g.Indent() + g.Printf("if (o == null || !(o instanceof %s)) {\n return false;\n}\n", n) + g.Printf("%s that = (%s)o;\n", n, n) + for _, f := range fields { + if t := f.Type(); !g.isSupported(t) { + g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", n, f.Name(), t) + continue + } + nf := f.Name() + g.Printf("%s this%s = get%s();\n", g.javaType(f.Type()), nf, nf) + g.Printf("%s that%s = that.get%s();\n", g.javaType(f.Type()), nf, nf) + if isJavaPrimitive(f.Type()) { + g.Printf("if (this%s != that%s) {\n return false;\n}\n", nf, nf) + } else { + g.Printf("if (this%s == null) {\n", nf) + g.Indent() + g.Printf("if (that%s != null) {\n return false;\n}\n", nf) + g.Outdent() + g.Printf("} else if (!this%s.equals(that%s)) {\n return false;\n}\n", nf, nf) + } + } + g.Printf("return true;\n") + g.Outdent() + g.Printf("}\n\n") + + g.Printf("@Override public int hashCode() {\n") + g.Printf(" return java.util.Arrays.hashCode(new Object[] {") + idx := 0 + for _, f := range fields { + if t := f.Type(); !g.isSupported(t) { + continue + } + if idx > 0 { + g.Printf(", ") + } + idx++ + g.Printf("get%s()", f.Name()) + } + g.Printf("});\n") + g.Printf("}\n\n") + + g.Printf("@Override public String toString() {\n") + g.Indent() + if isStringer { + g.Printf("return string();\n") + } else { + g.Printf("StringBuilder b = new StringBuilder();\n") + g.Printf(`b.append("%s").append("{");`, n) + g.Printf("\n") + for _, f := range fields { + if t := f.Type(); !g.isSupported(t) { + continue + } + n := f.Name() + g.Printf(`b.append("%s:").append(get%s()).append(",");`, n, n) + g.Printf("\n") + } + g.Printf(`return b.append("}").toString();`) + g.Printf("\n") + } + g.Outdent() + g.Printf("}\n") +} + +func (g *JavaGen) genInterface(iface interfaceInfo) { + pkgPath := "" + if g.Pkg != nil { + pkgPath = g.Pkg.Path() + } + g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.javaTypeName(iface.obj.Name()), g.gobindOpts(), pkgPath) + + var exts []string + numM := iface.t.NumMethods() + for _, other := range g.allIntf { + // Only extend interfaces with fewer methods to avoid circular references + if other.t.NumMethods() < numM && types.AssignableTo(iface.t, other.t) { + n := other.obj.Name() + if p := other.obj.Pkg(); p != g.Pkg { + if n == JavaClassName(p) { + n = n + "_" + } + n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n) + } else { + n = g.javaTypeName(n) + } + exts = append(exts, n) + } + } + doc := g.docs[iface.obj.Name()] + g.javadoc(doc.Doc()) + g.Printf("public interface %s", g.javaTypeName(iface.obj.Name())) + if len(exts) > 0 { + g.Printf(" extends %s", strings.Join(exts, ", ")) + } + g.Printf(" {\n") + g.Indent() + + for _, m := range iface.summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name()) + continue + } + g.javadoc(doc.Member(m.Name())) + g.Printf("public ") + g.genFuncSignature(m, nil, false) + } + + g.Printf("\n") + + g.Outdent() + g.Printf("}\n\n") +} + +func isJavaPrimitive(T types.Type) bool { + b, ok := T.(*types.Basic) + if !ok { + return false + } + switch b.Kind() { + case types.Bool, types.Uint8, types.Float32, types.Float64, + types.Int, types.Int8, types.Int16, types.Int32, types.Int64: + return true + } + return false +} + +// jniType returns a string that can be used as a JNI type. +func (g *JavaGen) jniType(T types.Type) string { + switch T := T.(type) { + case *types.Basic: + switch T.Kind() { + case types.Bool, types.UntypedBool: + return "jboolean" + case types.Int: + return "jlong" + case types.Int8: + return "jbyte" + case types.Int16: + return "jshort" + case types.Int32, types.UntypedRune: // types.Rune + return "jint" + case types.Int64, types.UntypedInt: + return "jlong" + case types.Uint8: // types.Byte + // TODO(crawshaw): Java bytes are signed, so this is + // questionable, but vital. + return "jbyte" + // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: + case types.Float32: + return "jfloat" + case types.Float64, types.UntypedFloat: + return "jdouble" + case types.String, types.UntypedString: + return "jstring" + default: + g.errorf("unsupported basic type: %s", T) + return "TODO" + } + case *types.Slice: + return "jbyteArray" + + case *types.Pointer: + if _, ok := T.Elem().(*types.Named); ok { + return g.jniType(T.Elem()) + } + g.errorf("unsupported pointer to type: %s", T) + case *types.Named: + return "jobject" + default: + g.errorf("unsupported jniType: %#+v, %s\n", T, T) + } + return "TODO" +} + +func (g *JavaGen) javaBasicType(T *types.Basic) string { + switch T.Kind() { + case types.Bool, types.UntypedBool: + return "boolean" + case types.Int: + return "long" + case types.Int8: + return "byte" + case types.Int16: + return "short" + case types.Int32, types.UntypedRune: // types.Rune + return "int" + case types.Int64, types.UntypedInt: + return "long" + case types.Uint8: // types.Byte + // TODO(crawshaw): Java bytes are signed, so this is + // questionable, but vital. + return "byte" + // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: + case types.Float32: + return "float" + case types.Float64, types.UntypedFloat: + return "double" + case types.String, types.UntypedString: + return "String" + default: + g.errorf("unsupported basic type: %s", T) + return "TODO" + } +} + +// javaType returns a string that can be used as a Java type. +func (g *JavaGen) javaType(T types.Type) string { + if isErrorType(T) { + // The error type is usually translated into an exception in + // Java, however the type can be exposed in other ways, such + // as an exported field. + return "java.lang.Exception" + } else if isJavaType(T) { + return classNameFor(T) + } + switch T := T.(type) { + case *types.Basic: + return g.javaBasicType(T) + case *types.Slice: + elem := g.javaType(T.Elem()) + return elem + "[]" + + case *types.Pointer: + if _, ok := T.Elem().(*types.Named); ok { + return g.javaType(T.Elem()) + } + g.errorf("unsupported pointer to type: %s", T) + case *types.Named: + n := T.Obj() + nPkg := n.Pkg() + if !isErrorType(T) && !g.validPkg(nPkg) { + g.errorf("type %s is in %s, which is not bound", n.Name(), nPkg) + break + } + // TODO(crawshaw): more checking here + clsName := n.Name() + if nPkg != g.Pkg { + if clsName == JavaClassName(nPkg) { + clsName += "_" + } + return fmt.Sprintf("%s.%s", g.javaPkgName(nPkg), clsName) + } else { + return g.javaTypeName(clsName) + } + default: + g.errorf("unsupported javaType: %#+v, %s\n", T, T) + } + return "TODO" +} + +func (g *JavaGen) genJNIFuncSignature(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) { + sig := o.Type().(*types.Signature) + res := sig.Results() + + var ret string + switch res.Len() { + case 2: + ret = g.jniType(res.At(0).Type()) + case 1: + if isErrorType(res.At(0).Type()) { + ret = "void" + } else { + ret = g.jniType(res.At(0).Type()) + } + case 0: + ret = "void" + default: + g.errorf("too many result values: %s", o) + return + } + + g.Printf("JNIEXPORT %s JNICALL\n", ret) + g.Printf("Java_%s_", g.jniPkgName()) + if sName != "" { + if proxy { + g.Printf(java.JNIMangle(g.className())) + // 0024 is the mangled form of $, for naming inner classes. + g.Printf("_00024proxy%s", sName) + } else { + g.Printf(java.JNIMangle(g.javaTypeName(sName))) + } + } else { + g.Printf(java.JNIMangle(g.className())) + } + g.Printf("_") + if jm != nil { + g.Printf(jm.JNIName) + } else { + oName := javaNameReplacer(lowerFirst(o.Name())) + g.Printf(java.JNIMangle(oName)) + } + g.Printf("(JNIEnv* env, ") + if sName != "" { + g.Printf("jobject __this__") + } else { + g.Printf("jclass _clazz") + } + params := sig.Params() + i := 0 + if isjava && params.Len() > 0 && params.At(0).Name() == "this" { + // Skip the implicit this argument, if any. + i = 1 + } + for ; i < params.Len(); i++ { + g.Printf(", ") + v := sig.Params().At(i) + name := g.paramName(params, i) + jt := g.jniType(v.Type()) + g.Printf("%s %s", jt, name) + } + g.Printf(")") +} + +func (g *JavaGen) jniPkgName() string { + return strings.Replace(java.JNIMangle(g.javaPkgName(g.Pkg)), ".", "_", -1) +} + +var javaLetterDigitRE = regexp.MustCompile(`[0-9a-zA-Z$_]`) + +func (g *JavaGen) paramName(params *types.Tuple, pos int) string { + name := basicParamName(params, pos) + if !javaLetterDigitRE.MatchString(name) { + name = fmt.Sprintf("p%d", pos) + } + return javaNameReplacer(name) +} + +func (g *JavaGen) genFuncSignature(o *types.Func, jm *java.Func, hasThis bool) { + sig := o.Type().(*types.Signature) + res := sig.Results() + + var returnsError bool + var ret string + switch res.Len() { + case 2: + if !isErrorType(res.At(1).Type()) { + g.errorf("second result value must be of type error: %s", o) + return + } + returnsError = true + ret = g.javaType(res.At(0).Type()) + case 1: + if isErrorType(res.At(0).Type()) { + returnsError = true + ret = "void" + } else { + ret = g.javaType(res.At(0).Type()) + } + case 0: + ret = "void" + default: + g.errorf("too many result values: %s", o) + return + } + + g.Printf("%s ", ret) + if jm != nil { + g.Printf(jm.Name) + } else { + g.Printf(javaNameReplacer(lowerFirst(o.Name()))) + } + g.Printf("(") + g.genFuncArgs(o, jm, hasThis) + g.Printf(")") + if returnsError { + if jm != nil { + if jm.Throws == "" { + g.errorf("%s declares an error return value but the overridden method does not throw", o) + return + } + g.Printf(" throws %s", jm.Throws) + } else { + g.Printf(" throws Exception") + } + } + g.Printf(";\n") +} + +func (g *JavaGen) genVar(o *types.Var) { + if t := o.Type(); !g.isSupported(t) { + g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t) + return + } + jType := g.javaType(o.Type()) + + doc := g.docs[o.Name()].Doc() + // setter + g.javadoc(doc) + g.Printf("public static native void set%s(%s v);\n", o.Name(), jType) + + // getter + g.javadoc(doc) + g.Printf("public static native %s get%s();\n\n", jType, o.Name()) +} + +// genCRetClear clears the result value from a JNI call if an exception was +// raised. +func (g *JavaGen) genCRetClear(varName string, t types.Type, exc string) { + g.Printf("if (%s != NULL) {\n", exc) + g.Indent() + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("%s = NULL;\n", varName) + default: + g.Printf("%s = 0;\n", varName) + } + case *types.Slice, *types.Named, *types.Pointer: + g.Printf("%s = NULL;\n", varName) + } + g.Outdent() + g.Printf("}\n") +} + +func (g *JavaGen) genJavaToC(varName string, t types.Type, mode varMode) { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", varName, varName) + default: + g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, %d);\n", varName, varName, toCFlag(mode == modeRetained)) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } + case *types.Named: + switch u := t.Underlying().(type) { + case *types.Interface: + g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName) + default: + g.errorf("unsupported named type: %s / %T", u, u) + } + case *types.Pointer: + g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName) + default: + g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) + } +} + +func (g *JavaGen) genCToJava(toName, fromName string, t types.Type, mode varMode) { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("jstring %s = go_seq_to_java_string(env, %s);\n", toName, fromName) + case types.Bool: + g.Printf("jboolean %s = %s ? JNI_TRUE : JNI_FALSE;\n", toName, fromName) + default: + g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("jbyteArray %s = go_seq_to_java_bytearray(env, %s, %d);\n", toName, fromName, toCFlag(mode == modeRetained)) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } + case *types.Pointer: + // TODO(crawshaw): test *int + // TODO(crawshaw): test **Generator + switch t := t.Elem().(type) { + case *types.Named: + g.genFromRefnum(toName, fromName, t, t.Obj()) + default: + g.errorf("unsupported type %s", t) + } + case *types.Named: + switch t.Underlying().(type) { + case *types.Interface, *types.Pointer: + g.genFromRefnum(toName, fromName, t, t.Obj()) + default: + g.errorf("unsupported, direct named type %s", t) + } + default: + g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName) + } +} + +func (g *JavaGen) genFromRefnum(toName, fromName string, t types.Type, o *types.TypeName) { + oPkg := o.Pkg() + isJava := isJavaType(o.Type()) + if !isErrorType(o.Type()) && !g.validPkg(oPkg) && !isJava { + g.errorf("type %s is defined in package %s, which is not bound", t, oPkg) + return + } + p := pkgPrefix(oPkg) + g.Printf("jobject %s = go_seq_from_refnum(env, %s, ", toName, fromName) + if isJava { + g.Printf("NULL, NULL") + } else { + g.Printf("proxy_class_%s_%s, proxy_class_%s_%s_cons", p, o.Name(), p, o.Name()) + } + g.Printf(");\n") +} + +func (g *JavaGen) gobindOpts() string { + opts := []string{"-lang=java"} + if g.JavaPkg != "" { + opts = append(opts, "-javapkg="+g.JavaPkg) + } + return strings.Join(opts, " ") +} + +var javaNameReplacer = newNameSanitizer([]string{ + "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", + "class", "const", "continue", "default", "do", "double", "else", "enum", + "extends", "final", "finally", "float", "for", "goto", "if", "implements", + "import", "instanceof", "int", "interface", "long", "native", "new", "package", + "private", "protected", "public", "return", "short", "static", "strictfp", + "super", "switch", "synchronized", "this", "throw", "throws", "transient", + "try", "void", "volatile", "while", "false", "null", "true"}) + +func (g *JavaGen) javaPkgName(pkg *types.Package) string { + return JavaPkgName(g.JavaPkg, pkg) +} + +// JavaPkgName returns the Java package name for a Go package +// given a pkg prefix. If the prefix is empty, "go" is used +// instead. +func JavaPkgName(pkgPrefix string, pkg *types.Package) string { + if pkg == nil { + return "go" + } + s := javaNameReplacer(pkg.Name()) + if pkgPrefix == "" { + return s + } + return pkgPrefix + "." + s +} + +func (g *JavaGen) className() string { + return JavaClassName(g.Pkg) +} + +// JavaClassName returns the name of the Java class that +// contains Go package level identifiers. +func JavaClassName(pkg *types.Package) string { + if pkg == nil { + return "Universe" + } + return javaNameReplacer(strings.Title(pkg.Name())) +} + +func (g *JavaGen) genConst(o *types.Const) { + if _, ok := o.Type().(*types.Basic); !ok || !g.isSupported(o.Type()) { + g.Printf("// skipped const %s with unsupported type: %s\n\n", o.Name(), o.Type()) + return + } + // TODO(hyangah): should const names use upper cases + "_"? + // TODO(hyangah): check invalid names. + jType := g.javaType(o.Type()) + val := o.Val().ExactString() + switch b := o.Type().(*types.Basic); b.Kind() { + case types.Int64, types.UntypedInt: + i, exact := constant.Int64Val(o.Val()) + if !exact { + g.errorf("const value %s for %s cannot be represented as %s", val, o.Name(), jType) + return + } + val = fmt.Sprintf("%dL", i) + + case types.Float32: + f, _ := constant.Float32Val(o.Val()) + val = fmt.Sprintf("%gf", f) + + case types.Float64, types.UntypedFloat: + f, _ := constant.Float64Val(o.Val()) + if math.IsInf(f, 0) || math.Abs(f) > math.MaxFloat64 { + g.errorf("const value %s for %s cannot be represented as %s", val, o.Name(), jType) + return + } + val = fmt.Sprintf("%g", f) + } + g.javadoc(g.docs[o.Name()].Doc()) + g.Printf("public static final %s %s = %s;\n", g.javaType(o.Type()), o.Name(), val) +} + +func (g *JavaGen) genJNIField(o *types.TypeName, f *types.Var) { + if t := f.Type(); !g.isSupported(t) { + g.Printf("// skipped field %s with unsupported type: %s\n\n", o.Name(), t) + return + } + n := java.JNIMangle(g.javaTypeName(o.Name())) + // setter + g.Printf("JNIEXPORT void JNICALL\n") + g.Printf("Java_%s_%s_set%s(JNIEnv *env, jobject this, %s v) {\n", g.jniPkgName(), n, java.JNIMangle(f.Name()), g.jniType(f.Type())) + g.Indent() + g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n") + g.genJavaToC("v", f.Type(), modeRetained) + g.Printf("proxy%s_%s_%s_Set(o, _v);\n", g.pkgPrefix, o.Name(), f.Name()) + g.genRelease("v", f.Type(), modeRetained) + g.Outdent() + g.Printf("}\n\n") + + // getter + g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(f.Type())) + g.Printf("Java_%s_%s_get%s(JNIEnv *env, jobject this) {\n", g.jniPkgName(), n, java.JNIMangle(f.Name())) + g.Indent() + g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n") + g.Printf("%s r0 = ", g.cgoType(f.Type())) + g.Printf("proxy%s_%s_%s_Get(o);\n", g.pkgPrefix, o.Name(), f.Name()) + g.genCToJava("_r0", "r0", f.Type(), modeRetained) + g.Printf("return _r0;\n") + g.Outdent() + g.Printf("}\n\n") +} + +func (g *JavaGen) genJNIVar(o *types.Var) { + if t := o.Type(); !g.isSupported(t) { + g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t) + return + } + n := java.JNIMangle(g.javaTypeName(o.Name())) + // setter + g.Printf("JNIEXPORT void JNICALL\n") + g.Printf("Java_%s_%s_set%s(JNIEnv *env, jclass clazz, %s v) {\n", g.jniPkgName(), java.JNIMangle(g.className()), n, g.jniType(o.Type())) + g.Indent() + g.genJavaToC("v", o.Type(), modeRetained) + g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name()) + g.genRelease("v", o.Type(), modeRetained) + g.Outdent() + g.Printf("}\n\n") + + // getter + g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(o.Type())) + g.Printf("Java_%s_%s_get%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.className()), n) + g.Indent() + g.Printf("%s r0 = ", g.cgoType(o.Type())) + g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name()) + g.genCToJava("_r0", "r0", o.Type(), modeRetained) + g.Printf("return _r0;\n") + g.Outdent() + g.Printf("}\n\n") +} + +func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) { + if !g.isConsSigSupported(f.Type()) { + return + } + sig := f.Type().(*types.Signature) + res := sig.Results() + + g.Printf("JNIEXPORT jint JNICALL\n") + g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__"+f.Name())) + params := sig.Params() + for i := 0; i < params.Len(); i++ { + v := params.At(i) + jt := g.jniType(v.Type()) + g.Printf(", %s %s", jt, g.paramName(params, i)) + } + g.Printf(") {\n") + g.Indent() + for i := 0; i < params.Len(); i++ { + name := g.paramName(params, i) + g.genJavaToC(name, params.At(i).Type(), modeTransient) + } + // Constructors always return a mandatory *T and an optional error + if res.Len() == 1 { + g.Printf("int32_t refnum = proxy%s__%s(", g.pkgPrefix, f.Name()) + } else { + g.Printf("struct proxy%s__%s_return res = proxy%s__%s(", g.pkgPrefix, f.Name(), g.pkgPrefix, f.Name()) + } + for i := 0; i < params.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("_%s", g.paramName(params, i)) + } + g.Printf(");\n") + for i := 0; i < params.Len(); i++ { + g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient) + } + // Extract multi returns and handle errors + if res.Len() == 2 { + g.Printf("int32_t refnum = res.r0;\n") + g.genCToJava("_err", "res.r1", res.At(1).Type(), modeRetained) + g.Printf("go_seq_maybe_throw_exception(env, _err);\n") + } + g.Printf("return refnum;\n") + g.Outdent() + g.Printf("}\n\n") +} + +func (g *JavaGen) genJNIFunc(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) { + if !g.isSigSupported(o.Type()) { + n := o.Name() + if sName != "" { + n = sName + "." + n + } + g.Printf("// skipped function %s with unsupported parameter or return types\n\n", n) + return + } + g.genJNIFuncSignature(o, sName, jm, proxy, isjava) + + g.Printf(" {\n") + g.Indent() + g.genJNIFuncBody(o, sName, jm, isjava) + g.Outdent() + g.Printf("}\n\n") +} + +func (g *JavaGen) genJNIFuncBody(o *types.Func, sName string, jm *java.Func, isjava bool) { + sig := o.Type().(*types.Signature) + res := sig.Results() + if sName != "" { + g.Printf("int32_t o = go_seq_to_refnum_go(env, __this__);\n") + } + params := sig.Params() + first := 0 + if isjava && params.Len() > 0 && params.At(0).Name() == "this" { + // Start after the implicit this argument. + first = 1 + g.Printf("int32_t _%s = go_seq_to_refnum(env, __this__);\n", g.paramName(params, 0)) + } + for i := first; i < params.Len(); i++ { + name := g.paramName(params, i) + g.genJavaToC(name, params.At(i).Type(), modeTransient) + } + resPrefix := "" + if res.Len() > 0 { + if res.Len() == 1 { + g.Printf("%s r0 = ", g.cgoType(res.At(0).Type())) + } else { + resPrefix = "res." + g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, sName, o.Name()) + } + } + g.Printf("proxy%s_%s_%s(", g.pkgPrefix, sName, o.Name()) + if sName != "" { + g.Printf("o") + } + // Pass all arguments, including the implicit this argument. + for i := 0; i < params.Len(); i++ { + if i > 0 || sName != "" { + g.Printf(", ") + } + g.Printf("_%s", g.paramName(params, i)) + } + g.Printf(");\n") + for i := first; i < params.Len(); i++ { + g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient) + } + for i := 0; i < res.Len(); i++ { + tn := fmt.Sprintf("_r%d", i) + t := res.At(i).Type() + g.genCToJava(tn, fmt.Sprintf("%sr%d", resPrefix, i), t, modeRetained) + } + // Go backwards so that any exception is thrown before + // the return. + for i := res.Len() - 1; i >= 0; i-- { + t := res.At(i).Type() + if !isErrorType(t) { + g.Printf("return _r%d;\n", i) + } else { + g.Printf("go_seq_maybe_throw_exception(env, _r%d);\n", i) + } + } +} + +// genRelease cleans up arguments that weren't copied in genJavaToC. +func (g *JavaGen) genRelease(varName string, t types.Type, mode varMode) { + switch t := t.(type) { + case *types.Basic: + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + if mode == modeTransient { + g.Printf("go_seq_release_byte_array(env, %s, _%s.ptr);\n", varName, varName) + } + } + } + } +} + +func (g *JavaGen) genMethodInterfaceProxy(oName string, m *types.Func) { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s with unsupported parameter or return types\n\n", oName) + return + } + sig := m.Type().(*types.Signature) + params := sig.Params() + res := sig.Results() + g.genInterfaceMethodSignature(m, oName, false, g.paramName) + g.Indent() + g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", params.Len()) + g.Printf("jobject o = go_seq_from_refnum(env, refnum, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", g.pkgPrefix, oName, g.pkgPrefix, oName) + for i := 0; i < params.Len(); i++ { + pn := g.paramName(params, i) + g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient) + } + if res.Len() > 0 && !isErrorType(res.At(0).Type()) { + t := res.At(0).Type() + g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t)) + } else { + g.Printf("(*env)->CallVoidMethod(env, o, ") + } + g.Printf("mid_%s_%s", oName, m.Name()) + for i := 0; i < params.Len(); i++ { + g.Printf(", _%s", g.paramName(params, i)) + } + g.Printf(");\n") + var retName string + if res.Len() > 0 { + t := res.At(0).Type() + if res.Len() == 2 || isErrorType(t) { + g.Printf("jobject exc = go_seq_get_exception(env);\n") + errType := types.Universe.Lookup("error").Type() + g.genJavaToC("exc", errType, modeRetained) + retName = "_exc" + } + if !isErrorType(t) { + if res.Len() == 2 { + g.genCRetClear("res", t, "exc") + } + g.genJavaToC("res", t, modeRetained) + retName = "_res" + } + + if res.Len() > 1 { + g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name()) + g.Printf(" _res, _exc\n") + g.Printf("};\n") + retName = "sres" + } + } + g.Printf("go_seq_pop_local_frame(env);\n") + if retName != "" { + g.Printf("return %s;\n", retName) + } + g.Outdent() + g.Printf("}\n\n") +} + +func (g *JavaGen) GenH() error { + pkgPath := "" + if g.Pkg != nil { + pkgPath = g.Pkg.Path() + } + g.Printf(hPreamble, g.gobindOpts(), pkgPath, g.className()) + for _, iface := range g.interfaces { + g.Printf("extern jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name()) + g.Printf("extern jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name()) + g.Printf("\n") + for _, m := range iface.summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name()) + continue + } + g.genInterfaceMethodSignature(m, iface.obj.Name(), true, g.paramName) + g.Printf("\n") + } + } + for _, s := range g.structs { + g.Printf("extern jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name()) + g.Printf("extern jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name()) + } + g.Printf("#endif\n") + if len(g.err) > 0 { + return g.err + } + return nil +} + +func (g *JavaGen) jniCallType(t types.Type) string { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.Bool, types.UntypedBool: + return "Boolean" + case types.Int: + return "Long" + case types.Int8, types.Uint8: // types.Byte + return "Byte" + case types.Int16: + return "Short" + case types.Int32, types.UntypedRune: // types.Rune + return "Int" + case types.Int64, types.UntypedInt: + return "Long" + case types.Float32: + return "Float" + case types.Float64, types.UntypedFloat: + return "Double" + case types.String, types.UntypedString: + return "Object" + default: + g.errorf("unsupported basic type: %s", t) + } + case *types.Slice: + return "Object" + case *types.Pointer: + if _, ok := t.Elem().(*types.Named); ok { + return g.jniCallType(t.Elem()) + } + g.errorf("unsupported pointer to type: %s", t) + case *types.Named: + return "Object" + default: + return "Object" + } + return "TODO" +} + +func (g *JavaGen) jniClassSigPrefix(pkg *types.Package) string { + return strings.Replace(g.javaPkgName(pkg), ".", "/", -1) + "/" +} + +func (g *JavaGen) jniSigType(T types.Type) string { + if isErrorType(T) { + return "Ljava/lang/Exception;" + } + switch T := T.(type) { + case *types.Basic: + switch T.Kind() { + case types.Bool, types.UntypedBool: + return "Z" + case types.Int: + return "J" + case types.Int8: + return "B" + case types.Int16: + return "S" + case types.Int32, types.UntypedRune: // types.Rune + return "I" + case types.Int64, types.UntypedInt: + return "J" + case types.Uint8: // types.Byte + return "B" + case types.Float32: + return "F" + case types.Float64, types.UntypedFloat: + return "D" + case types.String, types.UntypedString: + return "Ljava/lang/String;" + default: + g.errorf("unsupported basic type: %s", T) + return "TODO" + } + case *types.Slice: + return "[" + g.jniSigType(T.Elem()) + case *types.Pointer: + if _, ok := T.Elem().(*types.Named); ok { + return g.jniSigType(T.Elem()) + } + g.errorf("unsupported pointer to type: %s", T) + case *types.Named: + return "L" + g.jniClassSigPrefix(T.Obj().Pkg()) + g.javaTypeName(T.Obj().Name()) + ";" + default: + g.errorf("unsupported jniType: %#+v, %s\n", T, T) + } + return "TODO" +} + +func (g *JavaGen) GenC() error { + var pkgName, pkgPath string + if g.Pkg != nil { + pkgName = g.Pkg.Name() + pkgPath = g.Pkg.Path() + } else { + pkgName = "universe" + } + g.Printf(cPreamble, g.gobindOpts(), pkgPath) + g.Printf("#include %q\n", pkgName+".h") + if g.Pkg != nil { + for _, pkg := range g.Pkg.Imports() { + if g.validPkg(pkg) { + g.Printf("#include \"%s.h\"\n", pkg.Name()) + } + } + } + g.Printf("\n") + + for _, iface := range g.interfaces { + g.Printf("jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name()) + g.Printf("jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name()) + for _, m := range iface.summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name()) + continue + } + g.Printf("static jmethodID mid_%s_%s;\n", iface.obj.Name(), m.Name()) + } + } + for _, s := range g.structs { + g.Printf("jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name()) + g.Printf("jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name()) + } + g.Printf("\n") + g.Printf("JNIEXPORT void JNICALL\n") + g.Printf("Java_%s_%s__1init(JNIEnv *env, jclass _unused) {\n", g.jniPkgName(), java.JNIMangle(g.className())) + g.Indent() + g.Printf("jclass clazz;\n") + for _, s := range g.structs { + if jinf, ok := g.jstructs[s.obj]; ok { + // Leave the class and constructor NULL for Java classes with no + // default constructor. + if !jinf.genNoargCon { + continue + } + } + g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(s.obj.Pkg())+g.javaTypeName(s.obj.Name())) + g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, s.obj.Name()) + g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"\", \"(I)V\");\n", g.pkgPrefix, s.obj.Name()) + } + for _, iface := range g.interfaces { + pkg := iface.obj.Pkg() + g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+JavaClassName(pkg)+"$proxy"+iface.obj.Name()) + g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, iface.obj.Name()) + g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"\", \"(I)V\");\n", g.pkgPrefix, iface.obj.Name()) + if isErrorType(iface.obj.Type()) { + // As a special case, Java Exceptions are passed to Go pretending to implement the Go error interface. + // To complete the illusion, use the Throwable.getMessage method for proxied calls to the error.Error method. + g.Printf("clazz = (*env)->FindClass(env, \"java/lang/Throwable\");\n") + g.Printf("mid_error_Error = (*env)->GetMethodID(env, clazz, \"getMessage\", \"()Ljava/lang/String;\");\n") + continue + } + g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+g.javaTypeName(iface.obj.Name())) + for _, m := range iface.summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name()) + continue + } + sig := m.Type().(*types.Signature) + res := sig.Results() + retSig := "V" + if res.Len() > 0 { + if t := res.At(0).Type(); !isErrorType(t) { + retSig = g.jniSigType(t) + } + } + var jniParams string + params := sig.Params() + for i := 0; i < params.Len(); i++ { + jniParams += g.jniSigType(params.At(i).Type()) + } + g.Printf("mid_%s_%s = (*env)->GetMethodID(env, clazz, %q, \"(%s)%s\");\n", + iface.obj.Name(), m.Name(), javaNameReplacer(lowerFirst(m.Name())), jniParams, retSig) + } + g.Printf("\n") + } + g.Outdent() + g.Printf("}\n\n") + for _, f := range g.funcs { + g.genJNIFunc(f, "", nil, false, false) + } + for _, s := range g.structs { + sName := s.obj.Name() + cons := g.constructors[s.obj] + jinf := g.jstructs[s.obj] + for _, f := range cons { + g.genJNIConstructor(f, sName) + } + if len(cons) == 0 && (jinf == nil || jinf.genNoargCon) { + g.Printf("JNIEXPORT jint JNICALL\n") + g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__New")) + g.Indent() + g.Printf("return new_%s_%s();\n", g.pkgPrefix, sName) + g.Outdent() + g.Printf("}\n\n") + } + + for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) { + var jm *java.Func + if jinf != nil { + jm = jinf.lookupMethod(m, g.hasThis(s.obj.Name(), m)) + } + g.genJNIFunc(m, sName, jm, false, jinf != nil) + } + for _, f := range exportedFields(s.t) { + g.genJNIField(s.obj, f) + } + } + for _, iface := range g.interfaces { + for _, m := range iface.summary.callable { + g.genJNIFunc(m, iface.obj.Name(), nil, true, false) + g.genMethodInterfaceProxy(iface.obj.Name(), m) + } + } + for _, v := range g.vars { + g.genJNIVar(v) + } + if len(g.err) > 0 { + return g.err + } + return nil +} + +func (g *JavaGen) GenJava() error { + pkgPath := "" + if g.Pkg != nil { + pkgPath = g.Pkg.Path() + } + g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.className(), g.gobindOpts(), pkgPath) + + g.Printf("public abstract class %s {\n", g.className()) + g.Indent() + g.Printf("static {\n") + g.Indent() + g.Printf("Seq.touch(); // for loading the native library\n") + if g.Pkg != nil { + for _, p := range g.Pkg.Imports() { + if g.validPkg(p) { + g.Printf("%s.%s.touch();\n", g.javaPkgName(p), JavaClassName(p)) + } + } + } + g.Printf("_init();\n") + g.Outdent() + g.Printf("}\n\n") + g.Printf("private %s() {} // uninstantiable\n\n", g.className()) + g.Printf("// touch is called from other bound packages to initialize this package\n") + g.Printf("public static void touch() {}\n\n") + g.Printf("private static native void _init();\n\n") + + for _, iface := range g.interfaces { + n := iface.obj.Name() + g.Printf("private static final class proxy%s", n) + if isErrorType(iface.obj.Type()) { + g.Printf(" extends Exception") + } + g.Printf(" implements Seq.Proxy, %s {\n", g.javaTypeName(n)) + g.Indent() + g.genProxyImpl("proxy" + n) + g.Printf("proxy%s(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }\n\n", n) + + if isErrorType(iface.obj.Type()) { + g.Printf("@Override public String getMessage() { return error(); }\n\n") + } + for _, m := range iface.summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name()) + continue + } + g.Printf("public native ") + g.genFuncSignature(m, nil, false) + } + + g.Outdent() + g.Printf("}\n") + } + + g.Printf("\n") + + for _, c := range g.constants { + g.genConst(c) + } + g.Printf("\n") + for _, v := range g.vars { + g.genVar(v) + } + for _, f := range g.funcs { + if !g.isSigSupported(f.Type()) { + g.Printf("// skipped function %s with unsupported parameter or return types\n\n", f.Name()) + continue + } + g.javadoc(g.docs[f.Name()].Doc()) + g.Printf("public static native ") + g.genFuncSignature(f, nil, false) + } + + g.Outdent() + g.Printf("}\n") + + if len(g.err) > 0 { + return g.err + } + return nil +} + +// embeddedJavaClasses returns the possible empty list of Java types embedded +// in the given struct type. +func embeddedJavaClasses(t *types.Struct) []string { + clsSet := make(map[string]struct{}) + var classes []string + for i := 0; i < t.NumFields(); i++ { + f := t.Field(i) + if !f.Exported() { + continue + } + if t := f.Type(); isJavaType(t) { + cls := classNameFor(t) + if _, exists := clsSet[cls]; !exists { + clsSet[cls] = struct{}{} + classes = append(classes, cls) + } + } + } + return classes +} + +func classNameFor(t types.Type) string { + obj := t.(*types.Named).Obj() + pkg := obj.Pkg() + return strings.Replace(pkg.Path()[len("Java/"):], "/", ".", -1) + "." + obj.Name() +} + +func isJavaType(t types.Type) bool { + return typePkgFirstElem(t) == "Java" +} + +const ( + javaPreamble = gobindPreamble + `// Java class %[1]s.%[2]s is a proxy for talking to a Go program. +// +// autogenerated by gobind %[3]s %[4]s +package %[1]s; + +import go.Seq; + +` + cPreamble = gobindPreamble + `// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind %[1]s %[2]s + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +` + + hPreamble = gobindPreamble + `// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind %[1]s %[2]s + +#ifndef __%[3]s_H__ +#define __%[3]s_H__ + +#include + +` +) diff --git a/bind/genobjc.go b/bind/genobjc.go new file mode 100644 index 000000000..d0982207d --- /dev/null +++ b/bind/genobjc.go @@ -0,0 +1,1428 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bind + +import ( + "fmt" + "go/constant" + "go/types" + "math" + "strings" + + "golang.org/x/mobile/internal/importers/objc" +) + +// TODO(hyangah): handle method name conflicts. +// - struct with SetF method and exported F field. +// - method names conflicting with NSObject methods. e.g. Init +// - interface type with InitWithRef. + +// TODO(hyangah): error code/domain propagation + +type ObjcGen struct { + Prefix string // prefix arg passed by flag. + + *Generator + + // fields set by init. + namePrefix string + // Map of all wrapped Objc types + wrapMap map[string]*objc.Named + // Structs that embeds Objc wrapper types. + ostructs map[*types.TypeName]*objcClassInfo + modules []string + // Constructors is a map from Go struct types to a list + // of exported constructor functions for the type, on the form + // func New(...) *Type + constructors map[*types.TypeName][]*types.Func +} + +type objcClassInfo struct { + // The Objc class this class extends. + extends *objc.Named + // All classes and protocols this class extends and conforms to. + supers []*objc.Named + methods map[string]*objc.Func +} + +func (g *ObjcGen) Init(wrappers []*objc.Named) { + g.Generator.Init() + g.namePrefix = g.namePrefixOf(g.Pkg) + g.wrapMap = make(map[string]*objc.Named) + g.constructors = make(map[*types.TypeName][]*types.Func) + modMap := make(map[string]struct{}) + for _, w := range wrappers { + g.wrapMap[w.GoName] = w + if _, exists := modMap[w.Module]; !exists { + if !w.Generated { + g.modules = append(g.modules, w.Module) + } + modMap[w.Module] = struct{}{} + } + } + if _, exists := modMap["Foundation"]; !exists { + g.modules = append(g.modules, "Foundation") + } + g.ostructs = make(map[*types.TypeName]*objcClassInfo) + for _, s := range g.structs { + embds := embeddedObjcTypes(s.t) + if len(embds) == 0 { + continue + } + inf := &objcClassInfo{ + methods: make(map[string]*objc.Func), + } + for _, n := range embds { + t := g.wrapMap[n] + for _, f := range t.AllMethods { + inf.methods[f.GoName] = f + } + inf.supers = append(inf.supers, t) + if !t.Protocol { + if inf.extends != nil { + g.errorf("%s embeds more than one ObjC class; only one is allowed.", s.obj) + } + inf.extends = t + } + } + g.ostructs[s.obj] = inf + } + for _, f := range g.funcs { + if t := g.constructorType(f); t != nil { + g.constructors[t] = append(g.constructors[t], f) + } + } +} + +func (g *ObjcGen) namePrefixOf(pkg *types.Package) string { + if pkg == nil { + return "Universe" + } + p := g.Prefix + return p + strings.Title(pkg.Name()) +} + +func (g *ObjcGen) GenGoH() error { + var pkgPath string + if g.Pkg != nil { + pkgPath = g.Pkg.Path() + } + g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath) + g.Printf("#ifndef __GO_%s_H__\n", g.pkgName) + g.Printf("#define __GO_%s_H__\n\n", g.pkgName) + g.Printf("#include \n") + g.Printf("#include \n") + + for _, i := range g.interfaces { + if !i.summary.implementable { + continue + } + for _, m := range i.summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", i.obj.Name(), m.Name()) + continue + } + g.genInterfaceMethodSignature(m, i.obj.Name(), true, g.paramName) + g.Printf("\n") + } + } + + g.Printf("#endif\n") + + if len(g.err) > 0 { + return g.err + } + return nil +} + +func (g *ObjcGen) GenH() error { + var pkgPath string + if g.Pkg != nil { + pkgPath = g.Pkg.Path() + } + g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath) + g.Printf("#ifndef __%s_H__\n", g.namePrefix) + g.Printf("#define __%s_H__\n", g.namePrefix) + g.Printf("\n") + for _, m := range g.modules { + g.Printf("@import %s;\n", m) + } + g.Printf("#include \"ref.h\"\n") + if g.Pkg != nil { + g.Printf("#include \"Universe.objc.h\"\n\n") + } + + if g.Pkg != nil { + for _, pkg := range g.Pkg.Imports() { + if g.validPkg(pkg) { + g.Printf("#include %q\n", g.namePrefixOf(pkg)+".objc.h") + } + } + } + g.Printf("\n") + + // Forward declaration of @class and @protocol + for _, s := range g.structs { + g.Printf("@class %s%s;\n", g.namePrefix, s.obj.Name()) + } + for _, i := range g.interfaces { + g.Printf("@protocol %s%s;\n", g.namePrefix, i.obj.Name()) + if i.summary.implementable { + g.Printf("@class %s%s;\n", g.namePrefix, i.obj.Name()) + // Forward declaration for other cases will be handled at the beginning of GenM. + } + } + if len(g.structs) > 0 || len(g.interfaces) > 0 { + g.Printf("\n") + } + + // @interfaces + for _, i := range g.interfaces { + g.genInterfaceH(i.obj, i.t) + g.Printf("\n") + } + for _, s := range g.structs { + g.genStructH(s.obj, s.t) + g.Printf("\n") + } + + // const + // TODO: prefix with k?, or use a class method? + for _, obj := range g.constants { + if _, ok := obj.Type().(*types.Basic); !ok || !g.isSupported(obj.Type()) { + g.Printf("// skipped const %s with unsupported type: %s\n\n", obj.Name(), obj.Type()) + continue + } + g.objcdoc(g.docs[obj.Name()].Doc()) + switch b := obj.Type().(*types.Basic); b.Kind() { + case types.String, types.UntypedString: + g.Printf("FOUNDATION_EXPORT NSString* _Nonnull const %s%s;\n", g.namePrefix, obj.Name()) + default: + g.Printf("FOUNDATION_EXPORT const %s %s%s;\n", g.objcType(obj.Type()), g.namePrefix, obj.Name()) + } + } + if len(g.constants) > 0 { + g.Printf("\n") + } + + // var + if len(g.vars) > 0 { + g.Printf("@interface %s : NSObject\n", g.namePrefix) + for _, obj := range g.vars { + if t := obj.Type(); !g.isSupported(t) { + g.Printf("// skipped variable %s with unsupported type: %s\n\n", obj.Name(), t) + continue + } + objcType := g.objcType(obj.Type()) + g.objcdoc(g.docs[obj.Name()].Doc()) + g.Printf("+ (%s) %s;\n", objcType, objcNameReplacer(lowerFirst(obj.Name()))) + g.Printf("+ (void) set%s:(%s)v;\n", obj.Name(), objcType) + g.Printf("\n") + } + g.Printf("@end\n\n") + } + + // static functions. + for _, obj := range g.funcs { + g.genFuncH(obj) + g.Printf("\n") + } + + for _, i := range g.interfaces { + if i.summary.implementable { + g.Printf("@class %s%s;\n\n", g.namePrefix, i.obj.Name()) + } + } + for _, i := range g.interfaces { + if i.summary.implementable { + // @interface Interface -- similar to what genStructH does. + g.genInterfaceInterface(i.obj, i.summary, true) + g.Printf("\n") + } + } + + g.Printf("#endif\n") + + if len(g.err) > 0 { + return g.err + } + return nil +} + +func (g *ObjcGen) gobindOpts() string { + opts := []string{"-lang=objc"} + if g.Prefix != "" { + opts = append(opts, fmt.Sprintf("-prefix=%q", g.Prefix)) + } + return strings.Join(opts, " ") +} + +func (g *ObjcGen) GenM() error { + var pkgPath string + if g.Pkg != nil { + pkgPath = g.Pkg.Path() + } + g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath) + g.Printf("#include \n") + g.Printf("#include \"seq.h\"\n") + g.Printf("#include \"_cgo_export.h\"\n") + g.Printf("#include %q\n", g.namePrefix+".objc.h") + g.Printf("\n") + + // struct + for _, s := range g.structs { + g.genStructM(s.obj, s.t) + g.Printf("\n") + } + + // interface + var needProxy []*types.TypeName + for _, i := range g.interfaces { + if g.genInterfaceM(i.obj, i.t) { + needProxy = append(needProxy, i.obj) + } + g.Printf("\n") + } + + // const + for _, o := range g.constants { + g.genConstM(o) + } + if len(g.constants) > 0 { + g.Printf("\n") + } + + // vars + if len(g.vars) > 0 { + g.Printf("@implementation %s\n", g.namePrefix) + for _, o := range g.vars { + g.genVarM(o) + } + g.Printf("@end\n\n") + } + + g.Printf("\n") + + for _, obj := range g.funcs { + if !g.isSigSupported(obj.Type()) { + g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name()) + continue + } + g.genFuncM(obj) + g.Printf("\n") + } + + for _, i := range g.interfaces { + for _, m := range i.summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", i.obj.Name(), m.Name()) + continue + } + g.genInterfaceMethodProxy(i.obj, m) + } + } + + g.Printf("__attribute__((constructor)) static void init() {\n") + g.Indent() + g.Printf("init_seq();\n") + g.Outdent() + g.Printf("}\n") + + if len(g.err) > 0 { + return g.err + } + + return nil +} + +func (g *ObjcGen) genVarM(o *types.Var) { + if t := o.Type(); !g.isSupported(t) { + g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t) + return + } + objcType := g.objcType(o.Type()) + + // setter + g.Printf("+ (void) set%s:(%s)v {\n", o.Name(), objcType) + g.Indent() + g.genWrite("v", o.Type(), modeRetained) + g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name()) + g.genRelease("v", o.Type(), modeRetained) + g.Outdent() + g.Printf("}\n\n") + + // getter + g.Printf("+ (%s) %s {\n", objcType, objcNameReplacer(lowerFirst(o.Name()))) + g.Indent() + g.Printf("%s r0 = ", g.cgoType(o.Type())) + g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name()) + g.genRead("_r0", "r0", o.Type(), modeRetained) + g.Printf("return _r0;\n") + g.Outdent() + g.Printf("}\n\n") +} + +func (g *ObjcGen) genConstM(o *types.Const) { + if _, ok := o.Type().(*types.Basic); !ok || !g.isSupported(o.Type()) { + g.Printf("// skipped const %s with unsupported type: %s\n\n", o.Name(), o.Type()) + return + } + cName := fmt.Sprintf("%s%s", g.namePrefix, o.Name()) + objcType := g.objcType(o.Type()) + + switch b := o.Type().(*types.Basic); b.Kind() { + case types.Bool, types.UntypedBool: + v := "NO" + if constant.BoolVal(o.Val()) { + v = "YES" + } + g.Printf("const BOOL %s = %s;\n", cName, v) + + case types.String, types.UntypedString: + g.Printf("NSString* const %s = @%s;\n", cName, o.Val().ExactString()) + + case types.Int, types.Int8, types.Int16, types.Int32: + g.Printf("const %s %s = %s;\n", objcType, cName, o.Val()) + + case types.Int64, types.UntypedInt: + i, exact := constant.Int64Val(o.Val()) + if !exact { + g.errorf("const value %s for %s cannot be represented as %s", o.Val(), o.Name(), objcType) + return + } + if i == math.MinInt64 { + // -9223372036854775808LL does not work because 922337203685477508 is + // larger than max int64. + g.Printf("const int64_t %s = %dLL-1;\n", cName, i+1) + } else { + g.Printf("const int64_t %s = %dLL;\n", cName, i) + } + + case types.Float32, types.Float64, types.UntypedFloat: + f, _ := constant.Float64Val(o.Val()) + if math.IsInf(f, 0) || math.Abs(f) > math.MaxFloat64 { + g.errorf("const value %s for %s cannot be represented as double", o.Val(), o.Name()) + return + } + g.Printf("const %s %s = %g;\n", objcType, cName, f) + + default: + g.errorf("unsupported const type %s for %s", b, o.Name()) + } +} + +type funcSummary struct { + name string + goname string + ret string + sig *types.Signature + params, retParams []paramInfo + hasself bool + initName string +} + +type paramInfo struct { + typ types.Type + name string +} + +func (g *ObjcGen) funcSummary(obj *types.TypeName, f *types.Func) *funcSummary { + sig := f.Type().(*types.Signature) + s := &funcSummary{goname: f.Name(), sig: sig} + var om *objc.Func + var sigElems []string + oinf := g.ostructs[obj] + if oinf != nil { + om = oinf.methods[f.Name()] + } + if om != nil { + sigElems = strings.Split(om.Sig, ":") + s.name = sigElems[0] + } else { + s.name = f.Name() + } + params := sig.Params() + first := 0 + if oinf != nil { + if params.Len() > 0 { + v := params.At(0) + if v.Name() == "self" { + t := v.Type() + if t, ok := t.(*types.Named); ok { + if pkg := t.Obj().Pkg(); pkgFirstElem(pkg) == "ObjC" { + s.hasself = true + module := pkg.Path()[len("ObjC/"):] + typName := module + "." + t.Obj().Name() + exp := g.namePrefix + "." + obj.Name() + if typName != exp { + g.errorf("the type %s of the `this` argument to method %s is not %s", typName, f.Name(), exp) + } + } + } + } + } + } + for i := first; i < params.Len(); i++ { + p := params.At(i) + v := paramInfo{ + typ: p.Type(), + } + if om != nil { + v.name = sigElems[i-first] + } else { + v.name = g.paramName(params, i) + } + s.params = append(s.params, v) + } + if obj != nil { + if pref := "New" + obj.Name(); strings.Index(f.Name(), pref) != -1 { + s.initName = "init" + f.Name()[len(pref):] + } + } + res := sig.Results() + switch res.Len() { + case 0: + s.ret = "void" + case 1: + p := res.At(0) + if isErrorType(p.Type()) { + s.retParams = append(s.retParams, paramInfo{ + typ: p.Type(), + name: "error", + }) + s.ret = "BOOL" + } else { + name := p.Name() + if name == "" || paramRE.MatchString(name) { + name = "ret0_" + } + typ := p.Type() + s.retParams = append(s.retParams, paramInfo{typ: typ, name: name}) + s.ret = g.objcType(typ) + } + case 2: + name := res.At(0).Name() + if name == "" || paramRE.MatchString(name) { + name = "ret0_" + } + typ := res.At(0).Type() + s.retParams = append(s.retParams, paramInfo{ + typ: typ, + name: name, + }) + if isNullableType(typ) { + s.ret = g.objcType(typ) // Return is nullable, so satisfies the ObjC/Swift error protocol + } else { + s.ret = "BOOL" // Return is not nullable, must use an output parameter and return bool + } + + if !isErrorType(res.At(1).Type()) { + g.errorf("second result value must be of type error: %s", f) + return nil + } + s.retParams = append(s.retParams, paramInfo{ + typ: res.At(1).Type(), + name: "error", // TODO(hyangah): name collision check. + }) + default: + // TODO(hyangah): relax the constraint on multiple return params. + g.errorf("too many result values: %s", f) + return nil + } + + return s +} + +func (s *funcSummary) asFunc(g *ObjcGen) string { + var params []string + for _, p := range s.params { + params = append(params, g.objcParamType(p.typ)+" "+p.name) + } + skip := 0 + if s.returnsVal() { + skip = 1 + } + for _, p := range s.retParams[skip:] { + params = append(params, g.objcType(p.typ)+"* _Nullable "+p.name) + } + paramContents := "void" + if len(params) > 0 { + paramContents = strings.Join(params, ", ") + } + return fmt.Sprintf("%s %s%s(%s)", s.ret, g.namePrefix, s.name, paramContents) +} + +func (s *funcSummary) asMethod(g *ObjcGen) string { + return fmt.Sprintf("(%s)%s%s", s.ret, objcNameReplacer(lowerFirst(s.name)), s.asSignature(g)) +} + +func (s *funcSummary) asSignature(g *ObjcGen) string { + var params []string + skip := 0 + if s.hasself { + skip = 1 + } + for i, p := range s.params[skip:] { + var key string + if i != 0 { + key = p.name + } + params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcParamType(p.typ), p.name)) + } + skip = 0 + if s.returnsVal() { + skip = 1 + } + for _, p := range s.retParams[skip:] { + var key string + if len(params) > 0 { + key = p.name + } + params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ)+"* _Nullable", p.name)) + } + return strings.Join(params, " ") +} + +func (s *funcSummary) asInitSignature(g *ObjcGen) string { + var params []string + for i, p := range s.params { + var key string + if i > 0 { + key = p.name + } + params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcParamType(p.typ), p.name)) + } + return strings.Join(params, " ") +} + +func (s *funcSummary) callMethod(g *ObjcGen) string { + var params []string + for i, p := range s.params { + var key string + if i != 0 { + key = p.name + } + params = append(params, fmt.Sprintf("%s:_%s", key, p.name)) + } + skip := 0 + if s.returnsVal() { + skip = 1 + } + for _, p := range s.retParams[skip:] { + var key string + if len(params) > 0 { + key = p.name + } + params = append(params, fmt.Sprintf("%s:&%s", key, p.name)) + } + return fmt.Sprintf("%s%s", objcNameReplacer(lowerFirst(s.name)), strings.Join(params, " ")) +} + +func (s *funcSummary) returnsVal() bool { + return (len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ)) || (len(s.retParams) == 2 && isNullableType(s.retParams[0].typ)) +} + +func (g *ObjcGen) paramName(params *types.Tuple, pos int) string { + name := basicParamName(params, pos) + return objcNameReplacer(name) +} + +func (g *ObjcGen) genFuncH(obj *types.Func) { + if !g.isSigSupported(obj.Type()) { + g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name()) + return + } + if s := g.funcSummary(nil, obj); s != nil { + g.objcdoc(g.docs[obj.Name()].Doc()) + g.Printf("FOUNDATION_EXPORT %s;\n", s.asFunc(g)) + } +} + +func (g *ObjcGen) genFuncM(obj *types.Func) { + s := g.funcSummary(nil, obj) + if s == nil { + return + } + g.Printf("%s {\n", s.asFunc(g)) + g.Indent() + g.genFunc(s, "") + g.Outdent() + g.Printf("}\n") +} + +func (g *ObjcGen) genGetter(oName string, f *types.Var) { + t := f.Type() + g.Printf("- (%s)%s {\n", g.objcType(t), objcNameReplacer(lowerFirst(f.Name()))) + g.Indent() + g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") + g.Printf("%s r0 = ", g.cgoType(f.Type())) + g.Printf("proxy%s_%s_%s_Get(refnum);\n", g.pkgPrefix, oName, f.Name()) + g.genRead("_r0", "r0", f.Type(), modeRetained) + g.Printf("return _r0;\n") + g.Outdent() + g.Printf("}\n\n") +} + +func (g *ObjcGen) genSetter(oName string, f *types.Var) { + t := f.Type() + + g.Printf("- (void)set%s:(%s)v {\n", f.Name(), g.objcType(t)) + g.Indent() + g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") + g.genWrite("v", f.Type(), modeRetained) + g.Printf("proxy%s_%s_%s_Set(refnum, _v);\n", g.pkgPrefix, oName, f.Name()) + g.genRelease("v", f.Type(), modeRetained) + g.Outdent() + g.Printf("}\n\n") +} + +func (g *ObjcGen) genWrite(varName string, t types.Type, mode varMode) { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("nstring _%s = go_seq_from_objc_string(%s);\n", varName, varName) + default: + g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("nbyteslice _%s = go_seq_from_objc_bytearray(%s, %d);\n", varName, varName, toCFlag(mode == modeRetained)) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } + case *types.Named: + switch u := t.Underlying().(type) { + case *types.Interface: + g.genRefWrite(varName) + default: + g.errorf("unsupported named type: %s / %T", u, u) + } + case *types.Pointer: + g.genRefWrite(varName) + default: + g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) + } +} + +func (g *ObjcGen) genRefWrite(varName string) { + g.Printf("int32_t _%s;\n", varName) + g.Printf("if ([%s conformsToProtocol:@protocol(goSeqRefInterface)]) {\n", varName) + g.Indent() + g.Printf("id %[1]s_proxy = (id)(%[1]s);\n", varName) + g.Printf("_%s = go_seq_go_to_refnum(%s_proxy._ref);\n", varName, varName) + g.Outdent() + g.Printf("} else {\n") + g.Indent() + g.Printf("_%s = go_seq_to_refnum(%s);\n", varName, varName) + g.Outdent() + g.Printf("}\n") +} + +func (g *ObjcGen) genRefRead(toName, fromName string, t types.Type) { + ptype := g.refTypeBase(t) + g.Printf("%s* %s = nil;\n", ptype, toName) + g.Printf("GoSeqRef* %s_ref = go_seq_from_refnum(%s);\n", toName, fromName) + g.Printf("if (%s_ref != NULL) {\n", toName) + g.Printf(" %s = %s_ref.obj;\n", toName, toName) + g.Printf(" if (%s == nil) {\n", toName) + if isObjcType(t) { + g.Printf(" LOG_FATAL(@\"unexpected NULL reference\");\n") + } else { + g.Printf(" %s = [[%s alloc] initWithRef:%s_ref];\n", toName, ptype, toName) + } + g.Printf(" }\n") + g.Printf("}\n") +} + +func (g *ObjcGen) genRead(toName, fromName string, t types.Type, mode varMode) { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("NSString *%s = go_seq_to_objc_string(%s);\n", toName, fromName) + case types.Bool: + g.Printf("BOOL %s = %s ? YES : NO;\n", toName, fromName) + default: + g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("NSData *%s = go_seq_to_objc_bytearray(%s, %d);\n", toName, fromName, toCFlag(mode == modeRetained)) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } + case *types.Pointer: + switch t := t.Elem().(type) { + case *types.Named: + g.genRefRead(toName, fromName, types.NewPointer(t)) + default: + g.errorf("unsupported type %s", t) + } + case *types.Named: + switch t.Underlying().(type) { + case *types.Interface, *types.Pointer: + g.genRefRead(toName, fromName, t) + default: + g.errorf("unsupported, direct named type %s", t) + } + default: + g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName) + } +} + +func (g *ObjcGen) genFunc(s *funcSummary, objName string) { + skip := 0 + if objName != "" { + g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") + if s.hasself { + skip = 1 + g.Printf("int32_t _self = go_seq_to_refnum(self);\n") + } + } + for _, p := range s.params[skip:] { + g.genWrite(p.name, p.typ, modeTransient) + } + resPrefix := "" + if len(s.retParams) > 0 { + if len(s.retParams) == 1 { + g.Printf("%s r0 = ", g.cgoType(s.retParams[0].typ)) + } else { + resPrefix = "res." + g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, objName, s.goname) + } + } + g.Printf("proxy%s_%s_%s(", g.pkgPrefix, objName, s.goname) + if objName != "" { + g.Printf("refnum") + if s.hasself { + g.Printf(", _self") + } + } + for i, p := range s.params[skip:] { + if i > 0 || objName != "" { + g.Printf(", ") + } + g.Printf("_%s", p.name) + } + g.Printf(");\n") + for _, p := range s.params { + g.genRelease(p.name, p.typ, modeTransient) + } + + for i, r := range s.retParams { + g.genRead("_"+r.name, fmt.Sprintf("%sr%d", resPrefix, i), r.typ, modeRetained) + } + skip = 0 + if s.returnsVal() { + skip = 1 + } + for _, p := range s.retParams[skip:] { + if isErrorType(p.typ) { + g.Printf("if (_%s != nil && %s != nil) {\n", p.name, p.name) + g.Indent() + g.Printf("*%s = _%s;\n", p.name, p.name) + g.Outdent() + g.Printf("}\n") + } else { + g.Printf("*%s = _%s;\n", p.name, p.name) + } + } + + if n := len(s.retParams); n > 0 { + var ( + first = s.retParams[0] + last = s.retParams[n-1] + ) + if (n == 1 && isErrorType(last.typ)) || (n == 2 && !isNullableType(first.typ) && isErrorType(last.typ)) { + g.Printf("return (_%s == nil);\n", last.name) + } else { + if s.returnsVal() && isErrorType(last.typ) { + g.Printf("if (_%s != nil) {\n", last.name) + g.Indent() + g.Printf("return nil;\n") + g.Outdent() + g.Printf("}\n") + } + g.Printf("return _%s;\n", first.name) + } + } +} + +func (g *ObjcGen) genInterfaceInterface(obj *types.TypeName, summary ifaceSummary, isProtocol bool) { + doc := g.docs[obj.Name()] + g.objcdoc(doc.Doc()) + g.Printf("@interface %[1]s%[2]s : ", g.namePrefix, obj.Name()) + if isErrorType(obj.Type()) { + g.Printf("NSError") + } else { + g.Printf("NSObject") + } + prots := []string{"goSeqRefInterface"} + if isProtocol { + prots = append(prots, fmt.Sprintf("%[1]s%[2]s", g.namePrefix, obj.Name())) + } + g.Printf(" <%s>", strings.Join(prots, ", ")) + g.Printf(" {\n}\n") + g.Printf("@property(strong, readonly) _Nonnull id _ref;\n") + g.Printf("\n") + g.Printf("- (nonnull instancetype)initWithRef:(_Nonnull id)ref;\n") + for _, m := range summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) + continue + } + s := g.funcSummary(nil, m) + g.objcdoc(doc.Member(m.Name())) + g.Printf("- %s;\n", s.asMethod(g)) + } + g.Printf("@end\n") +} + +func (g *ObjcGen) genInterfaceH(obj *types.TypeName, t *types.Interface) { + doc := g.docs[obj.Name()] + summary := makeIfaceSummary(t) + if !summary.implementable { + g.genInterfaceInterface(obj, summary, false) + return + } + g.Printf("@protocol %s%s \n", g.namePrefix, obj.Name()) + for _, m := range makeIfaceSummary(t).callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) + continue + } + s := g.funcSummary(nil, m) + g.objcdoc(doc.Member(m.Name())) + g.Printf("- %s;\n", s.asMethod(g)) + } + g.Printf("@end\n") +} + +func (g *ObjcGen) genInterfaceM(obj *types.TypeName, t *types.Interface) bool { + summary := makeIfaceSummary(t) + + // @implementation Interface -- similar to what genStructM does. + g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) + g.Printf("}\n") + g.Printf("\n") + g.Printf("- (nonnull instancetype)initWithRef:(id)ref {\n") + g.Indent() + if isErrorType(obj.Type()) { + g.Printf("if (self) {\n") + g.Printf(" __ref = ref;\n") + g.Printf(" self = [super initWithDomain:@\"go\" code:1 userInfo:@{NSLocalizedDescriptionKey: [self error]}];\n") + g.Printf("}\n") + } else { + g.Printf("self = [super init];\n") + g.Printf("if (self) { __ref = ref; }\n") + } + g.Printf("return self;\n") + g.Outdent() + g.Printf("}\n") + g.Printf("\n") + + for _, m := range summary.callable { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) + continue + } + s := g.funcSummary(nil, m) + g.Printf("- %s {\n", s.asMethod(g)) + g.Indent() + g.genFunc(s, obj.Name()) + g.Outdent() + g.Printf("}\n\n") + } + g.Printf("@end\n") + g.Printf("\n") + + return summary.implementable +} + +func (g *ObjcGen) genInterfaceMethodProxy(obj *types.TypeName, m *types.Func) { + oName := obj.Name() + s := g.funcSummary(nil, m) + g.genInterfaceMethodSignature(m, oName, false, g.paramName) + g.Indent() + g.Printf("@autoreleasepool {\n") + g.Indent() + g.Printf("%s* o = go_seq_objc_from_refnum(refnum);\n", g.refTypeBase(obj.Type())) + for _, p := range s.params { + g.genRead("_"+p.name, p.name, p.typ, modeTransient) + } + + // call method + for _, p := range s.retParams { + if isErrorType(p.typ) { + g.Printf("NSError* %s = nil;\n", p.name) + } else { + g.Printf("%s %s;\n", g.objcType(p.typ), p.name) + } + } + + if isErrorType(obj.Type()) && m.Name() == "Error" { + // As a special case, ObjC NSErrors are passed to Go pretending to implement the Go error interface. + // They don't actually have an Error method, so calls to to it needs to be rerouted. + g.Printf("%s = [o localizedDescription];\n", s.retParams[0].name) + } else { + if s.ret == "void" { + g.Printf("[o %s];\n", s.callMethod(g)) + } else if !s.returnsVal() { + g.Printf("%s returnVal = [o %s];\n", s.ret, s.callMethod(g)) + } else { + g.Printf("%s = [o %s];\n", s.retParams[0].name, s.callMethod(g)) + } + } + + if len(s.retParams) > 0 { + if len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ) { + p := s.retParams[0] + g.genWrite(p.name, p.typ, modeRetained) + g.Printf("return _%s;\n", p.name) + } else { + var rets []string + for _, p := range s.retParams { + if isErrorType(p.typ) { + g.Printf("NSError *_%s = nil;\n", p.name) + if !s.returnsVal() { + g.Printf("if (!returnVal) {\n") + } else { + g.Printf("if (%s != nil) {\n", p.name) + } + g.Indent() + g.Printf("_%[1]s = %[1]s;\n", p.name) + g.Outdent() + g.Printf("}\n") + g.genWrite("_"+p.name, p.typ, modeRetained) + rets = append(rets, "__"+p.name) + } else { + g.genWrite(p.name, p.typ, modeRetained) + rets = append(rets, "_"+p.name) + } + } + if len(rets) > 1 { + g.Printf("cproxy%s_%s_%s_return _sres = {\n", g.pkgPrefix, oName, m.Name()) + g.Printf(" %s\n", strings.Join(rets, ", ")) + g.Printf("};\n") + g.Printf("return _sres;\n") + } else { + g.Printf("return %s;\n", rets[0]) + } + } + } + g.Outdent() + g.Printf("}\n") + g.Outdent() + g.Printf("}\n\n") +} + +// genRelease cleans up arguments that weren't copied in genWrite. +func (g *ObjcGen) genRelease(varName string, t types.Type, mode varMode) { + switch t := t.(type) { + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + if mode == modeTransient { + // If the argument was not mutable, go_seq_from_objc_bytearray created a copy. + // Free it here. + g.Printf("if (![%s isKindOfClass:[NSMutableData class]]) {\n", varName) + g.Printf(" free(_%s.ptr);\n", varName) + g.Printf("}\n") + } + } + } + } +} + +func (g *ObjcGen) genStructH(obj *types.TypeName, t *types.Struct) { + doc := g.docs[obj.Name()] + g.objcdoc(doc.Doc()) + g.Printf("@interface %s%s : ", g.namePrefix, obj.Name()) + oinf := g.ostructs[obj] + var prots []string + if oinf != nil { + for _, sup := range oinf.supers { + if !sup.Protocol { + g.Printf(sup.Name) + } else { + prots = append(prots, sup.Name) + } + } + } else { + g.Printf("NSObject") + prots = append(prots, "goSeqRefInterface") + } + pT := types.NewPointer(obj.Type()) + for _, iface := range g.allIntf { + p := iface.obj.Pkg() + if g.Pkg != nil && g.Pkg != p { + // To avoid header include cycles, only declare implementation of interfaces + // from imported packages. TODO(elias.naur): Include every interface that + // doesn't introduce an include cycle. + found := false + for _, imp := range g.Pkg.Imports() { + if imp == p { + found = true + break + } + } + if !found { + continue + } + } + obj := iface.obj + if types.AssignableTo(pT, obj.Type()) { + n := fmt.Sprintf("%s%s", g.namePrefixOf(obj.Pkg()), obj.Name()) + prots = append(prots, n) + } + } + + if len(prots) > 0 { + g.Printf(" <%s>", strings.Join(prots, ", ")) + } + g.Printf(" {\n") + g.Printf("}\n") + g.Printf("@property(strong, readonly) _Nonnull id _ref;\n") + g.Printf("\n") + g.Printf("- (nonnull instancetype)initWithRef:(_Nonnull id)ref;\n") + cons := g.constructors[obj] + if oinf == nil { + for _, f := range cons { + if !g.isSigSupported(f.Type()) { + g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", obj.Name(), f.Name()) + continue + } + g.genInitH(obj, f) + } + } + if oinf != nil || len(cons) == 0 { + // default constructor won't return nil + g.Printf("- (nonnull instancetype)init;\n") + } + + // accessors to exported fields. + for _, f := range exportedFields(t) { + if t := f.Type(); !g.isSupported(t) { + g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t) + continue + } + name, typ := f.Name(), g.objcType(f.Type()) + g.objcdoc(doc.Member(f.Name())) + + // properties are atomic by default so explicitly say otherwise + g.Printf("@property (nonatomic) %s %s;\n", typ, objcNameReplacer(lowerFirst(name))) + } + + // exported methods + for _, m := range exportedMethodSet(types.NewPointer(obj.Type())) { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) + continue + } + s := g.funcSummary(obj, m) + g.objcdoc(doc.Member(m.Name())) + g.Printf("- %s;\n", s.asMethod(g)) + } + g.Printf("@end\n") +} + +func (g *ObjcGen) objcdoc(doc string) { + if doc == "" { + return + } + g.Printf("/**\n * %s */\n", doc) +} + +func (g *ObjcGen) genStructM(obj *types.TypeName, t *types.Struct) { + fields := exportedFields(t) + methods := exportedMethodSet(types.NewPointer(obj.Type())) + + g.Printf("\n") + oinf := g.ostructs[obj] + g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) + g.Printf("}\n\n") + g.Printf("- (nonnull instancetype)initWithRef:(_Nonnull id)ref {\n") + g.Indent() + g.Printf("self = [super init];\n") + g.Printf("if (self) { __ref = ref; }\n") + g.Printf("return self;\n") + g.Outdent() + g.Printf("}\n\n") + cons := g.constructors[obj] + if oinf == nil { + for _, f := range cons { + if !g.isSigSupported(f.Type()) { + g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", obj, f.Name()) + continue + } + g.genInitM(obj, f) + } + } + if oinf != nil || len(cons) == 0 { + g.Printf("- (nonnull instancetype)init {\n") + g.Indent() + g.Printf("self = [super init];\n") + g.Printf("if (self) {\n") + g.Indent() + g.Printf("__ref = go_seq_from_refnum(new_%s_%s());\n", g.pkgPrefix, obj.Name()) + g.Outdent() + g.Printf("}\n") + g.Printf("return self;\n") + g.Outdent() + g.Printf("}\n\n") + } + + for _, f := range fields { + if !g.isSupported(f.Type()) { + g.Printf("// skipped unsupported field %s with type %s\n\n", f.Name(), f.Type()) + continue + } + g.genGetter(obj.Name(), f) + g.genSetter(obj.Name(), f) + } + + for _, m := range methods { + if !g.isSigSupported(m.Type()) { + g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) + continue + } + s := g.funcSummary(obj, m) + g.Printf("- %s {\n", s.asMethod(g)) + g.Indent() + g.genFunc(s, obj.Name()) + g.Outdent() + g.Printf("}\n\n") + } + g.Printf("@end\n\n") +} + +func (g *ObjcGen) genInitH(obj *types.TypeName, f *types.Func) { + s := g.funcSummary(obj, f) + doc := g.docs[f.Name()] + g.objcdoc(doc.Doc()) + + // custom inits can return nil in Go so make them nullable + g.Printf("- (nullable instancetype)%s%s;\n", s.initName, s.asInitSignature(g)) +} + +func (g *ObjcGen) genInitM(obj *types.TypeName, f *types.Func) { + s := g.funcSummary(obj, f) + g.Printf("- (instancetype)%s%s {\n", s.initName, s.asInitSignature(g)) + g.Indent() + g.Printf("self = [super init];\n") + g.Printf("if (!self) return nil;\n") + for _, p := range s.params { + g.genWrite(p.name, p.typ, modeTransient) + } + // Constructors always return a mandatory *T and an optional error + if len(s.retParams) == 1 { + g.Printf("%s refnum = ", g.cgoType(s.retParams[0].typ)) + } else { + g.Printf("struct proxy%s__%s_return res = ", g.pkgPrefix, s.goname) + } + g.Printf("proxy%s__%s(", g.pkgPrefix, s.goname) + for i, p := range s.params { + if i > 0 { + g.Printf(", ") + } + g.Printf("_%s", p.name) + } + g.Printf(");\n") + for _, p := range s.params { + g.genRelease(p.name, p.typ, modeTransient) + } + if len(s.retParams) == 2 { + g.Printf("int32_t refnum = res.r0;\n") + g.Printf("GoSeqRef *_err = go_seq_from_refnum(res.r1);\n") + } + g.Printf("__ref = go_seq_from_refnum(refnum);\n") + if len(s.retParams) == 2 { + g.Printf("if (_err != NULL)\n") + g.Printf(" return nil;\n") + } + g.Printf("return self;\n") + g.Outdent() + g.Printf("}\n\n") +} + +func (g *ObjcGen) errorf(format string, args ...interface{}) { + g.err = append(g.err, fmt.Errorf(format, args...)) +} + +func (g *ObjcGen) refTypeBase(typ types.Type) string { + switch typ := typ.(type) { + case *types.Pointer: + if _, ok := typ.Elem().(*types.Named); ok { + return g.objcType(typ.Elem()) + } + case *types.Named: + n := typ.Obj() + if isObjcType(typ) { + return g.wrapMap[n.Name()].Name + } + if isErrorType(typ) || g.validPkg(n.Pkg()) { + switch typ.Underlying().(type) { + case *types.Interface, *types.Struct: + return g.namePrefixOf(n.Pkg()) + n.Name() + } + } + } + + // fallback to whatever objcType returns. This must not happen. + return g.objcType(typ) +} + +func (g *ObjcGen) objcParamType(t types.Type) string { + + switch typ := t.(type) { + case *types.Basic: + switch typ.Kind() { + case types.String, types.UntypedString: + return "NSString* _Nullable" + } + } + + return g.objcType(t) + +} + +func (g *ObjcGen) objcType(typ types.Type) string { + + if isErrorType(typ) { + return "NSError* _Nullable" + } + + switch typ := typ.(type) { + case *types.Basic: + switch typ.Kind() { + case types.Bool, types.UntypedBool: + return "BOOL" + case types.Int: + return "long" + case types.Int8: + return "int8_t" + case types.Int16: + return "int16_t" + case types.Int32, types.UntypedRune: // types.Rune + return "int32_t" + case types.Int64, types.UntypedInt: + return "int64_t" + case types.Uint8: + // byte is an alias of uint8, and the alias is lost. + return "byte" + case types.Uint16: + return "uint16_t" + case types.Uint32: + return "uint32_t" + case types.Uint64: + return "uint64_t" + case types.Float32: + return "float" + case types.Float64, types.UntypedFloat: + return "double" + case types.String, types.UntypedString: + return "NSString* _Nonnull" + default: + g.errorf("unsupported type: %s", typ) + 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" + } + // TODO(hyangah): support other slice types: NSArray or CFArrayRef. + // Investigate the performance implication. + g.errorf("unsupported type: %s", typ) + return "TODO" + case *types.Pointer: + if _, ok := typ.Elem().(*types.Named); ok { + return g.objcType(typ.Elem()) + "* _Nullable" + } + g.errorf("unsupported pointer to type: %s", typ) + return "TODO" + case *types.Named: + n := typ.Obj() + if isObjcType(typ) { + w := g.wrapMap[n.Name()] + return w.ObjcType() + } + if !isErrorType(typ) && !g.validPkg(n.Pkg()) { + g.errorf("type %s is in package %s, which is not bound", n.Name(), n.Pkg().Name()) + return "TODO" + } + switch t := typ.Underlying().(type) { + case *types.Interface: + if makeIfaceSummary(t).implementable { + return "id<" + g.namePrefixOf(n.Pkg()) + n.Name() + "> _Nullable" + } else { + return g.namePrefixOf(n.Pkg()) + n.Name() + "* _Nullable" + } + case *types.Struct: + return g.namePrefixOf(n.Pkg()) + n.Name() + } + g.errorf("unsupported, named type %s", typ) + return "TODO" + default: + g.errorf("unsupported type: %#+v, %s", typ, typ) + return "TODO" + } +} + +// embeddedObjcTypes returns the possible empty list of Objc types embedded +// in the given struct type. +func embeddedObjcTypes(t *types.Struct) []string { + typeSet := make(map[string]struct{}) + var typs []string + for i := 0; i < t.NumFields(); i++ { + f := t.Field(i) + if !f.Exported() { + continue + } + if ft := f.Type(); isObjcType(ft) { + name := ft.(*types.Named).Obj().Name() + if _, exists := typeSet[name]; !exists { + typeSet[name] = struct{}{} + typs = append(typs, name) + } + } + } + return typs +} + +func isObjcType(t types.Type) bool { + return typePkgFirstElem(t) == "ObjC" +} + +var objcNameReplacer = newNameSanitizer([]string{ + "bool", "bycopy", "byref", "char", "const", "double", "float", + "id", "in", "init", "inout", "int", "long", "nil", "oneway", + "out", "self", "short", "signed", "super", "unsigned", "void", + "volatile"}) + +const ( + objcPreamble = `// Objective-C API for talking to %[1]s Go package. +// gobind %[2]s %[3]s +// +// File is generated by gobind. Do not edit. + +` +) diff --git a/bind/genobjcw.go b/bind/genobjcw.go new file mode 100644 index 000000000..1f5ccf63f --- /dev/null +++ b/bind/genobjcw.go @@ -0,0 +1,756 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bind + +import ( + "path" + "strings" + + "golang.org/x/mobile/internal/importers/objc" +) + +type ( + // ObjCWrapper generates Go and C stubs for ObjC interfaces and protocols. + ObjcWrapper struct { + *Printer + imported map[string]*objc.Named + // The list of ObjC types. + types []*objc.Named + // The list of Go package paths with ObjC wrappers. + pkgNames []string + modules []string + // For each ObjC module, the list of ObjC types within. + modMap map[string][]*objc.Named + // For each module/name Go package path, the ObjC type + // with static functions or constants. + typePkgs map[string]*objc.Named + // supers is the map of types that need Super methods. + supers map[string]struct{} + } +) + +// Init initializes the ObjC types wrapper generator. Types is the +// list of types to wrap, genNames the list of generated type names. +func (g *ObjcWrapper) Init(types []*objc.Named, genNames []string) { + g.supers = make(map[string]struct{}) + for _, s := range genNames { + g.supers[s] = struct{}{} + } + g.types = types + g.imported = make(map[string]*objc.Named) + g.modMap = make(map[string][]*objc.Named) + g.typePkgs = make(map[string]*objc.Named) + pkgSet := make(map[string]struct{}) + for _, n := range types { + g.imported[n.GoName] = n + typePkg := n.Module + "/" + n.GoName + g.typePkgs[typePkg] = n + if !n.Generated { + if _, exists := g.modMap[n.Module]; !exists { + g.modules = append(g.modules, n.Module) + } + } + g.modMap[n.Module] = append(g.modMap[n.Module], n) + if _, exists := pkgSet[n.Module]; !exists { + pkgSet[n.Module] = struct{}{} + g.pkgNames = append(g.pkgNames, n.Module) + } + g.pkgNames = append(g.pkgNames, typePkg) + } +} + +func (g *ObjcWrapper) GenM() { + g.Printf(gobindPreamble) + // For objc_msgSend* functions. + g.Printf("@import ObjectiveC.message;\n") + g.Printf("#include \"seq.h\"\n") + g.Printf("#include \"interfaces.h\"\n\n") + for _, n := range g.types { + g.genM(n) + } + g.Printf("\n") + for _, n := range g.types { + for _, f := range n.AllMethods { + if !g.isFuncSupported(f) { + continue + } + g.genCFuncDecl("cproxy", n.GoName, f) + g.genCFuncBody(n, f, false) + if _, exists := g.supers[n.GoName]; exists { + g.genCFuncDecl("csuper", n.GoName, f) + g.genCFuncBody(n, f, true) + } + } + } +} + +func (g *ObjcWrapper) genCFuncBody(n *objc.Named, f *objc.Func, super bool) { + g.Printf(" {\n") + g.Indent() + if !f.Static { + g.Printf("%s _this = go_seq_from_refnum(this).obj;\n", n.ObjcType()) + } + var errParam *objc.Param + for i, a := range f.Params { + if i == len(f.Params)-1 && g.isErrorType(a.Type) { + errParam = a + break + } + g.genCToObjC(a.Name, a.Type, modeTransient) + } + if errParam != nil { + g.Printf("NSError *%s = nil;\n", errParam.Name) + } + if f.Constructor { + g.Printf("%s _this = [%s alloc];\n", n.ObjcType(), n.Name) + } + if super { + g.Printf("struct objc_super _super = {\n") + g.Printf(" .receiver = _this,\n") + g.Printf(" .super_class = class_getSuperclass([%s class]),\n", n.Name) + g.Printf("};\n") + } + retType := "void" + if f.Ret != nil { + retType = g.objcType(f.Ret) + g.Printf("%s res = ", retType) + } + // There is no direct way to send a message to a class' super + // class from outside the class itself. Use objc_msgSendSuper instead + // which is what the compiler uses itself. To keep us honest and to exercise + // the code paths more use objc_msgSend for regular calls as well. + // + // A regular call looks like this: + // + // res = (( (*)(id, SEL, ))objc_msgSend)(_this, @selector(...), ) + // + // a call to super looks like this: + // + // ret = (( (*)(id, SEL, ))objc_msgSendSuper)(, ) + if f.Ret != nil { + switch f.Ret.Kind { + case objc.String, objc.Bool, objc.Data, objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double, objc.Class, objc.Protocol: + default: + // If support for struct results is added, objc_msgSend_stret must be used + panic("unsupported type kind - use objc_msgSend_stret?") + } + } + g.Printf("((%s (*)(", retType) + if super { + g.Printf("struct objc_super *") + } else { + g.Printf("id") + } + g.Printf(", SEL") + for _, a := range f.Params { + g.Printf(", %s", g.objcType(a.Type)) + } + g.Printf("))") + if super { + g.Printf("objc_msgSendSuper") + } else { + g.Printf("objc_msgSend") + } + g.Printf(")(") + if f.Static && !f.Constructor { + g.Printf("[%s class]", n.Name) + } else { + if super { + g.Printf("&_super") + } else { + g.Printf("_this") + } + } + g.Printf(", @selector(%s)", f.Sig) + for _, a := range f.Params { + arg := "_" + a.Name + if a == errParam { + arg = "&" + a.Name + } + g.Printf(", %s", arg) + } + g.Printf(");\n") + if errParam != nil { + g.Printf("NSError *_%s = nil;\n", errParam.Name) + if f.Ret != nil { + g.Printf("if (!res && %s != nil) {\n", errParam.Name) + } else { + g.Printf("if (%s != nil) {\n", errParam.Name) + } + g.Printf(" _%[1]s = %[1]s;\n", errParam.Name) + g.Printf("}\n") + g.genObjCToC("_"+errParam.Name, g.errType(), modeRetained) + } + ret := f.Ret + if ret != nil && ret.Kind == objc.Bool && errParam != nil { + ret = nil + } + if ret != nil { + g.genObjCToC("res", ret, modeRetained) + } + switch { + case ret != nil && errParam != nil: + stype := strings.Replace(g.cType(ret), " ", "_", -1) + g.Printf("ret_%s _sres = {_res, __%s};\n", stype, errParam.Name) + g.Printf("return _sres;\n") + case ret != nil: + g.Printf("return _res;\n") + case errParam != nil: + g.Printf("return __%s;\n", errParam.Name) + } + g.Outdent() + g.Printf("}\n\n") +} + +func (_ *ObjcWrapper) errType() *objc.Type { + return &objc.Type{Kind: objc.Class, Name: "NSError"} +} + +func (g *ObjcWrapper) genM(n *objc.Named) { + for _, f := range n.Funcs { + if !g.isFuncSupported(f) { + continue + } + g.genCFuncDecl("cproxy", n.GoName, f) + g.genCFuncBody(n, f, false) + } +} + +func (g *ObjcWrapper) GenH() { + g.Printf(gobindPreamble) + g.Printf("#include \"seq.h\"\n\n") + for _, m := range g.modules { + g.Printf("@import %s;\n", m) + } + // Include header files for generated types + for _, n := range g.pkgNames { + hasGen := false + for _, t := range g.modMap[n] { + if t.Generated { + hasGen = true + break + } + } + if hasGen { + g.Printf("#import %q\n", n+".objc.h") + } + } + for _, tn := range []string{"int", "nstring", "nbyteslice", "long", "unsigned long", "short", "unsigned short", "bool", "char", "unsigned char", "float", "double"} { + sn := strings.Replace(tn, " ", "_", -1) + g.Printf("typedef struct ret_%s {\n", sn) + g.Printf(" %s res;\n", tn) + g.Printf(" int err;\n") + g.Printf("} ret_%s;\n", sn) + } + g.Printf("\n") + for _, n := range g.types { + for _, f := range n.AllMethods { + if !g.isFuncSupported(f) { + continue + } + g.Printf("extern ") + g.genCFuncDecl("cproxy", n.GoName, f) + g.Printf(";\n") + if _, exists := g.supers[n.GoName]; exists { + g.Printf("extern ") + g.genCFuncDecl("csuper", n.GoName, f) + g.Printf(";\n") + } + } + } + for _, cls := range g.types { + g.genH(cls) + } +} + +func (g *ObjcWrapper) genH(n *objc.Named) { + for _, f := range n.Funcs { + if !g.isFuncSupported(f) { + continue + } + g.Printf("extern ") + g.genCFuncDecl("cproxy", n.GoName, f) + g.Printf(";\n") + } +} + +func (g *ObjcWrapper) genCFuncDecl(prefix, name string, f *objc.Func) { + returnsErr := len(f.Params) > 0 && g.isErrorType(f.Params[len(f.Params)-1].Type) + ret := f.Ret + if ret != nil && returnsErr && ret.Kind == objc.Bool { + ret = nil + } + switch { + case ret != nil && returnsErr: + g.Printf("ret_%s", strings.Replace(g.cType(ret), " ", "_", -1)) + case ret != nil: + g.Printf(g.cType(ret)) + case returnsErr: + g.Printf("int") + default: + g.Printf("void") + } + g.Printf(" ") + g.Printf(prefix) + if f.Static { + g.Printf("_s") + } + g.Printf("_%s_%s(", name, f.GoName) + if !f.Static { + g.Printf("int this") + } + for i, p := range f.Params { + if i == len(f.Params)-1 && returnsErr { + break + } + if !f.Static || i > 0 { + g.Printf(", ") + } + g.Printf("%s %s", g.cType(p.Type), p.Name) + } + g.Printf(")") +} + +func (g *ObjcWrapper) GenGo() { + g.Printf(gobindPreamble) + g.Printf("package main\n\n") + g.Printf("// #include \"interfaces.h\"\n") + g.Printf("import \"C\"\n\n") + g.Printf("import \"ObjC\"\n") + g.Printf("import _seq \"golang.org/x/mobile/bind/seq\"\n") + + for _, n := range g.types { + for _, f := range n.Funcs { + if g.isFuncSupported(f) { + pkgName := n.Module + "/" + n.GoName + g.Printf("import %q\n", "ObjC/"+pkgName) + break + } + } + } + g.Printf("\n") + g.Printf("type proxy interface { Bind_proxy_refnum__() int32 }\n\n") + g.Printf("// Suppress unused package error\n\n") + g.Printf("var _ = _seq.FromRefNum\n") + g.Printf("const _ = ObjC.Dummy\n\n") + for _, n := range g.types { + g.genGo(n) + } +} + +func (g *ObjcWrapper) genGo(n *objc.Named) { + g.Printf("func init() {\n") + g.Indent() + for _, f := range n.Funcs { + if !g.isFuncSupported(f) { + continue + } + g.Printf("%s.%s = func", n.GoName, f.GoName) + g.genFuncDecl(false, f) + g.genFuncBody(n, f, "cproxy") + } + g.Outdent() + g.Printf("}\n\n") + g.Printf("type proxy_class_%s _seq.Ref\n\n", n.GoName) + g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }\n\n", n.GoName) + for _, f := range n.AllMethods { + if !g.isFuncSupported(f) { + continue + } + g.Printf("func (p *proxy_class_%s) %s", n.GoName, f.GoName) + g.genFuncDecl(false, f) + g.genFuncBody(n, f, "cproxy") + } + if _, exists := g.supers[n.GoName]; exists { + g.Printf("func (p *proxy_class_%s) Super() ObjC.%s {\n", n.GoName, n.Module+"_"+n.GoName) + g.Printf(" return &super_%s{p}\n", n.GoName) + g.Printf("}\n\n") + g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", n.GoName) + for _, f := range n.AllMethods { + if !g.isFuncSupported(f) { + continue + } + g.Printf("func (p *super_%s) %s", n.GoName, f.GoName) + g.genFuncDecl(false, f) + g.genFuncBody(n, f, "csuper") + } + } +} + +func (g *ObjcWrapper) genFuncBody(n *objc.Named, f *objc.Func, prefix string) { + g.Printf(" {\n") + g.Indent() + var errParam *objc.Param + for i, a := range f.Params { + if i == len(f.Params)-1 && g.isErrorType(a.Type) { + errParam = a + break + } + g.genWrite(a) + } + ret := f.Ret + if ret != nil && errParam != nil && ret.Kind == objc.Bool { + ret = nil + } + if ret != nil || errParam != nil { + g.Printf("res := ") + } + g.Printf("C.") + g.Printf(prefix) + if f.Static { + g.Printf("_s") + } + g.Printf("_%s_%s(", n.GoName, f.GoName) + if !f.Static { + g.Printf("C.int(p.Bind_proxy_refnum__())") + } + for i, a := range f.Params { + if a == errParam { + break + } + if !f.Static || i > 0 { + g.Printf(", ") + } + g.Printf("_%s", a.Name) + } + g.Printf(")\n") + switch { + case ret != nil && errParam != nil: + g.genRead("_res", "res.res", ret) + g.genRefRead("_"+errParam.Name, "res.err", "error", "proxy_error") + g.Printf("return _res, _%s\n", errParam.Name) + case ret != nil: + g.genRead("_res", "res", ret) + g.Printf("return _res\n") + case errParam != nil: + g.genRefRead("_"+errParam.Name, "res", "error", "proxy_error") + g.Printf("return _%s\n", errParam.Name) + } + g.Outdent() + g.Printf("}\n\n") +} + +func (g *ObjcWrapper) genCToObjC(name string, t *objc.Type, mode varMode) { + switch t.Kind { + case objc.String: + g.Printf("NSString *_%s = go_seq_to_objc_string(%s);\n", name, name) + case objc.Bool: + g.Printf("BOOL _%s = %s ? YES : NO;\n", name, name) + case objc.Data: + g.Printf("NSData *_%s = go_seq_to_objc_bytearray(%s, %d);\n", name, name, toCFlag(mode == modeRetained)) + case objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double: + g.Printf("%s _%s = (%s)%s;\n", g.objcType(t), name, g.objcType(t), name) + case objc.Class, objc.Protocol: + g.Printf("GoSeqRef* %s_ref = go_seq_from_refnum(%s);\n", name, name) + g.Printf("%s _%s;\n", g.objcType(t), name) + g.Printf("if (%s_ref != NULL) {\n", name) + g.Printf(" _%s = %s_ref.obj;\n", name, name) + g.Printf("}\n") + default: + panic("invalid kind") + } +} + +func (g *ObjcWrapper) genObjCToC(name string, t *objc.Type, mode varMode) { + switch t.Kind { + case objc.String: + g.Printf("nstring _%s = go_seq_from_objc_string(%s);\n", name, name) + case objc.Data: + g.Printf("nbyteslice _%s = go_seq_from_objc_bytearray(%s, %d);\n", name, name, toCFlag(mode == modeRetained)) + case objc.Bool, objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double: + g.Printf("%s _%s = (%s)%s;\n", g.cType(t), name, g.cType(t), name) + case objc.Protocol, objc.Class: + g.Printf("int _%s = go_seq_to_refnum(%s);\n", name, name) + default: + panic("invalid kind") + } +} + +func (g *ObjcWrapper) genWrite(a *objc.Param) { + switch a.Type.Kind { + case objc.String: + g.Printf("_%s := encodeString(%s)\n", a.Name, a.Name) + case objc.Data: + g.Printf("_%s := fromSlice(%s, false)\n", a.Name, a.Name) + case objc.Bool: + g.Printf("_%s := %s(0)\n", a.Name, g.cgoType(a.Type)) + g.Printf("if %s {\n", a.Name) + g.Printf(" _%s = %s(1)\n", a.Name, g.cgoType(a.Type)) + g.Printf("}\n") + case objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double: + g.Printf("_%s := %s(%s)\n", a.Name, g.cgoType(a.Type), a.Name) + case objc.Protocol, objc.Class: + g.Printf("var _%s %s = _seq.NullRefNum\n", a.Name, g.cgoType(a.Type)) + g.Printf("if %s != nil {\n", a.Name) + g.Printf(" _%s = %s(_seq.ToRefNum(%s))\n", a.Name, g.cgoType(a.Type), a.Name) + g.Printf("}\n") + default: + panic("invalid kind") + } +} + +func (g *ObjcWrapper) genRead(to, from string, t *objc.Type) { + switch t.Kind { + case objc.Int, objc.Uint, objc.Uchar, objc.Short, objc.Ushort, objc.Char, objc.Float, objc.Double: + g.Printf("%s := %s(%s)\n", to, g.goType(t, false), from) + case objc.Bool: + g.Printf("%s := %s != 0\n", to, from) + case objc.String: + g.Printf("%s := decodeString(%s)\n", to, from) + case objc.Data: + g.Printf("%s := toSlice(%s, true)\n", to, from) + case objc.Protocol, objc.Class: + var proxyName string + if n := g.lookupImported(t); n != nil { + proxyName = "proxy_class_" + n.GoName + } + g.genRefRead(to, from, g.goType(t, false), proxyName) + default: + panic("invalid kind") + } +} + +func (g *ObjcWrapper) genRefRead(to, from string, intfName, proxyName string) { + g.Printf("var %s %s\n", to, intfName) + g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", to, from) + g.Printf("if %s_ref != nil {\n", to) + g.Printf(" if %s < 0 { // go object\n", from) + g.Printf(" %s = %s_ref.Get().(%s)\n", to, to, intfName) + if proxyName != "" { + g.Printf(" } else { // foreign object\n") + g.Printf(" %s = (*%s)(%s_ref)\n", to, proxyName, to) + } + g.Printf(" }\n") + g.Printf("}\n") +} + +// Packages return the list of Go packages to be generated. +func (g *ObjcWrapper) Packages() []string { + return g.pkgNames +} + +func (g *ObjcWrapper) GenPackage(idx int) { + pkg := g.pkgNames[idx] + g.Printf(gobindPreamble) + g.Printf("package %s\n\n", path.Base(pkg)) + g.Printf("import \"ObjC\"\n\n") + g.Printf("const _ = ObjC.Dummy\n\n") + for _, n := range g.modMap[pkg] { + g.Printf("type %s ObjC.%s\n", n.GoName, n.Module+"_"+n.GoName) + } + if n, ok := g.typePkgs[pkg]; ok { + g.Printf("var (\n") + g.Indent() + // Functions + for _, f := range n.Funcs { + if !g.isFuncSupported(f) { + continue + } + g.Printf("%s func", f.GoName) + g.genFuncDecl(false, f) + g.Printf("\n") + } + g.Outdent() + g.Printf(")\n\n") + } +} + +func (g *ObjcWrapper) GenInterfaces() { + g.Printf(gobindPreamble) + g.Printf("package ObjC\n\n") + g.Printf("// Used to silence this package not used errors\n") + g.Printf("const Dummy = 0\n\n") + for _, n := range g.types { + g.genInterface(n) + } +} + +func (g *ObjcWrapper) genInterface(n *objc.Named) { + g.Printf("type %s interface {\n", n.Module+"_"+n.GoName) + g.Indent() + // Methods + for _, f := range n.AllMethods { + if !g.isFuncSupported(f) { + continue + } + g.Printf(f.GoName) + g.genFuncDecl(true, f) + g.Printf("\n") + } + if _, exists := g.supers[n.GoName]; exists { + g.Printf("Super() %s\n", n.Module+"_"+n.GoName) + } + g.Outdent() + g.Printf("}\n\n") +} + +func (g *ObjcWrapper) genFuncDecl(local bool, f *objc.Func) { + var returnsErr bool + g.Printf("(") + for i, p := range f.Params { + if i == len(f.Params)-1 && g.isErrorType(p.Type) { + returnsErr = true + break + } + if i > 0 { + g.Printf(", ") + } + g.Printf("%s %s", p.Name, g.goType(p.Type, local)) + } + g.Printf(")") + if f.Ret != nil || returnsErr { + ret := f.Ret + if ret.Kind == objc.Bool && returnsErr { + // Skip the bool result and use the error results. + ret = nil + } + if ret != nil { + g.Printf(" (%s", g.goType(f.Ret, local)) + if returnsErr { + g.Printf(", error") + } + g.Printf(")") + } else { + g.Printf(" error") + } + } +} + +func (g *ObjcWrapper) isFuncSupported(f *objc.Func) bool { + for i, p := range f.Params { + if !g.isSupported(p.Type) { + if i < len(f.Params)-1 || !g.isErrorType(p.Type) { + return false + } + } + } + if f.Ret != nil { + return g.isSupported(f.Ret) + } + return true +} + +func (g *ObjcWrapper) isErrorType(t *objc.Type) bool { + // Must be a NSError ** type + return t.Kind == objc.Class && t.Indirect && t.Name == "NSError" +} + +func (g *ObjcWrapper) isSupported(t *objc.Type) bool { + if t.Indirect { + return false + } + switch t.Kind { + case objc.Unknown: + return false + case objc.Protocol: + // TODO: support inout parameters. + return !strings.HasSuffix(t.Decl, " *") + case objc.Class: + return t.Name != "SEL" && t.Name != "void" + default: + return true + } +} + +func (g *ObjcWrapper) cgoType(t *objc.Type) string { + switch t.Kind { + case objc.Uint: + return "C.ulong" + case objc.Ushort: + return "C.ushort" + case objc.Uchar: + return "C.uchar" + default: + return "C." + g.cType(t) + } +} + +func (g *ObjcWrapper) cType(t *objc.Type) string { + switch t.Kind { + case objc.Protocol, objc.Class: + return "int" + case objc.String: + return "nstring" + case objc.Data: + return "nbyteslice" + case objc.Int: + return "long" + case objc.Uint: + return "unsigned long" + case objc.Short: + return "short" + case objc.Ushort: + return "unsigned short" + case objc.Bool: + return "char" + case objc.Char: + return "char" + case objc.Uchar: + return "unsigned char" + case objc.Float: + return "float" + case objc.Double: + return "double" + default: + panic("invalid kind") + } +} + +func (g *ObjcWrapper) objcType(t *objc.Type) string { + return t.Decl +} + +func (g *ObjcWrapper) lookupImported(t *objc.Type) *objc.Named { + var mangled string + switch t.Kind { + case objc.Class: + mangled = t.Name + "C" + case objc.Protocol: + mangled = t.Name + "P" + default: + panic("invalid type kind") + } + if n, exists := g.imported[mangled]; exists { + return n + } + return g.imported[t.Name] +} + +func (g *ObjcWrapper) goType(t *objc.Type, local bool) string { + switch t.Kind { + case objc.String: + return "string" + case objc.Data: + return "[]byte" + case objc.Int: + return "int" + case objc.Uint: + return "uint" + case objc.Short: + return "int16" + case objc.Ushort: + return "uint16" + case objc.Bool: + return "bool" + case objc.Char: + return "byte" + case objc.Uchar: + return "uint8" + case objc.Float: + return "float32" + case objc.Double: + return "float64" + case objc.Protocol, objc.Class: + var n *objc.Named + n = g.lookupImported(t) + name := n.Module + "_" + n.GoName + if !local { + name = "ObjC." + name + } + return name + default: + panic("invalid kind") + } +} diff --git a/bind/implicit.go b/bind/implicit.go new file mode 100644 index 000000000..5144209c3 --- /dev/null +++ b/bind/implicit.go @@ -0,0 +1,10 @@ +// This file imports implicit dependencies required by generated code. + +//go:build mobile_implicit +// +build mobile_implicit + +package bind + +import ( + _ "golang.org/x/mobile/bind/seq" +) diff --git a/bind/java/ClassesTest.java b/bind/java/ClassesTest.java new file mode 100644 index 000000000..00f02edb7 --- /dev/null +++ b/bind/java/ClassesTest.java @@ -0,0 +1,157 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go; + +import android.test.InstrumentationTestCase; +import android.test.MoreAsserts; + +import java.io.InputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Random; + +import javapkg.Javapkg; +import javapkg.I; +import javapkg.GoObject; +import javapkg.GoRunnable; +import javapkg.GoSubset; +import javapkg.GoInputStream; +import javapkg.GoArrayList; + +public class ClassesTest extends InstrumentationTestCase { + public void testConst() { + assertEquals("const Float", Float.MIN_VALUE, Javapkg.floatMin()); + assertEquals("const String", java.util.jar.JarFile.MANIFEST_NAME, Javapkg.manifestName()); + assertEquals("const Int", 7, Integer.SIZE, Javapkg.integerBytes()); + } + + public void testFunction() { + Javapkg.systemCurrentTimeMillis(); + } + + public void testMethod() { + try { + assertEquals("Integer.decode", 0xff, Javapkg.integerDecode("0xff")); + } catch (Exception e) { + throw new RuntimeException(e); + } + Exception exc = null; + try { + Javapkg.integerDecode("obviously wrong"); + } catch (Exception e) { + exc = e; + } + assertNotNull("IntegerDecode Exception", exc); + } + + public void testOverloadedMethod() { + try { + assertEquals("Integer.parseInt", 0xc4, Javapkg.integerParseInt("c4", 16)); + } catch (Exception e) { + throw new RuntimeException(e); + } + Exception exc = null; + try { + Javapkg.integerParseInt("wrong", 16); + } catch (Exception e) { + exc = e; + } + assertNotNull("integerParseInt Exception", exc); + assertEquals("Integer.valueOf", 42, Javapkg.integerValueOf(42)); + } + + public void testException() { + Exception exc = null; + try { + Javapkg.provokeRuntimeException(); + } catch (Exception e) { + exc = e; + } + assertNotNull("RuntimeException", exc); + } + + public void testField() { + GoRunnable r = new GoRunnable(); + String f = r.getField(); + } + + public void testGoObject() { + Runnable r = new GoRunnable(); + r.run(); + assertEquals("GoRunnable.toString", r.toString(), Javapkg.ToStringPrefix); + Runnable r2 = ((GoRunnable)r).getThis(); + assertTrue("GoObject.this", r == r2); + Object o = new GoObject(); + assertEquals("GoObject hashCode", 42, o.hashCode()); + Object o2 = Javapkg.constructGoObject(); + assertEquals("GoObject hashCode", 42, o2.hashCode()); + assertTrue("GoObject.toString", o.toString().startsWith(Javapkg.ToStringPrefix)); + Javapkg.runRunnable(r); + final boolean[] ran = new boolean[1]; + Runnable r3 = new Runnable(){ + @Override public void run() { + ran[0] = true; + } + }; + Javapkg.runRunnable(r3); + assertTrue("RunRunnable", ran[0]); + assertTrue("RunnableRoundtrip Java", r3 == Javapkg.runnableRoundtrip(r3)); + assertTrue("RunnableRoundtrip Go", r == Javapkg.runnableRoundtrip(r)); + Runnable r5 = Javapkg.constructGoRunnable(); + r5.run(); + } + + public void testTypedException() { + InputStream is = new GoInputStream(); + Exception exc = null; + try { + is.read(); + } catch (IOException e) { + exc = e; + } + assertNotNull("IOException", exc); + assertEquals("IOException message", Javapkg.IOExceptionMessage, exc.getMessage()); + } + + public void testInnerClass() { + Character.Subset s = new Character.Subset(""){}; + Character.Subset s2 = new GoSubset(""); + Javapkg.callSubset(s); + Javapkg.callSubset(s2); + } + + public void testNew() { + Object o = Javapkg.newJavaObject(); + assertTrue("new Object()", o != null); + Integer i = Javapkg.newJavaInteger(); + assertEquals("new Integer(42)", 42, i.intValue()); + } + + private static class InterfaceRunnable implements I, Runnable { + @Override public void run() { + } + } + + public void testCast() { + Runnable r1 = new GoRunnable(); + Runnable r1c = Javapkg.castRunnable((Object)r1); + assertTrue("Casting Go object", r1c != null); + Runnable r2 = new Runnable() { + @Override public void run() { + } + }; + Runnable r2c = Javapkg.castRunnable((Object)r2); + assertTrue("Casting Java object", r2c != null); + Runnable r3c = Javapkg.castInterface(new InterfaceRunnable()); + assertTrue("Casting Go interface implementation", r3c != null); + Runnable r4c = Javapkg.castRunnable(new Object()); + assertTrue("Invalid cast", r4c == null); + } + + public void testUnwrap() { + GoArrayList l = new GoArrayList(); + Javapkg.unwrapGoArrayList(l); + } +} diff --git a/bind/java/CustomPkgTest.java b/bind/java/CustomPkgTest.java new file mode 100644 index 000000000..414302546 --- /dev/null +++ b/bind/java/CustomPkgTest.java @@ -0,0 +1,15 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go; + +import android.test.InstrumentationTestCase; + +import org.golang.custompkg.testpkg.Testpkg; + +public class CustomPkgTest extends InstrumentationTestCase { + public void testHi() { + Testpkg.hi(); + } +} diff --git a/bind/java/Seq.java b/bind/java/Seq.java new file mode 100644 index 000000000..367acdb67 --- /dev/null +++ b/bind/java/Seq.java @@ -0,0 +1,400 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go; + +import android.content.Context; + +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Logger; + +import go.Universe; + +// Seq is a sequence of machine-dependent encoded values. +// Used by automatically generated language bindings to talk to Go. +public class Seq { + private static Logger log = Logger.getLogger("GoSeq"); + + // also known to bind/seq/ref.go and bind/objc/seq_darwin.m + private static final int NULL_REFNUM = 41; + + // use single Ref for null Object + public static final Ref nullRef = new Ref(NULL_REFNUM, null); + + // The singleton GoRefQueue + private static final GoRefQueue goRefQueue = new GoRefQueue(); + + static { + System.loadLibrary("gojni"); + init(); + Universe.touch(); + } + + // setContext sets the context in the go-library to be used in RunOnJvm. + public static void setContext(Context context) { + setContext((java.lang.Object)context); + } + + private static native void init(); + + // Empty method to run class initializer + public static void touch() {} + + private Seq() { + } + + // ctx is an android.context.Context. + static native void setContext(java.lang.Object ctx); + + public static void incRefnum(int refnum) { + tracker.incRefnum(refnum); + } + + // incRef increments the reference count of Java objects. + // For proxies for Go objects, it calls into the Proxy method + // incRefnum() to make sure the Go reference count is positive + // even if the Proxy is garbage collected and its Ref is finalized. + public static int incRef(Object o) { + return tracker.inc(o); + } + + public static int incGoObjectRef(GoObject o) { + return o.incRefnum(); + } + + // trackGoRef tracks a Go reference and decrements its refcount + // when the given GoObject wrapper is garbage collected. + // + // TODO(crawshaw): We could cut down allocations for frequently + // sent Go objects by maintaining a map to weak references. This + // however, would require allocating two objects per reference + // instead of one. It also introduces weak references, the bane + // of any Java debugging session. + // + // When we have real code, examine the tradeoffs. + public static void trackGoRef(int refnum, GoObject obj) { + if (refnum > 0) { + throw new RuntimeException("trackGoRef called with Java refnum " + refnum); + } + goRefQueue.track(refnum, obj); + } + + public static Ref getRef(int refnum) { + return tracker.get(refnum); + } + + // Increment the Go reference count before sending over a refnum. + // The ref parameter is only used to make sure the referenced + // object is not garbage collected before Go increments the + // count. It's the equivalent of Go's runtime.KeepAlive. + public static native void incGoRef(int refnum, GoObject ref); + + // Informs the Go ref tracker that Java is done with this refnum. + static native void destroyRef(int refnum); + + // decRef is called from seq.FinalizeRef + static void decRef(int refnum) { + tracker.dec(refnum); + } + + // A GoObject is a Java class implemented in Go. When a GoObject + // is passed to Go, it is wrapped in a Go proxy, to make it behave + // the same as passing a regular Java class. + public interface GoObject { + // Increment refcount and return the refnum of the proxy. + // + // The Go reference count need to be bumped while the + // refnum is passed to Go, to avoid finalizing and + // invalidating it before being translated on the Go side. + int incRefnum(); + } + // A Proxy is a Java object that proxies a Go object. Proxies, unlike + // GoObjects, are unwrapped to their Go counterpart when deserialized + // in Go. + public interface Proxy extends GoObject {} + + // A Ref represents an instance of a Java object passed back and forth + // across the language boundary. + public static final class Ref { + public final int refnum; + + private int refcnt; // Track how many times sent to Go. + + public final Object obj; // The referenced Java obj. + + Ref(int refnum, Object o) { + if (refnum < 0) { + throw new RuntimeException("Ref instantiated with a Go refnum " + refnum); + } + this.refnum = refnum; + this.refcnt = 0; + this.obj = o; + } + + void inc() { + // Count how many times this ref's Java object is passed to Go. + if (refcnt == Integer.MAX_VALUE) { + throw new RuntimeException("refnum " + refnum + " overflow"); + } + refcnt++; + } + } + + static final RefTracker tracker = new RefTracker(); + + static final class RefTracker { + private static final int REF_OFFSET = 42; + + // Next Java object reference number. + // + // Reference numbers are positive for Java objects, + // and start, arbitrarily at a different offset to Go + // to make debugging by reading Seq hex a little easier. + private int next = REF_OFFSET; // next Java object ref + + // Java objects that have been passed to Go. refnum -> Ref + // The Ref obj field is non-null. + // This map pins Java objects so they don't get GCed while the + // only reference to them is held by Go code. + private final RefMap javaObjs = new RefMap(); + + // Java objects to refnum + private final IdentityHashMap javaRefs = new IdentityHashMap<>(); + + // inc increments the reference count of a Java object when it + // is sent to Go. inc returns the refnum for the object. + synchronized int inc(Object o) { + if (o == null) { + return NULL_REFNUM; + } + if (o instanceof Proxy) { + return ((Proxy)o).incRefnum(); + } + Integer refnumObj = javaRefs.get(o); + if (refnumObj == null) { + if (next == Integer.MAX_VALUE) { + throw new RuntimeException("createRef overflow for " + o); + } + refnumObj = next++; + javaRefs.put(o, refnumObj); + } + int refnum = refnumObj; + Ref ref = javaObjs.get(refnum); + if (ref == null) { + ref = new Ref(refnum, o); + javaObjs.put(refnum, ref); + } + ref.inc(); + return refnum; + } + + synchronized void incRefnum(int refnum) { + Ref ref = javaObjs.get(refnum); + if (ref == null) { + throw new RuntimeException("referenced Java object is not found: refnum="+refnum); + } + ref.inc(); + } + + // dec decrements the reference count of a Java object when + // Go signals a corresponding proxy object is finalized. + // If the count reaches zero, the Java object is removed + // from the javaObjs map. + synchronized void dec(int refnum) { + if (refnum <= 0) { + // We don't keep track of the Go object. + // This must not happen. + log.severe("dec request for Go object "+ refnum); + return; + } + if (refnum == Seq.nullRef.refnum) { + return; + } + // Java objects are removed on request of Go. + Ref obj = javaObjs.get(refnum); + if (obj == null) { + throw new RuntimeException("referenced Java object is not found: refnum="+refnum); + } + obj.refcnt--; + if (obj.refcnt <= 0) { + javaObjs.remove(refnum); + javaRefs.remove(obj.obj); + } + } + + // get returns an existing Ref to a Java object. + synchronized Ref get(int refnum) { + if (refnum < 0) { + throw new RuntimeException("ref called with Go refnum " + refnum); + } + if (refnum == NULL_REFNUM) { + return nullRef; + } + Ref ref = javaObjs.get(refnum); + if (ref == null) { + throw new RuntimeException("unknown java Ref: "+refnum); + } + return ref; + } + } + + // GoRefQueue is a queue of GoRefs that are no longer live. An internal thread + // processes the queue and decrement the reference count on the Go side. + static class GoRefQueue extends ReferenceQueue { + // The set of tracked GoRefs. If we don't hold on to the GoRef instances, the Java GC + // will not add them to the queue when their referents are reclaimed. + private final Collection refs = Collections.synchronizedCollection(new HashSet()); + + void track(int refnum, GoObject obj) { + refs.add(new GoRef(refnum, obj, this)); + } + + GoRefQueue() { + Thread daemon = new Thread(new Runnable() { + @Override public void run() { + while (true) { + try { + GoRef ref = (GoRef)remove(); + refs.remove(ref); + destroyRef(ref.refnum); + ref.clear(); + } catch (InterruptedException e) { + // Ignore + } + } + } + }); + daemon.setDaemon(true); + daemon.setName("GoRefQueue Finalizer Thread"); + daemon.start(); + } + } + + // A GoRef is a PhantomReference to a Java proxy for a Go object. + // GoRefs are enqueued to the singleton GoRefQueue when no longer live, + // so the corresponding reference count can be decremented. + static class GoRef extends PhantomReference { + final int refnum; + + GoRef(int refnum, GoObject obj, GoRefQueue q) { + super(obj, q); + if (refnum > 0) { + throw new RuntimeException("GoRef instantiated with a Java refnum " + refnum); + } + this.refnum = refnum; + } + } + + // RefMap is a mapping of integers to Ref objects. + // + // The integers can be sparse. In Go this would be a map[int]*Ref. + static final class RefMap { + private int next = 0; + private int live = 0; + private int[] keys = new int[16]; + private Ref[] objs = new Ref[16]; + + RefMap() {} + + Ref get(int key) { + int i = Arrays.binarySearch(keys, 0, next, key); + if (i >= 0) { + return objs[i]; + } + return null; + } + + void remove(int key) { + int i = Arrays.binarySearch(keys, 0, next, key); + if (i >= 0) { + if (objs[i] != null) { + objs[i] = null; + live--; + } + } + } + + void put(int key, Ref obj) { + if (obj == null) { + throw new RuntimeException("put a null ref (with key "+key+")"); + } + int i = Arrays.binarySearch(keys, 0, next, key); + if (i >= 0) { + if (objs[i] == null) { + objs[i] = obj; + live++; + } + if (objs[i] != obj) { + throw new RuntimeException("replacing an existing ref (with key "+key+")"); + } + return; + } + if (next >= keys.length) { + grow(); + i = Arrays.binarySearch(keys, 0, next, key); + } + i = ~i; + if (i < next) { + // Insert, shift everything afterwards down. + System.arraycopy(keys, i, keys, i+1, next-i); + System.arraycopy(objs, i, objs, i+1, next-i); + } + keys[i] = key; + objs[i] = obj; + live++; + next++; + } + + private void grow() { + // Compact and (if necessary) grow backing store. + int[] newKeys; + Ref[] newObjs; + int len = 2*roundPow2(live); + if (len > keys.length) { + newKeys = new int[keys.length*2]; + newObjs = new Ref[objs.length*2]; + } else { + newKeys = keys; + newObjs = objs; + } + + int j = 0; + for (int i = 0; i < keys.length; i++) { + if (objs[i] != null) { + newKeys[j] = keys[i]; + newObjs[j] = objs[i]; + j++; + } + } + for (int i = j; i < newKeys.length; i++) { + newKeys[i] = 0; + newObjs[i] = null; + } + + keys = newKeys; + objs = newObjs; + next = j; + + if (live != next) { + throw new RuntimeException("bad state: live="+live+", next="+next); + } + } + + private static int roundPow2(int x) { + int p = 1; + while (p < x) { + p *= 2; + } + return p; + } + } +} diff --git a/bind/java/SeqBench.java b/bind/java/SeqBench.java new file mode 100644 index 000000000..26adb9d55 --- /dev/null +++ b/bind/java/SeqBench.java @@ -0,0 +1,162 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go; + +import android.test.InstrumentationTestCase; +import android.util.Log; + +import java.util.Map; +import java.util.HashMap; + +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; + +import benchmark.*; + +public class SeqBench extends InstrumentationTestCase { + + public static class AnI implements I { + @Override public void f() { + } + } + + private static class Benchmarks implements benchmark.Benchmarks { + private static Map benchmarks; + private static ExecutorService executor = Executors.newSingleThreadExecutor(); + + static { + benchmarks = new HashMap(); + benchmarks.put("Empty", new Runnable() { + @Override public void run() { + } + }); + benchmarks.put("Noargs", new Runnable() { + @Override public void run() { + Benchmark.noargs(); + } + }); + benchmarks.put("Onearg", new Runnable() { + @Override public void run() { + Benchmark.onearg(0); + } + }); + benchmarks.put("Manyargs", new Runnable() { + @Override public void run() { + Benchmark.manyargs(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + }); + benchmarks.put("Oneret", new Runnable() { + @Override public void run() { + Benchmark.oneret(); + } + }); + final I javaRef = new AnI(); + benchmarks.put("Refforeign", new Runnable() { + @Override public void run() { + Benchmark.ref(javaRef); + } + }); + final I goRef = Benchmark.newI(); + benchmarks.put("Refgo", new Runnable() { + @Override public void run() { + Benchmark.ref(goRef); + } + }); + benchmarks.put("StringShort", new Runnable() { + @Override public void run() { + Benchmark.string(Benchmark.ShortString); + } + }); + benchmarks.put("StringLong", new Runnable() { + @Override public void run() { + Benchmark.string(Benchmark.LongString); + } + }); + benchmarks.put("StringShortUnicode", new Runnable() { + @Override public void run() { + Benchmark.string(Benchmark.ShortStringUnicode); + } + }); + benchmarks.put("StringLongUnicode", new Runnable() { + @Override public void run() { + Benchmark.string(Benchmark.LongStringUnicode); + } + }); + benchmarks.put("StringRetShort", new Runnable() { + @Override public void run() { + Benchmark.stringRetShort(); + } + }); + benchmarks.put("StringRetLong", new Runnable() { + @Override public void run() { + Benchmark.stringRetLong(); + } + }); + final byte[] shortSlice = Benchmark.getShortSlice(); + benchmarks.put("SliceShort", new Runnable() { + @Override public void run() { + Benchmark.slice(shortSlice); + } + }); + final byte[] longSlice = Benchmark.getLongSlice(); + benchmarks.put("SliceLong", new Runnable() { + @Override public void run() { + Benchmark.slice(longSlice); + } + }); + } + + public void runDirect(String name, final long n) { + final Runnable r = benchmarks.get(name); + try { + executor.submit(new Runnable() { + @Override public void run() { + for (int i = 0; i < n; i++) { + r.run(); + } + } + }).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void run(String name, long n) { + final Runnable r = benchmarks.get(name); + for (int i = 0; i < n; i++) { + r.run(); + } + } + + @Override public I newI() { + return new AnI(); + } + @Override public void ref(I i) { + } + @Override public void noargs() { + } + @Override public void onearg(long i) { + } + @Override public long oneret() { + return 0; + } + @Override public void manyargs(long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long gp8, long p9) { + } + @Override public void string(String s) { + } + @Override public void slice(byte[] s) { + } + @Override public String stringRetShort() { + return Benchmark.ShortString; + } + @Override public String stringRetLong() { + return Benchmark.LongString; + } + } + + public void testBenchmark() { + Benchmark.runBenchmarks(new Benchmarks()); + } +} diff --git a/bind/java/SeqTest.java b/bind/java/SeqTest.java new file mode 100644 index 000000000..f89693c97 --- /dev/null +++ b/bind/java/SeqTest.java @@ -0,0 +1,602 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go; + +import android.test.InstrumentationTestCase; +import android.test.MoreAsserts; + +import java.util.Arrays; +import java.util.Random; + +import testpkg.*; +import secondpkg.Secondpkg; + +public class SeqTest extends InstrumentationTestCase { + public SeqTest() { + } + + public void testConst() { + assertEquals("const String", "a string", Testpkg.AString); + assertEquals("const Int", 7, Testpkg.AnInt); + assertEquals("const Bool", true, Testpkg.ABool); + assertEquals("const Float", 0.12345, Testpkg.AFloat, 0.0001); + + assertEquals("const MinInt32", -1<<31, Testpkg.MinInt32); + assertEquals("const MaxInt32", (1<<31) - 1, Testpkg.MaxInt32); + assertEquals("const MinInt64", -1L<<63, Testpkg.MinInt64); + assertEquals("const MaxInt64", (1L<<63) - 1, Testpkg.MaxInt64); + assertEquals("const SmallestNonzeroFloat64", 4.940656458412465441765687928682213723651e-324, Testpkg.SmallestNonzeroFloat64, 1e-323); + assertEquals("const MaxFloat64", 1.797693134862315708145274237317043567981e+308, Testpkg.MaxFloat64, 0.0001); + assertEquals("const SmallestNonzeroFloat32", 1.401298464324817070923729583289916131280e-45, Testpkg.SmallestNonzeroFloat32, 1e-44); + assertEquals("const MaxFloat32", 3.40282346638528859811704183484516925440e+38, Testpkg.MaxFloat32, 0.0001); + assertEquals("const Log2E", 1/0.693147180559945309417232121458176568075500134360255254120680009, Testpkg.Log2E, 0.0001); + } + + public void testRefMap() { + // Ensure that the RefMap.live count is kept in sync + // even a particular reference number is removed and + // added again + Seq.RefMap m = new Seq.RefMap(); + Seq.Ref r = new Seq.Ref(1, null); + m.put(r.refnum, r); + m.remove(r.refnum); + m.put(r.refnum, r); + // Force the RefMap to grow, to activate the sanity + // checking of the live count in RefMap.grow. + for (int i = 2; i < 24; i++) { + m.put(i, new Seq.Ref(i, null)); + } + } + + public void testVar() { + assertEquals("var StringVar", "a string var", Testpkg.getStringVar()); + + String newStringVar = "a new string var"; + Testpkg.setStringVar(newStringVar); + assertEquals("var StringVar", newStringVar, Testpkg.getStringVar()); + + assertEquals("var IntVar", 77, Testpkg.getIntVar()); + + long newIntVar = 777; + Testpkg.setIntVar(newIntVar); + assertEquals("var IntVar", newIntVar, Testpkg.getIntVar()); + + S s0 = Testpkg.getStructVar(); + assertEquals("var StructVar", "a struct var", s0.string()); + S s1 = Testpkg.new_(); + Testpkg.setStructVar(s1); + assertEquals("var StructVar", s1.string(), Testpkg.getStructVar().string()); + + AnI obj = new AnI(); + obj.name = "this is an I"; + Testpkg.setInterfaceVar(obj); + assertEquals("var InterfaceVar", obj.string(), Testpkg.getInterfaceVar().string()); + } + + public void testAssets() { + // Make sure that a valid context is set before reading assets + Seq.setContext(getInstrumentation().getContext()); + String want = "Hello, Assets.\n"; + String got = Testpkg.readAsset(); + assertEquals("Asset read", want, got); + } + + public void testAdd() { + long res = Testpkg.add(3, 4); + assertEquals("Unexpected arithmetic failure", 7, res); + } + + public void testBool() { + assertTrue(Testpkg.negate(false)); + assertFalse(Testpkg.negate(true)); + } + + public void testShortString() { + String want = "a short string"; + String got = Testpkg.strDup(want); + assertEquals("Strings should match", want, got); + + want = ""; + got = Testpkg.strDup(want); + assertEquals("Strings should match (empty string)", want, got); + + got = Testpkg.strDup(null); + assertEquals("Strings should match (null string)", want, got); + } + + public void testLongString() { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < 128*1024; i++) { + b.append("0123456789"); + } + String want = b.toString(); + String got = Testpkg.strDup(want); + assertEquals("Strings should match", want, got); + } + + public void testUnicode() { + String[] tests = new String[]{ + "abcxyz09{}", + "Hello, 世界", + "\uffff\uD800\uDC00\uD800\uDC01\uD808\uDF45\uDBFF\uDFFF", + // From Go std lib tests in unicode/utf16/utf16_test.go + "\u0001\u0002\u0003\u0004", + "\uffff\ud800\udc00\ud800\udc01\ud808\udf45\udbff\udfff", + "\ud800a", + "\udfff" + }; + String[] wants = new String[]{ + "abcxyz09{}", + "Hello, 世界", + "\uffff\uD800\uDC00\uD800\uDC01\uD808\uDF45\uDBFF\uDFFF", + "\u0001\u0002\u0003\u0004", + "\uffff\ud800\udc00\ud800\udc01\ud808\udf45\udbff\udfff", + "\ufffda", + "\ufffd" + }; + for (int i = 0; i < tests.length; i++) { + String got = Testpkg.strDup(tests[i]); + String want = wants[i]; + assertEquals("Strings should match", want, got); + } + } + + public void testNilErr() throws Exception { + Testpkg.err(null); // returns nil, no exception + } + + public void testErr() { + String msg = "Go errors are dropped into the confusing space of exceptions"; + try { + Testpkg.err(msg); + fail("expected non-nil error to be turned into an exception"); + } catch (Exception e) { + assertEquals("messages should match", msg, e.getMessage()); + } + } + + public void testByteArray() { + for (int i = 0; i < 2048; i++) { + if (i == 0) { + byte[] got = Testpkg.bytesAppend(null, null); + assertEquals("Bytes(null+null) should match", (byte[])null, got); + got = Testpkg.bytesAppend(new byte[0], new byte[0]); + assertEquals("Bytes(empty+empty) should match", (byte[])null, got); + continue; + } + + byte[] want = new byte[i]; + new Random().nextBytes(want); + + byte[] s1 = null; + byte[] s2 = null; + if (i > 0) { + s1 = Arrays.copyOfRange(want, 0, 1); + } + if (i > 1) { + s2 = Arrays.copyOfRange(want, 1, i); + } + byte[] got = Testpkg.bytesAppend(s1, s2); + MoreAsserts.assertEquals("Bytes(len="+i+") should match", want, got); + } + } + + // Test for golang.org/issue/9486. + public void testByteArrayAfterString() { + byte[] bytes = new byte[1024]; + for (int i=0; i < bytes.length; i++) { + bytes[i] = 8; + } + + String stuff = "stuff"; + byte[] got = Testpkg.appendToString(stuff, bytes); + + try { + byte[] s = stuff.getBytes("UTF-8"); + byte[] want = new byte[s.length + bytes.length]; + System.arraycopy(s, 0, want, 0, s.length); + System.arraycopy(bytes, 0, want, s.length, bytes.length); + MoreAsserts.assertEquals("Bytes should match", want, got); + } catch (Exception e) { + fail("Cannot perform the test: " + e.toString()); + } + } + + public void testGoRefGC() { + S s = Testpkg.new_(); + runGC(); + long collected = Testpkg.numSCollected(); + assertEquals("Only S should be pinned", 0, collected); + + s = null; + runGC(); + collected = Testpkg.numSCollected(); + assertEquals("S should be collected", 1, collected); + } + + private class AnI implements I { + public void e() throws Exception { + throw new Exception("my exception from E"); + } + + boolean calledF; + public void f() { + calledF = true; + } + + public I i() { + return this; + } + + public S s() { + return Testpkg.new_(); + } + + public String stoString(S s) { + return s.string(); + } + + public long v() { + return 1234; + } + + public long ve() throws Exception { + throw new Exception("my exception from VE"); + } + + public String name; + + public String string() { + return name; + } + + } + + // TODO(hyangah): add tests for methods that take parameters. + + public void testInterfaceMethodReturnsError() { + final AnI obj = new AnI(); + try { + Testpkg.callE(obj); + fail("Expecting exception but none was thrown."); + } catch (Exception e) { + assertEquals("Error messages should match", "my exception from E", e.getMessage()); + } + } + + public void testInterfaceMethodVoid() { + final AnI obj = new AnI(); + Testpkg.callF(obj); + assertTrue("Want AnI.F to be called", obj.calledF); + } + + public void testInterfaceMethodReturnsInterface() { + AnI obj = new AnI(); + obj.name = "testing AnI.I"; + I i = Testpkg.callI(obj); + assertEquals("Want AnI.I to return itself", i.string(), obj.string()); + + runGC(); + + i = Testpkg.callI(obj); + assertEquals("Want AnI.I to return itself", i.string(), obj.string()); + } + + public void testInterfaceMethodReturnsStructPointer() { + final AnI obj = new AnI(); + for (int i = 0; i < 5; i++) { + S s = Testpkg.callS(obj); + runGC(); + } + } + + public void testInterfaceMethodTakesStructPointer() { + final AnI obj = new AnI(); + S s = Testpkg.callS(obj); + String got = obj.stoString(s); + String want = s.string(); + assertEquals("Want AnI.StoString(s) to call s's String", want, got); + } + + public void testInterfaceMethodReturnsInt() { + final AnI obj = new AnI(); + assertEquals("Values must match", 1234, Testpkg.callV(obj)); + } + + public void testInterfaceMethodReturnsIntOrError() { + final AnI obj = new AnI(); + try { + long v = Testpkg.callVE(obj); + fail("Expecting exception but none was thrown and got value " + v); + } catch (Exception e) { + assertEquals("Error messages should match", "my exception from VE", e.getMessage()); + } + } + + boolean finalizedAnI; + + private class AnI_Traced extends AnI { + @Override + public void finalize() throws Throwable { + finalizedAnI = true; + super.finalize(); + } + } + + public void testJavaRefKeep() { + finalizedAnI = false; + AnI obj = new AnI_Traced(); + Testpkg.callF(obj); + assertTrue("want F to be called", obj.calledF); + Testpkg.callF(obj); + obj = null; + int attempts = 0; + while (true) { + runGC(); + if (finalizedAnI) + break; + attempts++; + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + if (attempts >= 10) + fail("want obj not to be kept by Go; tried " + attempts + " garbage collections."); + } + + finalizedAnI = false; + obj = new AnI_Traced(); + Testpkg.keep(obj); + obj = null; + runGC(); + assertFalse("want obj to be kept live by Go", finalizedAnI); + } + + private int countI = 0; + + private class CountI implements I { + public void f() { countI++; } + + public void e() throws Exception {} + public I i() { return null; } + public S s() { return null; } + public String stoString(S s) { return ""; } + public long v() { return 0; } + public long ve() throws Exception { return 0; } + public String string() { return ""; } + } + + public void testGoRefMapGrow() { + CountI obj = new CountI(); + Testpkg.keep(obj); + + // Push active references beyond base map size. + for (int i = 0; i < 24; i++) { + CountI o = new CountI(); + Testpkg.callF(o); + if (i%3==0) { + Testpkg.keep(o); + } + } + runGC(); + for (int i = 0; i < 128; i++) { + Testpkg.callF(new CountI()); + } + + Testpkg.callF(obj); // original object needs to work. + + assertEquals(countI, 1+24+128); + } + + private void runGC() { + System.gc(); + System.runFinalization(); + Testpkg.gc(); + System.gc(); + System.runFinalization(); + } + + public void testUnnamedParams() { + final String msg = "1234567"; + assertEquals("want the length of \"1234567\" passed after unnamed params", + 7, Testpkg.unnamedParams(10, 20, msg)); + } + + public void testPointerToStructAsField() { + Node a = Testpkg.newNode("A"); + Node b = Testpkg.newNode("B"); + a.setNext(b); + String got = a.string(); + assertEquals("want Node A points to Node B", "A:B:", got); + } + + public void testImplementsInterface() { + Interface intf = Testpkg.newConcrete(); + } + + public void testErrorField() { + Node n = Testpkg.newNode("ErrTest"); + Exception want = new Exception("an error message"); + n.setErr(want); + Exception got = n.getErr(); + assertTrue("want back the error we set", want == got); + String msg = Testpkg.errorMessage(want); + assertEquals("the error message must match", want.getMessage(), msg); + } + + public void testErrorDup() { + Exception err = Testpkg.getGlobalErr(); + assertTrue("the Go error instance must preserve its identity", Testpkg.isGlobalErr(err)); + assertEquals("the Go error message must be preserved", "global err", err.getMessage()); + } + + //test if we have JNI local reference table overflow error + public void testLocalReferenceOverflow() { + Testpkg.callWithCallback(new GoCallback() { + + @Override + public void varUpdate() { + //do nothing + } + }); + } + + public void testNullReferences() { + assertTrue(Testpkg.callWithNull(null, new NullTest() { + public NullTest null_() { + return null; + } + })); + assertEquals("Go nil interface is null", null, Testpkg.newNullInterface()); + assertEquals("Go nil struct pointer is null", null, Testpkg.newNullStruct()); + + Issue20330 nullArger = new Issue20330(); + assertTrue(nullArger.callWithNull(null)); + } + + public void testPassByteArray() { + Testpkg.passByteArray(new B() { + @Override public void b(byte[] b) { + byte[] want = new byte[]{1, 2, 3, 4}; + MoreAsserts.assertEquals("bytes should match", want, b); + } + }); + } + + public void testReader() { + byte[] b = new byte[8]; + try { + long n = Testpkg.readIntoByteArray(b); + assertEquals("wrote to the entire byte array", b.length, n); + byte[] want = new byte[b.length]; + for (int i = 0; i < want.length; i++) + want[i] = (byte)i; + MoreAsserts.assertEquals("bytes should match", want, b); + } catch (Exception e) { + fail("Failed to write: " + e.toString()); + } + } + + public void testGoroutineCallback() { + Testpkg.goroutineCallback(new Receiver() { + @Override public void hello(String msg) { + } + }); + } + + public void testImportedPkg() { + Testpkg.callImportedI(new secondpkg.I() { + @Override public long f(long i) { + return i; + } + }); + assertEquals("imported string should match", Secondpkg.HelloString, Secondpkg.hello()); + secondpkg.I i = Testpkg.newImportedI(); + secondpkg.S s = Testpkg.newImportedS(); + i = Testpkg.getImportedVarI(); + s = Testpkg.getImportedVarS(); + assertEquals("numbers should match", 8, i.f(8)); + assertEquals("numbers should match", 8, s.f(8)); + Testpkg.setImportedVarI(i); + Testpkg.setImportedVarS(s); + ImportedFields fields = Testpkg.newImportedFields(); + i = fields.getI(); + s = fields.getS(); + fields.setI(i); + fields.setS(s); + Testpkg.withImportedI(i); + Testpkg.withImportedS(s); + + secondpkg.IF f = new AnI(); + f = Testpkg.new_(); + secondpkg.Ser ser = Testpkg.newSer(); + } + + public void testRoundtripEquality() { + I want = new AnI(); + assertTrue("java object passed through Go should not be wrapped", want == Testpkg.iDup(want)); + InterfaceDupper idup = new InterfaceDupper(){ + @Override public Interface iDup(Interface i) { + return i; + } + }; + assertTrue("Go interface passed through Java should not be wrapped", Testpkg.callIDupper(idup)); + ConcreteDupper cdup = new ConcreteDupper(){ + @Override public Concrete cDup(Concrete c) { + return c; + } + }; + assertTrue("Go struct passed through Java should not be wrapped", Testpkg.callCDupper(cdup)); + } + + public void testConstructor() { + Interface i = new Concrete(); + i.f(); + + S2 s = new S2(1, 2); + assertEquals("new S2().sum", 3.0, s.sum()); + assertEquals("new S2().tryTwoStrings", "gostring", s.tryTwoStrings("go", "string")); + + new S3(); + + S4 s4 = new S4(123); + assertEquals("Constructor argument", 123, s4.getI()); + + s4 = new S4(123.456); + assertEquals("Overloaded constructor argument", 123, s4.getI()); + + s4 = new S4(false); + assertEquals("Exceptional constructor", 0, s4.getI()); + + try { + s4 = new S4(true); + fail("Constructor error wasn't caught"); + } catch (Exception e) { + } + } + + public void testEmptyError() { + try { + Testpkg.emptyError(); + fail("Empty error wasn't caught"); + } catch (Exception e) { + } + EmptyErrorer empty = new EmptyErrorer() { + @Override public void emptyError() throws Exception { + throw new Exception(""); + } + }; + try { + Testpkg.callEmptyError(empty); + fail("Empty exception wasn't caught"); + } catch (Exception e) { + } + } + + public void testInitCaller() { + Testpkg.init(); + + InitCaller initer = Testpkg.newInitCaller(); + initer.init(); + } + + public void testSIGPIPE() { + Testpkg.testSIGPIPE(); + } + + public void testTags() { + assertEquals("Constant from a tagged file", 42, Testpkg.TaggedConst); + } + + public void testClassNameWithPackageName() { + testpkg.Testpkg_ o = new secondpkg.Secondpkg_(); + secondpkg.Secondpkg_ o2 = Secondpkg.newSecondpkg(); + o2.m(); + o2.setV("hi"); + assertEquals(o2.getV(), "hi"); + Testpkg.clashingParameterFromOtherPackage(o2); + } +} diff --git a/bind/java/context_android.c b/bind/java/context_android.c new file mode 100644 index 000000000..66ce56915 --- /dev/null +++ b/bind/java/context_android.c @@ -0,0 +1,16 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include +#include "seq_android.h" +#include "_cgo_export.h" + +JNIEXPORT void JNICALL +Java_go_Seq_setContext(JNIEnv* env, jclass clazz, jobject ctx) { + JavaVM* vm; + if ((*env)->GetJavaVM(env, &vm) != 0) { + LOG_FATAL("failed to get JavaVM"); + } + setContext(vm, (*env)->NewGlobalRef(env, ctx)); +} diff --git a/bind/java/context_android.go b/bind/java/context_android.go new file mode 100644 index 000000000..dc4443130 --- /dev/null +++ b/bind/java/context_android.go @@ -0,0 +1,21 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package java // import "golang.org/x/mobile/bind/java" + +// #cgo LDFLAGS: -llog +// +//#include +import "C" + +import ( + "unsafe" + + "golang.org/x/mobile/internal/mobileinit" +) + +//export setContext +func setContext(vm *C.JavaVM, ctx C.jobject) { + mobileinit.SetCurrentContext(unsafe.Pointer(vm), uintptr(ctx)) +} diff --git a/bind/java/doc.go b/bind/java/doc.go new file mode 100644 index 000000000..a2c1aa41b --- /dev/null +++ b/bind/java/doc.go @@ -0,0 +1,8 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package java implements the Java language bindings. +// +// See the design document (http://golang.org/s/gobind). +package java diff --git a/bind/java/seq_android.c.support b/bind/java/seq_android.c.support new file mode 100644 index 000000000..77ec5f4ae --- /dev/null +++ b/bind/java/seq_android.c.support @@ -0,0 +1,401 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// C support functions for bindings. This file is copied into the +// generated gomobile_bind package and compiled along with the +// generated binding files. + +#include +#include +#include +#include +#include +#include +#include +#include +#include "seq.h" +#include "_cgo_export.h" + +#define NULL_REFNUM 41 + +// initClasses are only exported from Go if reverse bindings are used. +// If they're not, weakly define a no-op function. +__attribute__((weak)) void initClasses(void) { } + +static JavaVM *jvm; +// jnienvs holds the per-thread JNIEnv* for Go threads where we called AttachCurrentThread. +// A pthread key destructor is supplied to call DetachCurrentThread on exit. This trick is +// documented in http://developer.android.com/training/articles/perf-jni.html under "Threads". +static pthread_key_t jnienvs; + +static jclass seq_class; +static jmethodID seq_getRef; +static jmethodID seq_decRef; +static jmethodID seq_incRef; +static jmethodID seq_incGoObjectRef; +static jmethodID seq_incRefnum; + +static jfieldID ref_objField; + +static jclass throwable_class; + +// env_destructor is registered as a thread data key destructor to +// clean up a Go thread that is attached to the JVM. +static void env_destructor(void *env) { + if ((*jvm)->DetachCurrentThread(jvm) != JNI_OK) { + LOG_INFO("failed to detach current thread"); + } +} + +static JNIEnv *go_seq_get_thread_env(void) { + JNIEnv *env; + jint ret = (*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_6); + if (ret != JNI_OK) { + if (ret != JNI_EDETACHED) { + LOG_FATAL("failed to get thread env"); + } + if ((*jvm)->AttachCurrentThread(jvm, &env, NULL) != JNI_OK) { + LOG_FATAL("failed to attach current thread"); + } + pthread_setspecific(jnienvs, env); + } + return env; +} + +void go_seq_maybe_throw_exception(JNIEnv *env, jobject exc) { + if (exc != NULL) { + (*env)->Throw(env, exc); + } +} + +jobject go_seq_get_exception(JNIEnv *env) { + jthrowable exc = (*env)->ExceptionOccurred(env); + if (!exc) { + return NULL; + } + (*env)->ExceptionClear(env); + return exc; +} + +jbyteArray go_seq_to_java_bytearray(JNIEnv *env, nbyteslice s, int copy) { + if (s.ptr == NULL) { + return NULL; + } + jbyteArray res = (*env)->NewByteArray(env, s.len); + if (res == NULL) { + LOG_FATAL("NewByteArray failed"); + } + (*env)->SetByteArrayRegion(env, res, 0, s.len, s.ptr); + if (copy) { + free(s.ptr); + } + return res; +} + +#define surr1 0xd800 +#define surr2 0xdc00 +#define surr3 0xe000 + +// Unicode replacement character +#define replacementChar 0xFFFD + +#define rune1Max ((1<<7) - 1) +#define rune2Max ((1<<11) - 1) +#define rune3Max ((1<<16) - 1) +// Maximum valid Unicode code point. +#define MaxRune 0x0010FFFF + +#define surrogateMin 0xD800 +#define surrogateMax 0xDFFF +// 0011 1111 +#define maskx 0x3F +// 1000 0000 +#define tx 0x80 +// 1100 0000 +#define t2 0xC0 +// 1110 0000 +#define t3 0xE0 +// 1111 0000 +#define t4 0xF0 + +// encode_rune writes into p (which must be large enough) the UTF-8 encoding +// of the rune. It returns the number of bytes written. +static int encode_rune(uint8_t *p, uint32_t r) { + if (r <= rune1Max) { + p[0] = (uint8_t)r; + return 1; + } else if (r <= rune2Max) { + p[0] = t2 | (uint8_t)(r>>6); + p[1] = tx | (((uint8_t)(r))&maskx); + return 2; + } else { + if (r > MaxRune || (surrogateMin <= r && r <= surrogateMax)) { + r = replacementChar; + } + if (r <= rune3Max) { + p[0] = t3 | (uint8_t)(r>>12); + p[1] = tx | (((uint8_t)(r>>6))&maskx); + p[2] = tx | (((uint8_t)(r))&maskx); + return 3; + } else { + p[0] = t4 | (uint8_t)(r>>18); + p[1] = tx | (((uint8_t)(r>>12))&maskx); + p[2] = tx | (((uint8_t)(r>>6))&maskx); + p[3] = tx | (((uint8_t)(r))&maskx); + return 4; + } + } +} + +// utf16_decode decodes an array of UTF16 characters to a UTF-8 encoded +// nstring copy. The support functions and utf16_decode itself are heavily +// based on the unicode/utf8 and unicode/utf16 Go packages. +static nstring utf16_decode(jchar *chars, jsize len) { + jsize worstCaseLen = 4*len; + uint8_t *buf = malloc(worstCaseLen); + if (buf == NULL) { + LOG_FATAL("utf16Decode: malloc failed"); + } + jsize nsrc = 0; + jsize ndst = 0; + while (nsrc < len) { + uint32_t r = chars[nsrc]; + nsrc++; + if (surr1 <= r && r < surr2 && nsrc < len) { + uint32_t r2 = chars[nsrc]; + if (surr2 <= r2 && r2 < surr3) { + nsrc++; + r = (((r-surr1)<<10) | (r2 - surr2)) + 0x10000; + } + } + if (ndst + 4 > worstCaseLen) { + LOG_FATAL("utf16Decode: buffer overflow"); + } + ndst += encode_rune(buf + ndst, r); + } + struct nstring res = {.chars = buf, .len = ndst}; + return res; +} + +nstring go_seq_from_java_string(JNIEnv *env, jstring str) { + struct nstring res = {NULL, 0}; + if (str == NULL) { + return res; + } + jsize nchars = (*env)->GetStringLength(env, str); + if (nchars == 0) { + return res; + } + jchar *chars = (jchar *)(*env)->GetStringChars(env, str, NULL); + if (chars == NULL) { + LOG_FATAL("GetStringChars failed"); + } + nstring nstr = utf16_decode(chars, nchars); + (*env)->ReleaseStringChars(env, str, chars); + return nstr; +} + +nbyteslice go_seq_from_java_bytearray(JNIEnv *env, jbyteArray arr, int copy) { + struct nbyteslice res = {NULL, 0}; + if (arr == NULL) { + return res; + } + + jsize len = (*env)->GetArrayLength(env, arr); + if (len == 0) { + return res; + } + jbyte *ptr = (*env)->GetByteArrayElements(env, arr, NULL); + if (ptr == NULL) { + LOG_FATAL("GetByteArrayElements failed"); + } + if (copy) { + void *ptr_copy = (void *)malloc(len); + if (ptr_copy == NULL) { + LOG_FATAL("malloc failed"); + } + memcpy(ptr_copy, ptr, len); + (*env)->ReleaseByteArrayElements(env, arr, ptr, JNI_ABORT); + ptr = (jbyte *)ptr_copy; + } + res.ptr = ptr; + res.len = len; + return res; +} + +int32_t go_seq_to_refnum_go(JNIEnv *env, jobject o) { + if (o == NULL) { + return NULL_REFNUM; + } + return (int32_t)(*env)->CallStaticIntMethod(env, seq_class, seq_incGoObjectRef, o); +} + +int32_t go_seq_to_refnum(JNIEnv *env, jobject o) { + if (o == NULL) { + return NULL_REFNUM; + } + return (int32_t)(*env)->CallStaticIntMethod(env, seq_class, seq_incRef, o); +} + +int32_t go_seq_unwrap(jint refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject jobj = go_seq_from_refnum(env, refnum, NULL, NULL); + int32_t goref = go_seq_to_refnum_go(env, jobj); + go_seq_pop_local_frame(env); + return goref; +} + +jobject go_seq_from_refnum(JNIEnv *env, int32_t refnum, jclass proxy_class, jmethodID proxy_cons) { + if (refnum == NULL_REFNUM) { + return NULL; + } + if (refnum < 0) { // Go object + // return new (refnum) + return (*env)->NewObject(env, proxy_class, proxy_cons, refnum); + } + // Seq.Ref ref = Seq.getRef(refnum) + jobject ref = (*env)->CallStaticObjectMethod(env, seq_class, seq_getRef, (jint)refnum); + if (ref == NULL) { + LOG_FATAL("Unknown reference: %d", refnum); + } + // Go incremented the reference count just before passing the refnum. Decrement it here. + (*env)->CallStaticVoidMethod(env, seq_class, seq_decRef, (jint)refnum); + // return ref.obj + return (*env)->GetObjectField(env, ref, ref_objField); +} + +// go_seq_to_java_string converts a nstring to a jstring. +jstring go_seq_to_java_string(JNIEnv *env, nstring str) { + jstring s = (*env)->NewString(env, str.chars, str.len/2); + if (str.chars != NULL) { + free(str.chars); + } + return s; +} + +// go_seq_push_local_frame retrieves or creates the JNIEnv* for the current thread +// and pushes a JNI reference frame. Must be matched with call to go_seq_pop_local_frame. +JNIEnv *go_seq_push_local_frame(jint nargs) { + JNIEnv *env = go_seq_get_thread_env(); + // Given the number of function arguments, compute a conservative bound for the minimal frame size. + // Assume two slots for each per parameter (Seq.Ref and Seq.Object) and add extra + // extra space for the receiver, the return value, and exception (if any). + jint frameSize = 2*nargs + 10; + if ((*env)->PushLocalFrame(env, frameSize) < 0) { + LOG_FATAL("PushLocalFrame failed"); + } + return env; +} + +// Pop the current local frame, freeing all JNI local references in it +void go_seq_pop_local_frame(JNIEnv *env) { + (*env)->PopLocalFrame(env, NULL); +} + +void go_seq_inc_ref(int32_t ref) { + JNIEnv *env = go_seq_get_thread_env(); + (*env)->CallStaticVoidMethod(env, seq_class, seq_incRefnum, (jint)ref); +} + +void go_seq_dec_ref(int32_t ref) { + JNIEnv *env = go_seq_get_thread_env(); + (*env)->CallStaticVoidMethod(env, seq_class, seq_decRef, (jint)ref); +} + +JNIEXPORT void JNICALL +Java_go_Seq_init(JNIEnv *env, jclass clazz) { + if ((*env)->GetJavaVM(env, &jvm) != 0) { + LOG_FATAL("failed to get JVM"); + } + if (pthread_key_create(&jnienvs, env_destructor) != 0) { + LOG_FATAL("failed to initialize jnienvs thread local storage"); + } + + seq_class = (*env)->NewGlobalRef(env, clazz); + seq_getRef = (*env)->GetStaticMethodID(env, seq_class, "getRef", "(I)Lgo/Seq$Ref;"); + if (seq_getRef == NULL) { + LOG_FATAL("failed to find method Seq.getRef"); + } + seq_decRef = (*env)->GetStaticMethodID(env, seq_class, "decRef", "(I)V"); + if (seq_decRef == NULL) { + LOG_FATAL("failed to find method Seq.decRef"); + } + seq_incRefnum = (*env)->GetStaticMethodID(env, seq_class, "incRefnum", "(I)V"); + if (seq_incRefnum == NULL) { + LOG_FATAL("failed to find method Seq.incRefnum"); + } + seq_incRef = (*env)->GetStaticMethodID(env, seq_class, "incRef", "(Ljava/lang/Object;)I"); + if (seq_incRef == NULL) { + LOG_FATAL("failed to find method Seq.incRef"); + } + seq_incGoObjectRef = (*env)->GetStaticMethodID(env, seq_class, "incGoObjectRef", "(Lgo/Seq$GoObject;)I"); + if (seq_incGoObjectRef == NULL) { + LOG_FATAL("failed to find method Seq.incGoObjectRef"); + } + jclass ref_class = (*env)->FindClass(env, "go/Seq$Ref"); + if (ref_class == NULL) { + LOG_FATAL("failed to find the Seq.Ref class"); + } + ref_objField = (*env)->GetFieldID(env, ref_class, "obj", "Ljava/lang/Object;"); + if (ref_objField == NULL) { + LOG_FATAL("failed to find the Seq.Ref.obj field"); + } + initClasses(); +} + +JNIEXPORT void JNICALL +Java_go_Seq_destroyRef(JNIEnv *env, jclass clazz, jint refnum) { + DestroyRef(refnum); +} + +JNIEXPORT void JNICALL +Java_go_Seq_incGoRef(JNIEnv *env, jclass clazz, jint refnum, jobject ref) { + IncGoRef(refnum); +} + +jclass go_seq_find_class(const char *name) { + JNIEnv *env = go_seq_push_local_frame(0); + jclass clazz = (*env)->FindClass(env, name); + if (clazz == NULL) { + (*env)->ExceptionClear(env); + } else { + clazz = (*env)->NewGlobalRef(env, clazz); + } + go_seq_pop_local_frame(env); + return clazz; +} + +jmethodID go_seq_get_static_method_id(jclass clazz, const char *name, const char *sig) { + JNIEnv *env = go_seq_push_local_frame(0); + jmethodID m = (*env)->GetStaticMethodID(env, clazz, name, sig); + if (m == NULL) { + (*env)->ExceptionClear(env); + } + go_seq_pop_local_frame(env); + return m; +} + +jmethodID go_seq_get_method_id(jclass clazz, const char *name, const char *sig) { + JNIEnv *env = go_seq_push_local_frame(0); + jmethodID m = (*env)->GetMethodID(env, clazz, name, sig); + if (m == NULL) { + (*env)->ExceptionClear(env); + } + go_seq_pop_local_frame(env); + return m; +} + +void go_seq_release_byte_array(JNIEnv *env, jbyteArray arr, jbyte* ptr) { + if (ptr != NULL) { + (*env)->ReleaseByteArrayElements(env, arr, ptr, 0); + } +} + +int go_seq_isinstanceof(jint refnum, jclass clazz) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject obj = go_seq_from_refnum(env, refnum, NULL, NULL); + jboolean isinst = (*env)->IsInstanceOf(env, obj, clazz); + go_seq_pop_local_frame(env); + return isinst; +} diff --git a/bind/java/seq_android.go.support b/bind/java/seq_android.go.support new file mode 100644 index 000000000..a83229268 --- /dev/null +++ b/bind/java/seq_android.go.support @@ -0,0 +1,98 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Go support functions for bindings. This file is copied into the +// generated main package and compiled along with the generated binding +// files. + +//#cgo CFLAGS: -Werror +//#cgo LDFLAGS: -llog +//#include +//#include +//#include +//#include "seq_android.h" +import "C" +import ( + "unsafe" + + "golang.org/x/mobile/bind/seq" +) + +// DestroyRef is called by Java to inform Go it is done with a reference. +//export DestroyRef +func DestroyRef(refnum C.int32_t) { + seq.Delete(int32(refnum)) +} + +// encodeString returns a copy of a Go string as a UTF16 encoded nstring. +// The returned data is freed in go_seq_to_java_string. +// +// encodeString uses UTF16 as the intermediate format. Note that UTF8 is an obvious +// alternative, but JNI only supports a C-safe variant of UTF8 (modified UTF8). +func encodeString(s string) C.nstring { + n := C.int(len(s)) + if n == 0 { + return C.nstring{} + } + // Allocate enough for the worst case estimate, every character is a surrogate pair + worstCaseLen := 4 * len(s) + utf16buf := C.malloc(C.size_t(worstCaseLen)) + if utf16buf == nil { + panic("encodeString: malloc failed") + } + chars := (*[1<<30 - 1]uint16)(unsafe.Pointer(utf16buf))[:worstCaseLen/2 : worstCaseLen/2] + nchars := seq.UTF16Encode(s, chars) + return C.nstring{chars: unsafe.Pointer(utf16buf), len: C.jsize(nchars*2)} +} + +// decodeString decodes a UTF8 encoded nstring to a Go string. The data +// in str is freed after use. +func decodeString(str C.nstring) string { + if str.chars == nil { + return "" + } + chars := (*[1<<31 - 1]byte)(str.chars)[:str.len] + s := string(chars) + C.free(str.chars) + return s +} + +// fromSlice converts a slice to a jbyteArray cast as a nbyteslice. If cpy +// is set, the returned slice is a copy to be free by go_seq_to_java_bytearray. +func fromSlice(s []byte, cpy bool) C.nbyteslice { + if s == nil || len(s) == 0 { + return C.nbyteslice{} + } + var ptr *C.jbyte + n := C.jsize(len(s)) + if cpy { + ptr = (*C.jbyte)(C.malloc(C.size_t(n))) + if ptr == nil { + panic("fromSlice: malloc failed") + } + copy((*[1<<31 - 1]byte)(unsafe.Pointer(ptr))[:n], s) + } else { + ptr = (*C.jbyte)(unsafe.Pointer(&s[0])) + } + return C.nbyteslice{ptr: unsafe.Pointer(ptr), len: n} +} + +// toSlice takes a nbyteslice (jbyteArray) and returns a byte slice +// with the data. If cpy is set, the slice contains a copy of the data and is +// freed. +func toSlice(s C.nbyteslice, cpy bool) []byte { + if s.ptr == nil || s.len == 0 { + return nil + } + var b []byte + if cpy { + b = C.GoBytes(s.ptr, C.int(s.len)) + C.free(s.ptr) + } else { + b = (*[1<<31 - 1]byte)(unsafe.Pointer(s.ptr))[:s.len:s.len] + } + return b +} diff --git a/bind/java/seq_android.h b/bind/java/seq_android.h new file mode 100644 index 000000000..26e90251e --- /dev/null +++ b/bind/java/seq_android.h @@ -0,0 +1,67 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef __GO_SEQ_ANDROID_HDR__ +#define __GO_SEQ_ANDROID_HDR__ + +#include +#include +// For abort() +#include +#include + +#define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "go/Seq", __VA_ARGS__) +#define LOG_FATAL(...) \ + { \ + __android_log_print(ANDROID_LOG_FATAL, "go/Seq", __VA_ARGS__); \ + abort(); \ + } + +// Platform specific types +typedef struct nstring { + // UTF16 or UTF8 Encoded string. When converting from Java string to Go + // string, UTF16. When converting from Go to Java, UTF8. + void *chars; + // length in bytes, regardless of encoding + jsize len; +} nstring; +typedef struct nbyteslice { + void *ptr; + jsize len; +} nbyteslice; +typedef jlong nint; + +extern void go_seq_dec_ref(int32_t ref); +extern void go_seq_inc_ref(int32_t ref); +// go_seq_unwrap takes a reference number to a Java wrapper and returns +// a reference number to its wrapped Go object. +extern int32_t go_seq_unwrap(jint refnum); +extern int32_t go_seq_to_refnum(JNIEnv *env, jobject o); +extern int32_t go_seq_to_refnum_go(JNIEnv *env, jobject o); +extern jobject go_seq_from_refnum(JNIEnv *env, int32_t refnum, jclass proxy_class, jmethodID proxy_cons); + +extern void go_seq_maybe_throw_exception(JNIEnv *env, jobject msg); +// go_seq_get_exception returns any pending exception and clears the exception status. +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 void go_seq_release_byte_array(JNIEnv *env, jbyteArray arr, jbyte* ptr); + +extern jstring go_seq_to_java_string(JNIEnv *env, nstring str); +extern nstring go_seq_from_java_string(JNIEnv *env, jstring s); + +// push_local_frame retrieves or creates the JNIEnv* for the current thread +// and pushes a JNI reference frame. Must be matched with call to pop_local_frame. +extern JNIEnv *go_seq_push_local_frame(jint cap); +// Pop the current local frame, releasing all JNI local references in it +extern void go_seq_pop_local_frame(JNIEnv *env); + +// Return a global reference to the given class. Return NULL and clear exception if not found. +extern jclass go_seq_find_class(const char *name); +extern jmethodID go_seq_get_static_method_id(jclass clazz, const char *name, const char *sig); +extern jmethodID go_seq_get_method_id(jclass clazz, const char *name, const char *sig); +extern int go_seq_isinstanceof(jint refnum, jclass clazz); + +#endif // __GO_SEQ_ANDROID_HDR__ diff --git a/bind/java/seq_test.go b/bind/java/seq_test.go new file mode 100644 index 000000000..a5151d40b --- /dev/null +++ b/bind/java/seq_test.go @@ -0,0 +1,257 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package java + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + + "golang.org/x/mobile/internal/importers/java" + "golang.org/x/mobile/internal/sdkpath" +) + +var gomobileBin string + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +func testMain(m *testing.M) int { + // Build gomobile and gobind and put them into PATH. + binDir, err := ioutil.TempDir("", "bind-java-test-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(binDir) + exe := "" + if runtime.GOOS == "windows" { + exe = ".exe" + } + if runtime.GOOS != "android" { + gocmd := filepath.Join(runtime.GOROOT(), "bin", "go") + gomobileBin = filepath.Join(binDir, "gomobile"+exe) + gobindBin := filepath.Join(binDir, "gobind"+exe) + if out, err := exec.Command(gocmd, "build", "-o", gomobileBin, "golang.org/x/mobile/cmd/gomobile").CombinedOutput(); err != nil { + log.Fatalf("gomobile build failed: %v: %s", err, out) + } + if out, err := exec.Command(gocmd, "build", "-o", gobindBin, "golang.org/x/mobile/cmd/gobind").CombinedOutput(); err != nil { + log.Fatalf("gobind build failed: %v: %s", err, out) + } + path := binDir + if oldPath := os.Getenv("PATH"); oldPath != "" { + path += string(filepath.ListSeparator) + oldPath + } + os.Setenv("PATH", path) + } + return m.Run() +} + +func TestClasses(t *testing.T) { + if !java.IsAvailable() { + t.Skipf("java importer is not available") + } + runTest(t, []string{ + "golang.org/x/mobile/bind/testdata/testpkg/javapkg", + }, "", "ClassesTest") +} + +func TestCustomPkg(t *testing.T) { + runTest(t, []string{ + "golang.org/x/mobile/bind/testdata/testpkg", + }, "org.golang.custompkg", "CustomPkgTest") +} + +func TestJavaSeqTest(t *testing.T) { + runTest(t, []string{ + "golang.org/x/mobile/bind/testdata/testpkg", + "golang.org/x/mobile/bind/testdata/testpkg/secondpkg", + "golang.org/x/mobile/bind/testdata/testpkg/simplepkg", + }, "", "SeqTest") +} + +// TestJavaSeqBench runs java test SeqBench.java, with the same +// environment requirements as TestJavaSeqTest. +// +// The benchmarks runs on the phone, so the benchmarkpkg implements +// rudimentary timing logic and outputs benchcmp compatible runtimes +// to logcat. Use +// +// adb logcat -v raw GoLog:* *:S +// +// while running the benchmark to see the results. +func TestJavaSeqBench(t *testing.T) { + if testing.Short() { + t.Skip("skipping benchmark in short mode.") + } + runTest(t, []string{"golang.org/x/mobile/bind/testdata/benchmark"}, "", "SeqBench") +} + +// runTest runs the Android java test class specified with javaCls. If javaPkg is +// set, it is passed with the -javapkg flag to gomobile. The pkgNames lists the Go +// packages to bind for the test. +// This requires the gradle command to be in PATH and the Android SDK to be +// installed. +func runTest(t *testing.T, pkgNames []string, javaPkg, javaCls string) { + if gomobileBin == "" { + t.Skipf("no gomobile on %s", runtime.GOOS) + } + gradle, err := exec.LookPath("gradle") + if err != nil { + t.Skip("command gradle not found, skipping") + } + if _, err := sdkpath.AndroidHome(); err != nil { + t.Skip("Android SDK not found, skipping") + } + + cwd, err := os.Getwd() + if err != nil { + t.Fatalf("failed pwd: %v", err) + } + tmpdir, err := ioutil.TempDir("", "bind-java-seq-test-") + if err != nil { + t.Fatalf("failed to prepare temp dir: %v", err) + } + defer os.RemoveAll(tmpdir) + t.Logf("tmpdir = %s", tmpdir) + + if err := os.Chdir(tmpdir); err != nil { + t.Fatalf("failed chdir: %v", err) + } + defer os.Chdir(cwd) + + for _, d := range []string{"src/main", "src/androidTest/java/go", "libs", "src/main/res/values"} { + err = os.MkdirAll(filepath.Join(tmpdir, d), 0700) + if err != nil { + t.Fatal(err) + } + } + + args := []string{"bind", "-tags", "aaa bbb", "-o", "pkg.aar"} + if javaPkg != "" { + args = append(args, "-javapkg", javaPkg) + } + args = append(args, pkgNames...) + cmd := exec.Command(gomobileBin, args...) + // Reverse binding doesn't work with Go module since imports starting with Java or ObjC are not valid FQDNs. + // Disable Go module explicitly until this problem is solved. See golang/go#27234. + cmd.Env = append(os.Environ(), "GO111MODULE=off") + buf, err := cmd.CombinedOutput() + if err != nil { + t.Logf("%s", buf) + t.Fatalf("failed to run gomobile bind: %v", err) + } + + fname := filepath.Join(tmpdir, "libs", "pkg.aar") + err = cp(fname, filepath.Join(tmpdir, "pkg.aar")) + if err != nil { + t.Fatalf("failed to copy pkg.aar: %v", err) + } + + fname = filepath.Join(tmpdir, "src/androidTest/java/go/"+javaCls+".java") + err = cp(fname, filepath.Join(cwd, javaCls+".java")) + if err != nil { + t.Fatalf("failed to copy SeqTest.java: %v", err) + } + + fname = filepath.Join(tmpdir, "src/main/AndroidManifest.xml") + err = ioutil.WriteFile(fname, []byte(androidmanifest), 0700) + if err != nil { + t.Fatalf("failed to write android manifest file: %v", err) + } + + // Add a dummy string resource to avoid errors from the Android build system. + fname = filepath.Join(tmpdir, "src/main/res/values/strings.xml") + err = ioutil.WriteFile(fname, []byte(stringsxml), 0700) + if err != nil { + t.Fatalf("failed to write strings.xml file: %v", err) + } + + fname = filepath.Join(tmpdir, "build.gradle") + err = ioutil.WriteFile(fname, []byte(buildgradle), 0700) + if err != nil { + t.Fatalf("failed to write build.gradle file: %v", err) + } + + if buf, err := run(gradle + " connectedAndroidTest"); err != nil { + t.Logf("%s", buf) + t.Errorf("failed to run gradle test: %v", err) + } +} + +func run(cmd string) ([]byte, error) { + c := strings.Split(cmd, " ") + return exec.Command(c[0], c[1:]...).CombinedOutput() +} + +func cp(dst, src string) error { + r, err := os.Open(src) + if err != nil { + return fmt.Errorf("failed to read source: %v", err) + } + defer r.Close() + w, err := os.Create(dst) + if err != nil { + return fmt.Errorf("failed to open destination: %v", err) + } + _, err = io.Copy(w, r) + cerr := w.Close() + if err != nil { + return err + } + return cerr +} + +const androidmanifest = ` + +` + +const buildgradle = `buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.0' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 'android-19' + defaultConfig { minSdkVersion 16 } +} + +repositories { + flatDir { dirs 'libs' } +} + +dependencies { + implementation(name: "pkg", ext: "aar") +} +` + +const stringsxml = ` + + dummy +` diff --git a/bind/objc/SeqBench.m b/bind/objc/SeqBench.m new file mode 100644 index 000000000..cff91680a --- /dev/null +++ b/bind/objc/SeqBench.m @@ -0,0 +1,197 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build ignore +// +build ignore + +#import +#import +#import "benchmark/Benchmark.h" + +@interface AnI : NSObject { +} +@end + +@implementation AnI +- (void)f { +} +@end + +@interface Benchmarks : NSObject { +} +@end + +@implementation Benchmarks +- (void)manyargs:(long)p0 p1:(long)p1 p2:(long)p2 p3:(long)p3 p4:(long)p4 p5:(long)p5 p6:(long)p6 p7:(long)p7 p8:(long)p8 p9:(long)p9 { +} + +- (id)newI { + return [[AnI alloc] init]; +} + +- (void)noargs { +} + +- (void)onearg:(long)p0 { +} + +- (long)oneret { + return 0; +} + +- (void)ref:(id)p0 { +} + +- (void)slice:(NSData*)p0 { +} + +- (void)string:(NSString*)p0 { +} + +- (NSString*)stringRetLong { + return BenchmarkLongString; +} + +- (NSString*)stringRetShort { + return BenchmarkShortString; +} + +- (void (^)(void))lookupBenchmark:(NSString *)name { + if ([name isEqualToString:@"Empty"]) { + return ^() { + }; + } else if ([name isEqualToString:@"Noargs"]) { + return ^() { + BenchmarkNoargs(); + }; + } else if ([name isEqualToString:@"Onearg"]) { + return ^() { + BenchmarkOnearg(0); + }; + } else if ([name isEqualToString:@"Manyargs"]) { + return ^() { + BenchmarkManyargs(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + }; + } else if ([name isEqualToString:@"Oneret"]) { + return ^() { + BenchmarkOneret(); + }; + } else if ([name isEqualToString:@"Refforeign"]) { + id objcRef = [[AnI alloc] init]; + return ^() { + BenchmarkRef(objcRef); + }; + } else if ([name isEqualToString:@"Refgo"]) { + id goRef = BenchmarkNewI(); + return ^() { + BenchmarkRef(goRef); + }; + } else if ([name isEqualToString:@"StringShort"]) { + return ^() { + BenchmarkString(BenchmarkShortString); + }; + } else if ([name isEqualToString:@"StringLong"]) { + return ^() { + BenchmarkString(BenchmarkLongString); + }; + } else if ([name isEqualToString:@"StringShortUnicode"]) { + return ^() { + BenchmarkString(BenchmarkShortStringUnicode); + }; + } else if ([name isEqualToString:@"StringLongUnicode"]) { + return ^() { + BenchmarkString(BenchmarkLongStringUnicode); + }; + } else if ([name isEqualToString:@"StringRetShort"]) { + return ^() { + BenchmarkStringRetShort(); + }; + } else if ([name isEqualToString:@"StringRetLong"]) { + return ^() { + BenchmarkStringRetLong(); + }; + } else if ([name isEqualToString:@"SliceShort"]) { + NSData *s = [Benchmark shortSlice]; + return ^() { + BenchmarkSlice(s); + }; + } else if ([name isEqualToString:@"SliceLong"]) { + NSData *s = [Benchmark longSlice]; + return ^() { + BenchmarkSlice(s); + }; + } else { + return nil; + } +} + +- (void)run:(NSString*)name n:(long)n { + void (^bench)(void) = [self lookupBenchmark:name]; + if (bench == nil) { + NSLog(@"Error: no such benchmark: %@", name); + return; + } + for (int i = 0; i < n; i++) { + bench(); + } +} + +- (void)runDirect:(NSString*)name n:(long)n { + void (^bench)(void) = [self lookupBenchmark:name]; + if (bench == nil) { + NSLog(@"Error: no such benchmark: %@", name); + return; + } + dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + for (int i = 0; i < n; i++) { + bench(); + } + }); +} + +@end + +@interface benchmarks : XCTestCase + +@end + +@implementation benchmarks + +- (void)setUp { + [super setUp]; + + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + self.continueAfterFailure = NO; + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + [[[XCUIApplication alloc] init] launch]; + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testBenchmark { + // Long running unit tests seem to hang. Use an XCTestExpectation and run the Go + // benchmark suite on a GCD thread. + XCTestExpectation *expectation = + [self expectationWithDescription:@"Benchmark"]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + Benchmarks *b = [[Benchmarks alloc] init]; + BenchmarkRunBenchmarks(b); + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:5*60.0 handler:^(NSError *error) { + if (error) { + NSLog(@"Timeout Error: %@", error); + } + }]; +} +@end diff --git a/bind/objc/SeqCustom.m b/bind/objc/SeqCustom.m new file mode 100644 index 000000000..ed94b3e24 --- /dev/null +++ b/bind/objc/SeqCustom.m @@ -0,0 +1,22 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build ignore +// +build ignore + +#import +#import +@import Testpkg; + +@interface tests : XCTestCase + +@end + +@implementation tests + +- (void)testBasics { + CustomTestpkgHi(); +} + +@end diff --git a/bind/objc/SeqTest.m b/bind/objc/SeqTest.m new file mode 100644 index 000000000..257d8b1fa --- /dev/null +++ b/bind/objc/SeqTest.m @@ -0,0 +1,481 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build ignore +// +build ignore + +#import +#import +#import "testpkg/Testpkg.h" + +// Objective-C implementation of testpkg.I2. +@interface Number : NSObject { +} +@property int32_t value; + +// TODO(hyangah): error:error is not good. +- (BOOL)error:(BOOL)e error:(NSError **)error; +- (int64_t)times:(int32_t)v; +@end + +// numI is incremented when the first numI objective-C implementation is +// deallocated. +static int numI = 0; + +@implementation Number { +} +@synthesize value; + +- (NSString *)stringError:(NSString *)s + error:(NSError **)error { + if ([s isEqualToString:@"number"]) { + return @"OK"; + } + *error = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:@{NSLocalizedDescriptionKey: @"NumberError"}]; + return NULL; +} + +- (BOOL)error:(BOOL)triggerError error:(NSError **)error { + if (!triggerError) { + return YES; + } + if (error != NULL) { + *error = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:NULL]; + } + return NO; +} + +- (int64_t)times:(int32_t)v { + return v * value; +} + +- (void)dealloc { + if (self.value == 0) { + numI++; + } +} +@end + +// Objective-C implementation of testpkg.NullTest. +@interface NullTest : NSObject { +} + +- (TestpkgNullTest *)null; +@end + +@implementation NullTest { +} + +- (TestpkgNullTest *)null { + return nil; +} +@end + +// Objective-C implementation of testpkg.InterfaceDupper. +@interface IDup : NSObject { +} + +@end + +@implementation IDup { +} + +- (id)iDup:(id)i { + return i; +} +@end + +// Objective-C implementation of testpkg.ConcreteDupper. +@interface CDup : NSObject { +} + +@end + +@implementation CDup { +} + +- (TestpkgConcrete *)cDup:(TestpkgConcrete *)c { + return c; +} +@end + +// Objective-C implementation of testpkg.EmptyThrower. +@interface EmptyErrorer: NSObject { +} + +@end + +@implementation EmptyErrorer { +} + +- (BOOL)emptyError:(NSError **)error { + *error = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:NULL]; + return NO; +} +@end + +@interface tests : XCTestCase + +@end + +@implementation tests + +- (void)setUp { + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testBasics { + TestpkgHi(); + + TestpkgInt(42); +} + +- (void)testAdd { + int64_t sum = TestpkgAdd(31, 21); + XCTAssertEqual(sum, 52, @"TestpkgSum(31, 21) = %lld, want 52\n", sum); +} + +- (void)testHello:(NSString *)input { + NSString *got = TestpkgAppendHello(input); + NSString *want = [NSString stringWithFormat:@"Hello, %@!", input]; + XCTAssertEqualObjects(got, want, @"want %@\nTestpkgHello(%@)= %@", want, input, got); +} + +- (void)testHellos { + [self testHello:@"세계"]; // korean, utf-8, world. + unichar t[] = { + 0xD83D, 0xDCA9, + }; // utf-16, pile of poo. + [self testHello:[NSString stringWithCharacters:t length:2]]; +} + +- (void)testString { + NSString *input = @""; + NSString *got = TestpkgStrDup(input); + XCTAssertEqualObjects(got, input, @"want %@\nTestpkgEcho(%@)= %@", input, input, got); + + input = @"FOO"; + got = TestpkgStrDup(input); + XCTAssertEqualObjects(got, input, @"want %@\nTestpkgEcho(%@)= %@", input, input, got); +} + +- (void)testStruct { + TestpkgS2 *s = TestpkgNewS2(10.0, 100.0); + XCTAssertNotNil(s, @"TestpkgNewS2 returned NULL"); + + double x = [s x]; + double y = [s y]; + double sum = [s sum]; + XCTAssertTrue(x == 10.0 && y == 100.0 && sum == 110.0, + @"TestpkgS2(10.0, 100.0).X=%f Y=%f SUM=%f; want 10, 100, 110", x, y, sum); + + double sum2 = TestpkgCallSSum(s); + XCTAssertEqual(sum, sum2, @"TestpkgCallSSum(s)=%f; want %f as returned by s.Sum", sum2, sum); + + [s setX:7]; + [s setY:70]; + x = [s x]; + y = [s y]; + sum = [s sum]; + XCTAssertTrue(x == 7 && y == 70 && sum == 77, + @"TestpkgS2(7, 70).X=%f Y=%f SUM=%f; want 7, 70, 77", x, y, sum); + + NSString *first = @"trytwotested"; + NSString *second = @"test"; + NSString *got = [s tryTwoStrings:first second:second]; + NSString *want = [first stringByAppendingString:second]; + XCTAssertEqualObjects(got, want, @"TestpkgS_TryTwoStrings(%@, %@)= %@; want %@", first, second, got, want); +} + +- (void)testCollectS { + @autoreleasepool { + [self testStruct]; + } + + TestpkgGC(); + long numS = TestpkgCollectS2( + 1, 10); // within 10 seconds, collect the S used in testStruct. + XCTAssertEqual(numS, 1, @"%ld S objects were collected; S used in testStruct is supposed to " + @"be collected.", + numS); +} +- (void)testBytesAppend { + NSString *a = @"Foo"; + NSString *b = @"Bar"; + NSData *data_a = [a dataUsingEncoding:NSUTF8StringEncoding]; + NSData *data_b = [b dataUsingEncoding:NSUTF8StringEncoding]; + NSData *gotData = TestpkgBytesAppend(data_a, data_b); + NSString *got = [[NSString alloc] initWithData:gotData encoding:NSUTF8StringEncoding]; + NSString *want = [a stringByAppendingString:b]; + XCTAssertEqualObjects(got, want, @"want %@\nTestpkgBytesAppend(%@, %@) = %@", want, a, b, got); +} + +- (void)testInterface { + // Test Go object implementing testpkg.I is handled correctly. + id goObj = TestpkgNewI(); + int64_t got = [goObj times:10]; + XCTAssertEqual(got, 100, @"TestpkgNewI().times(10) = %lld; want %d", got, 100); + int32_t key = -1; + TestpkgRegisterI(key, goObj); + int64_t got2 = TestpkgMultiply(key, 10); + XCTAssertEqual(got, got2, @"TestpkgMultiply(10 * 10) = %lld; want %lld", got2, got); + TestpkgUnregisterI(key); + + // Test Objective-C objects implementing testpkg.I is handled correctly. + @autoreleasepool { + for (int32_t i = 0; i < 10; i++) { + Number *num = [[Number alloc] init]; + num.value = i; + TestpkgRegisterI(i, num); + } + TestpkgGC(); + } + + // Registered Objective-C objects are pinned on Go side which must + // prevent deallocation from Objective-C. + for (int32_t i = 0; i < 10; i++) { + int64_t got = TestpkgMultiply(i, 2); + XCTAssertEqual(got, i * 2,@"TestpkgMultiply(%d, 2) = %lld; want %d", i, got, i * 2); + TestpkgUnregisterI(i); + TestpkgGC(); + } + // Unregistered all Objective-C objects. +} + +- (void)testCollectI { + @autoreleasepool { + [self testInterface]; + } + XCTAssertEqual(numI, 1, @"%d I objects were collected; I used in testInterface is supposed " + @"to be collected.", numI); +} + +- (void)testConst { + XCTAssertEqualObjects(TestpkgAString, @"a string", @"TestpkgAString = %@, want 'a string'", TestpkgAString); + XCTAssertEqual(TestpkgAnInt, 7, @"TestpkgAnInt = %lld, want 7", TestpkgAnInt); + XCTAssertTrue(ABS(TestpkgAFloat - 0.12345) < 0.0001, @"TestpkgAFloat = %f, want 0.12345", TestpkgAFloat); + XCTAssertTrue(TestpkgABool == YES, @"TestpkgABool = %@, want YES", TestpkgAFloat ? @"YES" : @"NO"); + XCTAssertEqual(TestpkgMinInt32, INT32_MIN, @"TestpkgMinInt32 = %d, want %d", TestpkgMinInt32, INT32_MIN); + XCTAssertEqual(TestpkgMaxInt32, INT32_MAX, @"TestpkgMaxInt32 = %d, want %d", TestpkgMaxInt32, INT32_MAX); + XCTAssertEqual(TestpkgMinInt64, INT64_MIN, @"TestpkgMinInt64 = %lld, want %lld", TestpkgMinInt64, INT64_MIN); + XCTAssertEqual(TestpkgMaxInt64, INT64_MAX, @"TestpkgMaxInt64 = %lld, want %lld", TestpkgMaxInt64, INT64_MAX); + XCTAssertTrue(ABS(TestpkgSmallestNonzeroFloat64 - + 4.940656458412465441765687928682213723651e-324) < 1e-323, @"TestpkgSmallestNonzeroFloat64 = %f, want %f", + TestpkgSmallestNonzeroFloat64, + 4.940656458412465441765687928682213723651e-324); + XCTAssertTrue(ABS(TestpkgMaxFloat64 - + 1.797693134862315708145274237317043567981e+308) < 0.0001, @"TestpkgMaxFloat64 = %f, want %f", TestpkgMaxFloat64, + 1.797693134862315708145274237317043567981e+308); + XCTAssertTrue(ABS(TestpkgSmallestNonzeroFloat32 - + 1.401298464324817070923729583289916131280e-45) < 1e-44, @"TestpkgSmallestNonzeroFloat32 = %f, want %f", + TestpkgSmallestNonzeroFloat32, + 1.401298464324817070923729583289916131280e-45); + XCTAssertTrue(ABS(TestpkgMaxFloat32 - 3.40282346638528859811704183484516925440e+38) < 0.0001, + @"TestpkgMaxFloat32 = %f, want %f", TestpkgMaxFloat32, 3.40282346638528859811704183484516925440e+38); + XCTAssertTrue(ABS(TestpkgLog2E - 1 / 0.693147180559945309417232121458176568075500134360255254120680009) < 0.0001, + @"TestpkgLog2E = %f, want %f", TestpkgLog2E, 1 / 0.693147180559945309417232121458176568075500134360255254120680009); +} + +- (void)testIssue12307 { + Number *num = [[Number alloc] init]; + num.value = 1024; + NSError *error; + XCTAssertFalse(TestpkgCallIError(num, YES, &error), @"TestpkgCallIError(Number, YES) succeeded; want error"); + NSError *error2; + XCTAssertTrue(TestpkgCallIError(num, NO, &error2), @"TestpkgCallIError(Number, NO) failed(%@); want success", error2); +} + +- (void)testErrorField { + NSString *wantMsg = @"an error message"; + NSError *want = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:@{NSLocalizedDescriptionKey: wantMsg}]; + TestpkgNode *n = TestpkgNewNode(@"ErrTest"); + n.err = want; + NSError *got = n.err; + XCTAssertEqual(got, want, @"got different objects after roundtrip"); + NSString *gotMsg = TestpkgErrorMessage(want); + XCTAssertEqualObjects(gotMsg, wantMsg, @"err = %@, want %@", gotMsg, wantMsg); +} + +- (void)testErrorDup { + NSError *err = Testpkg.globalErr; + XCTAssertTrue(TestpkgIsGlobalErr(err), @"A Go error must preserve its identity across the boundary"); + XCTAssertEqualObjects([err localizedDescription], @"global err", "A Go error message must be preserved"); +} + +- (void)testVar { + NSString *s = Testpkg.stringVar; + XCTAssertEqualObjects(s, @"a string var", @"Testpkg.StringVar = %@, want 'a string var'", s); + s = @"a new string var"; + Testpkg.stringVar = s; + NSString *s2 = Testpkg.stringVar; + XCTAssertEqualObjects(s2, s, @"Testpkg.stringVar = %@, want %@", s2, s); + + int64_t i = Testpkg.intVar; + XCTAssertEqual(i, 77, @"Testpkg.intVar = %lld, want 77", i); + Testpkg.intVar = 777; + i = Testpkg.intVar; + XCTAssertEqual(i, 777, @"Testpkg.intVar = %lld, want 777", i); + [Testpkg setIntVar:7777]; + i = [Testpkg intVar]; + XCTAssertEqual(i, 7777, @"Testpkg.intVar = %lld, want 7777", i); + + TestpkgNode *n0 = Testpkg.nodeVar; + XCTAssertEqualObjects(n0.v, @"a struct var", @"Testpkg.NodeVar = %@, want 'a struct var'", n0.v); + TestpkgNode *n1 = TestpkgNewNode(@"a new struct var"); + Testpkg.nodeVar = n1; + TestpkgNode *n2 = Testpkg.nodeVar; + XCTAssertEqualObjects(n2.v, @"a new struct var", @"Testpkg.NodeVar = %@, want 'a new struct var'", n2.v); + + Number *num = [[Number alloc] init]; + num.value = 12345; + Testpkg.interfaceVar2 = num; + id iface = Testpkg.interfaceVar2; + int64_t x = [iface times:10]; + int64_t y = [num times:10]; + XCTAssertEqual(x, y, @"Testpkg.InterfaceVar2 Times 10 = %lld, want %lld", x, y); +} + +- (void)testIssue12403 { + Number *num = [[Number alloc] init]; + num.value = 1024; + + NSError *error; + NSString *ret = TestpkgCallIStringError(num, @"alphabet", &error); + XCTAssertNil(ret, @"TestpkgCallIStringError(Number, 'alphabet') succeeded(%@); want error", ret); + NSString *desc = [error localizedDescription]; + XCTAssertEqualObjects(desc, @"NumberError", @"TestpkgCallIStringError(Number, 'alphabet') returned unexpected error message %@", desc); + NSError *error2; + NSString *ret2 = TestpkgCallIStringError(num, @"number", &error2); + XCTAssertNotNil(ret2, @"TestpkgCallIStringError(Number, 'number') failed(%@); want success", error2); + XCTAssertEqualObjects(ret2, @"OK", @"TestpkgCallIStringError(Number, 'number') returned unexpected results %@", ret2); +} + +- (void)testStrDup:(NSString *)want { + NSString *got = TestpkgStrDup(want); + XCTAssertEqualObjects(want, got, @"StrDup returned %@; expected %@", got, want); +} + +- (void)testUnicodeStrings { + [self testStrDup:@"abcxyz09{}"]; + [self testStrDup:@"Hello, 世界"]; + [self testStrDup:@"\uffff\U00010000\U00010001\U00012345\U0010ffff"]; +} + +- (void)testByteArrayRead { + NSData *arr = [NSMutableData dataWithLength:8]; + long n; + XCTAssertTrue(TestpkgReadIntoByteArray(arr, &n, nil), @"ReadIntoByteArray failed"); + XCTAssertEqual(n, 8, @"ReadIntoByteArray wrote %ld bytes, expected %d", n, 8); + const uint8_t *b = [arr bytes]; + for (int i = 0; i < [arr length]; i++) { + XCTAssertEqual(b[i], i, @"ReadIntoByteArray wrote %d at %d; expected %d", b[i], i, i); + } + // Test that immutable data cannot be changed from Go + const uint8_t buf[] = {42}; + arr = [NSData dataWithBytes:buf length:1]; + XCTAssertTrue(TestpkgReadIntoByteArray(arr, &n, nil), @"ReadIntoByteArray failed"); + XCTAssertEqual(n, 1, @"ReadIntoByteArray wrote %ld bytes, expected %d", n, 8); + b = [arr bytes]; + XCTAssertEqual(b[0], 42, @"ReadIntoByteArray wrote to an immutable NSData; expected no change"); +} + +- (void)testNilField { + TestpkgNullFieldStruct *s = TestpkgNewNullFieldStruct(); + XCTAssertNil([s f], @"NullFieldStruct has non-nil field; expected nil"); +} + +- (void)testNullReferences { + NullTest *t = [[NullTest alloc] init]; + XCTAssertTrue(TestpkgCallWithNull(nil, t), @"Testpkg.CallWithNull failed"); + id i = TestpkgNewNullInterface(); + XCTAssertNil(i, @"NewNullInterface() returned %p; expected nil", i); + TestpkgS *s = TestpkgNewNullStruct(); + XCTAssertNil(s, @"NewNullStruct() returned %p; expected nil", s); + TestpkgIssue20330 *nullArger = TestpkgNewIssue20330(); + XCTAssertTrue([nullArger callWithNull:nil], @"Issue20330.CallWithNull failed"); +} + +- (void)testReturnsError { + NSError *error; + NSString *value = TestpkgReturnsError(TRUE, &error); + NSString *got = [error.userInfo valueForKey:NSLocalizedDescriptionKey]; + NSString *want = @"Error"; + XCTAssertEqualObjects(got, want, @"want %@\nTestpkgReturnsError(TRUE) = (%@, %@)", want, value, got); +} + +- (void)testImportedPkg { + XCTAssertEqualObjects(SecondpkgHelloString, SecondpkgHello(), @"imported string should match"); + id i = TestpkgNewImportedI(); + SecondpkgS *s = TestpkgNewImportedS(); + XCTAssertEqual(8, [i f:8], @"numbers should match"); + XCTAssertEqual(8, [s f:8], @"numbers should match"); + i = TestpkgWithImportedI(i); + s = TestpkgWithImportedS(s); + i = [Testpkg importedVarI]; + s = [Testpkg importedVarS]; + [Testpkg setImportedVarI:i]; + [Testpkg setImportedVarS:s]; + TestpkgImportedFields *fields = TestpkgNewImportedFields(); + i = [fields i]; + s = [fields s]; + [fields setI:i]; + [fields setS:s]; +} + +- (void)testRoundTripEquality { + Number *want = [[Number alloc] init]; + Number *got = (Number *)TestpkgI2Dup(want); + XCTAssertEqual(got, want, @"ObjC object passed through Go should not be wrapped"); + + IDup *idup = [[IDup alloc] init]; + XCTAssertTrue(TestpkgCallIDupper(idup), @"Go interface passed through ObjC should not be wrapped"); + CDup *cdup = [[CDup alloc] init]; + XCTAssertTrue(TestpkgCallCDupper(cdup), @"Go struct passed through ObjC should not be wrapped"); +} + +- (void)testEmptyError { + NSError *error; + XCTAssertFalse(TestpkgEmptyError(&error), @"GoTestpkgEmptyError succeeded; want error"); + XCTAssertNotNil(error, @"TestpkgEmptyError returned nil error"); + id empty = [[EmptyErrorer alloc] init]; + XCTAssertFalse(TestpkgCallEmptyError(empty, &error), @"TestpkgCallEmptyError succeeded; want error"); + XCTAssertNotNil(error, @"TestpkgCallEmptyError returned nil error"); +} + +- (void)testSIGPIPE { + TestpkgTestSIGPIPE(); +} + +- (void)testTags { + XCTAssertEqual(42, TestpkgTaggedConst, @"Tagged const must exist"); +} + +- (void)testConstructors { + id i = [[TestpkgConcrete alloc] init]; + [i f]; + + TestpkgS2 *s = [[TestpkgS2 alloc] init:1 y:2]; + XCTAssertEqual(3.0, [s sum]); + XCTAssertEqualObjects(@"gostring", [s tryTwoStrings:@"go" second:@"string"]); + + TestpkgS3 *s3 __attribute__((unused)) = [[TestpkgS3 alloc] init]; + + TestpkgS4 *s4 = [[TestpkgS4 alloc] initWithInt:123]; + XCTAssertEqual(123, s4.i); + + s4 = [[TestpkgS4 alloc] initWithFloat: 123.456]; + XCTAssertEqual(123, s4.i); + + s4 = [[TestpkgS4 alloc] initWithBoolAndError: false]; + XCTAssertEqual(0, s4.i); + + s4 = [[TestpkgS4 alloc] initWithBoolAndError: true]; + XCTAssertEqual(s4, NULL); +} + +@end diff --git a/bind/objc/SeqWrappers.m b/bind/objc/SeqWrappers.m new file mode 100644 index 000000000..71686d6ca --- /dev/null +++ b/bind/objc/SeqWrappers.m @@ -0,0 +1,98 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build ignore +// +build ignore + +@import ObjectiveC.message; +@import Foundation; +@import XCTest; +@import Objcpkg; + +@interface TestNSObject : NSObject + +- (NSString *)description; +- (NSString *)super_description; + +@end + +@implementation TestNSObject + +- (NSString *)description { + return @"hej"; +} + +- (NSString *)super_description { + return [super description]; +} + +@end + +@interface wrappers : XCTestCase + +@end + +@implementation wrappers + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testFunction { + ObjcpkgFunc(); +} + +- (void)testMethod { + ObjcpkgMethod(); +} + +- (void)testNew { + ObjcpkgNew(); +} + +- (void)testError { + ObjcpkgError(); +} + +- (void)testClass { + ObjcpkgGoNSDate *d = [[ObjcpkgGoNSDate alloc] init]; + NSString *desc = [d description]; + XCTAssertEqual(d, [d getSelf], "GoNSDate self not identical"); + XCTAssertEqual(ObjcpkgHash, [d hash], "GoNSDate hash not identical"); + XCTAssertTrue([desc isEqualToString:ObjcpkgDescriptionStr], "GoNSDate description mismatch: %@", desc); + ObjcpkgGoUIResponder *resp = [[ObjcpkgGoUIResponder alloc] init]; + [resp pressesBegan:nil withEvent:nil]; + XCTAssertTrue([resp called], "GoUIResponder.pressesBegan not called"); +} + +- (void)testSuper { + ObjcpkgGoNSObject *o = [[ObjcpkgGoNSObject alloc] init]; + struct objc_super _super = { + .receiver = o, + .super_class = [NSObject class], + }; + NSString *superDesc = ((NSString *(*)(struct objc_super*, SEL))objc_msgSendSuper)(&_super, @selector(description)); + XCTAssertTrue([superDesc isEqualToString:[o description]], "GoNSObject description mismatch"); + [o setUseSelf:TRUE]; + XCTAssertTrue([ObjcpkgDescriptionStr isEqualToString:[o description]], "GoNSObject description mismatch"); +} + +- (void)testIdentity { + NSDate *d = [[NSDate alloc] init]; + NSDate *d2 = ObjcpkgDupNSDate(d); + XCTAssertEqual(d, d2, @"ObjcpkgDupNSDate failed to duplicate ObjC instance"); + ObjcpkgGoNSDate *gd = [[ObjcpkgGoNSDate alloc] init]; + NSDate *gd2 = ObjcpkgDupNSDate(gd); + XCTAssertEqual(gd, gd2, @"ObjcpkgDupNSDate failed to duplicate Go instance"); + NSDate *gd3 = ObjcpkgNewGoNSDate(); + NSDate *gd4 = ObjcpkgDupNSDate(gd3); + XCTAssertEqual(gd4, gd3, @"ObjcpkgDupNSDate failed to duplicate instance created in Go"); +} +@end diff --git a/bind/objc/doc.go b/bind/objc/doc.go new file mode 100644 index 000000000..2370311dc --- /dev/null +++ b/bind/objc/doc.go @@ -0,0 +1,6 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package objc implements the Objective-C language bindings. +package objc diff --git a/bind/objc/ref.h b/bind/objc/ref.h new file mode 100644 index 000000000..b8036a4d8 --- /dev/null +++ b/bind/objc/ref.h @@ -0,0 +1,35 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef __GO_REF_HDR__ +#define __GO_REF_HDR__ + +#include + +// GoSeqRef is an object tagged with an integer for passing back and +// forth across the language boundary. A GoSeqRef may represent either +// an instance of a Go object, or an Objective-C object passed to Go. +// The explicit allocation of a GoSeqRef is used to pin a Go object +// when it is passed to Objective-C. The Go seq package maintains a +// reference to the Go object in a map keyed by the refnum along with +// a reference count. When the reference count reaches zero, the Go +// seq package will clear the corresponding entry in the map. +@interface GoSeqRef : NSObject { +} +@property(readonly) int32_t refnum; +@property(strong) id obj; // NULL when representing a Go object. + +// new GoSeqRef object to proxy a Go object. The refnum must be +// provided from Go side. +- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj; + +- (int32_t)incNum; + +@end + +@protocol goSeqRefInterface +-(GoSeqRef*) _ref; +@end + +#endif diff --git a/bind/objc/seq_darwin.go.support b/bind/objc/seq_darwin.go.support new file mode 100644 index 000000000..0b4e5de7b --- /dev/null +++ b/bind/objc/seq_darwin.go.support @@ -0,0 +1,91 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Go support functions for Objective-C. Note that this +// file is copied into and compiled with the generated +// bindings. + +/* +#cgo CFLAGS: -x objective-c -fobjc-arc -fmodules -fblocks -Werror +#cgo LDFLAGS: -framework Foundation + +#include +#include +#include "seq.h" +*/ +import "C" + +import ( + "unsafe" + + "golang.org/x/mobile/bind/seq" +) + +// DestroyRef is called by Objective-C to inform Go it is done with a reference. +//export DestroyRef +func DestroyRef(refnum C.int32_t) { + seq.Delete(int32(refnum)) +} + +// encodeString copies a Go string and returns it as a nstring. +func encodeString(s string) C.nstring { + n := C.int(len(s)) + if n == 0 { + return C.nstring{} + } + ptr := C.malloc(C.size_t(n)) + if ptr == nil { + panic("encodeString: malloc failed") + } + copy((*[1<<31 - 1]byte)(ptr)[:n], s) + return C.nstring{ptr: ptr, len: n} +} + +// decodeString converts a nstring to a Go string. The +// data in str is freed after use. +func decodeString(str C.nstring) string { + if str.ptr == nil { + return "" + } + s := C.GoStringN((*C.char)(str.ptr), str.len) + C.free(str.ptr) + return s +} + +// fromSlice converts a slice to a nbyteslice. +// If cpy is set, a malloc'ed copy of the data is returned. +func fromSlice(s []byte, cpy bool) C.nbyteslice { + if s == nil || len(s) == 0 { + return C.nbyteslice{} + } + ptr, n := unsafe.Pointer(&s[0]), C.int(len(s)) + if cpy { + nptr := C.malloc(C.size_t(n)) + if nptr == nil { + panic("fromSlice: malloc failed") + } + copy((*[1<<31 - 1]byte)(nptr)[:n], (*[1<<31 - 1]byte)(ptr)[:n]) + ptr = nptr + } + return C.nbyteslice{ptr: ptr, len: n} +} + +// toSlice takes a nbyteslice and returns a byte slice with the data. If cpy is +// set, the slice contains a copy of the data. If not, the generated Go code +// calls releaseByteSlice after use. +func toSlice(s C.nbyteslice, cpy bool) []byte { + if s.ptr == nil || s.len == 0 { + return nil + } + var b []byte + if cpy { + b = C.GoBytes(s.ptr, C.int(s.len)) + C.free(s.ptr) + } else { + b = (*[1<<31 - 1]byte)(unsafe.Pointer(s.ptr))[:s.len:s.len] + } + return b +} diff --git a/bind/objc/seq_darwin.h b/bind/objc/seq_darwin.h new file mode 100644 index 000000000..1aeec4ada --- /dev/null +++ b/bind/objc/seq_darwin.h @@ -0,0 +1,63 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef __GO_SEQ_DARWIN_HDR__ +#define __GO_SEQ_DARWIN_HDR__ + +#include +#include "ref.h" +#include "Universe.objc.h" + +#ifdef DEBUG +#define LOG_DEBUG(...) NSLog(__VA_ARGS__); +#else +#define LOG_DEBUG(...) ; +#endif + +#define LOG_INFO(...) NSLog(__VA_ARGS__); +#define LOG_FATAL(...) \ + { \ + NSLog(__VA_ARGS__); \ + @throw \ + [NSException exceptionWithName:NSInternalInconsistencyException \ + reason:[NSString stringWithFormat:__VA_ARGS__] \ + userInfo:NULL]; \ + } + +// Platform specific types +typedef struct nstring { + void *ptr; + int len; +} nstring; +typedef struct nbyteslice { + void *ptr; + int len; +} nbyteslice; +typedef int nint; + +extern void init_seq(); +// go_seq_dec_ref decrements the reference count for the +// specified refnum. It is called from Go from a finalizer. +extern void go_seq_dec_ref(int32_t refnum); +// go_seq_inc_ref increments the reference count for the +// specified refnum. It is called from Go just before converting +// a proxy to its refnum. +extern void go_seq_inc_ref(int32_t refnum); + +extern int32_t go_seq_to_refnum(id obj); +// go_seq_go_to_refnum is a special case of go_seq_to_refnum +extern int32_t go_seq_go_to_refnum(GoSeqRef *ref); + +extern GoSeqRef *go_seq_from_refnum(int32_t refnum); +// go_seq_objc_from_refnum is a special case of go_seq_from_refnum for +// Objective-C objects that implement a Go interface. +extern id go_seq_objc_from_refnum(int32_t refnum); + +extern nbyteslice go_seq_from_objc_bytearray(NSData *data, int copy); +extern nstring go_seq_from_objc_string(NSString *s); + +extern NSData *go_seq_to_objc_bytearray(nbyteslice, int copy); +extern NSString *go_seq_to_objc_string(nstring str); + +#endif // __GO_SEQ_DARWIN_HDR__ diff --git a/bind/objc/seq_darwin.m.support b/bind/objc/seq_darwin.m.support new file mode 100644 index 000000000..917a4efab --- /dev/null +++ b/bind/objc/seq_darwin.m.support @@ -0,0 +1,381 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include +#include +#include +#include +#include "seq.h" +#include "_cgo_export.h" + +// * Objective-C implementation of a Go interface type +// +// For an interface testpkg.I, gobind defines a protocol GoSeqTestpkgI. +// Reference tracker (tracker) maintains two maps: +// 1) _refs: objective-C object pointer -> a refnum (starting from 42). +// 2) _objs: refnum -> RefCounter. +// +// Whenever a user's object conforming the protocol is sent to Go (through +// a function or method that takes I), _refs is consulted to find the refnum +// of the object. If not found, the refnum is assigned and stored. +// +// _objs is also updated so that the RefCounter is incremented and the +// user's object is pinned. +// +// When a Go side needs to call a method of the interface, the Go side +// notifies the Objective-C side of the object's refnum. Upon receiving the +// request, Objective-C side looks up the object from _objs map, and sends +// the method to the object. +// +// The RefCount counts the references on objective-C objects from Go side, +// and pins the objective-C objects until there is no more references from +// Go side. +// +// * Objective-C proxy of a Go object (struct or interface type) +// +// For Go type object, a objective-C proxy instance is created whenever +// the object reference is passed into objective-C. +// +// While crossing the language barrier there is a brief window where the foreign +// proxy object might be finalized but the refnum is not yet translated to its object. +// If the proxy object was the last reference to the foreign object, the refnum +// will be invalid by the time it is looked up in the foreign reference tracker. +// +// To make sure the foreign object is kept live while its refnum is in transit, +// increment its refererence count before crossing. The other side will decrement +// it again immediately after the refnum is converted to its object. + +// Note that this file is copied into and compiled with the generated +// bindings. + +// A simple thread-safe mutable dictionary. +@interface goSeqDictionary : NSObject { +} +@property NSMutableDictionary *dict; +@end + +@implementation goSeqDictionary + +- (id)init { + if (self = [super init]) { + _dict = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (id)get:(id)key { + @synchronized(self) { + return [_dict objectForKey:key]; + } +} + +- (void)put:(id)obj withKey:(id)key { + @synchronized(self) { + [_dict setObject:obj forKey:key]; + } +} +@end + +// NULL_REFNUM is also known to bind/seq/ref.go and bind/java/Seq.java +#define NULL_REFNUM 41 + +// RefTracker encapsulates a map of objective-C objects passed to Go and +// the reference number counter which is incremented whenever an objective-C +// object that implements a Go interface is created. +@interface RefTracker : NSObject { + int32_t _next; + NSMutableDictionary *_refs; // map: object ptr -> refnum + NSMutableDictionary *_objs; // map: refnum -> RefCounter* +} + +- (id)init; + +// decrements the counter of the objective-C object with the reference number. +// This is called whenever a Go proxy to this object is finalized. +// When the counter reaches 0, the object is removed from the map. +- (void)dec:(int32_t)refnum; + +// increments the counter of the objective-C object with the reference number. +// This is called whenever a Go proxy is converted to its refnum and send +// across the language barrier. +- (void)inc:(int32_t)refnum; + +// returns the object of the reference number. +- (id)get:(int32_t)refnum; + +// returns the reference number of the object and increments the ref count. +// This is called whenever an Objective-C object is sent to Go side. +- (int32_t)assignRefnumAndIncRefcount:(id)obj; +@end + +static RefTracker *tracker = NULL; + +#define IS_FROM_GO(refnum) ((refnum) < 0) + +// init_seq is called when the Go side is initialized. +void init_seq() { tracker = [[RefTracker alloc] init]; } + +void go_seq_dec_ref(int32_t refnum) { + @autoreleasepool { + [tracker dec:refnum]; + } +} + +void go_seq_inc_ref(int32_t refnum) { + @autoreleasepool { + [tracker inc:refnum]; + } +} + +NSData *go_seq_to_objc_bytearray(nbyteslice s, int copy) { + if (s.ptr == NULL) { + return NULL; + } + BOOL freeWhenDone = copy ? YES : NO; + return [NSData dataWithBytesNoCopy:s.ptr length:s.len freeWhenDone:freeWhenDone]; +} + +NSString *go_seq_to_objc_string(nstring str) { + if (str.len == 0) { // empty string. + return @""; + } + NSString * res = [[NSString alloc] initWithBytesNoCopy:str.ptr + length:str.len + encoding:NSUTF8StringEncoding + freeWhenDone:YES]; + return res; +} + +id go_seq_objc_from_refnum(int32_t refnum) { + id obj = [tracker get:refnum]; + // Go called IncForeignRef just before converting its proxy to its refnum. Decrement it here. + // It's very important to decrement *after* fetching the reference from the tracker, in case + // there are no other proxy references to the object. + [tracker dec:refnum]; + return obj; +} + +GoSeqRef *go_seq_from_refnum(int32_t refnum) { + if (refnum == NULL_REFNUM) { + return nil; + } + if (IS_FROM_GO(refnum)) { + return [[GoSeqRef alloc] initWithRefnum:refnum obj:NULL]; + } + return [[GoSeqRef alloc] initWithRefnum:refnum obj:go_seq_objc_from_refnum(refnum)]; +} + +int32_t go_seq_to_refnum(id obj) { + if (obj == nil) { + return NULL_REFNUM; + } + return [tracker assignRefnumAndIncRefcount:obj]; +} + +int32_t go_seq_go_to_refnum(GoSeqRef *ref) { + int32_t refnum = [ref incNum]; + if (!IS_FROM_GO(refnum)) { + LOG_FATAL(@"go_seq_go_to_refnum on objective-c objects is not permitted"); + } + return refnum; +} + +nbyteslice go_seq_from_objc_bytearray(NSData *data, int copy) { + struct nbyteslice res = {NULL, 0}; + int sz = data.length; + if (sz == 0) { + return res; + } + void *ptr; + // If the argument was not a NSMutableData, copy the data so that + // the NSData is not changed from Go. The corresponding free is called + // by releaseByteSlice. + if (copy || ![data isKindOfClass:[NSMutableData class]]) { + void *arr_copy = malloc(sz); + if (arr_copy == NULL) { + LOG_FATAL(@"malloc failed"); + } + memcpy(arr_copy, [data bytes], sz); + ptr = arr_copy; + } else { + ptr = (void *)[data bytes]; + } + res.ptr = ptr; + res.len = sz; + return res; +} + +nstring go_seq_from_objc_string(NSString *s) { + nstring res = {NULL, 0}; + int len = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + + if (len == 0) { + if (s.length > 0) { + LOG_INFO(@"unable to encode an NSString into UTF-8"); + } + return res; + } + + char *buf = (char *)malloc(len); + if (buf == NULL) { + LOG_FATAL(@"malloc failed"); + } + NSUInteger used; + [s getBytes:buf + maxLength:len + usedLength:&used + encoding:NSUTF8StringEncoding + options:0 + range:NSMakeRange(0, [s length]) + remainingRange:NULL]; + res.ptr = buf; + res.len = used; + return res; +} + +@implementation GoSeqRef { +} + +- (id)init { + LOG_FATAL(@"GoSeqRef init is disallowed"); +} + +- (int32_t)incNum { + IncGoRef(_refnum); + return _refnum; +} + +// called when an object from Go is passed in. +- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj { + self = [super init]; + if (self) { + _refnum = refnum; + _obj = obj; + } + return self; +} + +- (void)dealloc { + if (IS_FROM_GO(_refnum)) { + DestroyRef(_refnum); + } +} +@end + +// RefCounter is a pair of (GoSeqProxy, count). GoSeqProxy has a strong +// reference to an Objective-C object. The count corresponds to +// the number of Go proxy objects. +// +// RefTracker maintains a map of refnum to RefCounter, for every +// Objective-C objects passed to Go. This map allows the transact +// call to relay the method call to the right Objective-C object, and +// prevents the Objective-C objects from being deallocated +// while they are still referenced from Go side. +@interface RefCounter : NSObject { +} +@property(strong, readonly) id obj; +@property int cnt; + +- (id)initWithObject:(id)obj; +@end + +@implementation RefCounter { +} +- (id)initWithObject:(id)obj { + self = [super init]; + if (self) { + _obj = obj; + _cnt = 0; + } + return self; +} + +@end + +@implementation RefTracker { +} + +- (id)init { + self = [super init]; + if (self) { + _next = 42; + _refs = [[NSMutableDictionary alloc] init]; + _objs = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)dec:(int32_t)refnum { // called whenever a go proxy object is finalized. + if (IS_FROM_GO(refnum)) { + LOG_FATAL(@"dec:invalid refnum for Objective-C objects"); + } + @synchronized(self) { + id key = @(refnum); + RefCounter *counter = [_objs objectForKey:key]; + if (counter == NULL) { + LOG_FATAL(@"unknown refnum"); + } + int n = counter.cnt; + if (n <= 0) { + LOG_FATAL(@"refcount underflow"); + } else if (n == 1) { + LOG_DEBUG(@"remove the reference %d", refnum); + NSValue *ptr = [NSValue valueWithPointer:(const void *)(counter.obj)]; + [_refs removeObjectForKey:ptr]; + [_objs removeObjectForKey:key]; + } else { + counter.cnt = n - 1; + } + } +} + +// inc is called whenever a ObjC refnum crosses from Go to ObjC +- (void)inc:(int32_t)refnum { + if (IS_FROM_GO(refnum)) { + LOG_FATAL(@"dec:invalid refnum for Objective-C objects"); + } + @synchronized(self) { + id key = @(refnum); + RefCounter *counter = [_objs objectForKey:key]; + if (counter == NULL) { + LOG_FATAL(@"unknown refnum"); + } + counter.cnt++; + } +} + +- (id)get:(int32_t)refnum { + if (IS_FROM_GO(refnum)) { + LOG_FATAL(@"get:invalid refnum for Objective-C objects"); + } + @synchronized(self) { + RefCounter *counter = _objs[@(refnum)]; + if (counter == NULL) { + LOG_FATAL(@"unidentified object refnum: %d", refnum); + } + return counter.obj; + } +} + +- (int32_t)assignRefnumAndIncRefcount:(id)obj { + @synchronized(self) { + NSValue *ptr = [NSValue valueWithPointer:(const void *)(obj)]; + NSNumber *refnum = [_refs objectForKey:ptr]; + if (refnum == NULL) { + refnum = @(_next++); + _refs[ptr] = refnum; + } + RefCounter *counter = [_objs objectForKey:refnum]; + if (counter == NULL) { + counter = [[RefCounter alloc] initWithObject:obj]; + counter.cnt = 1; + _objs[refnum] = counter; + } else { + counter.cnt++; + } + return (int32_t)([refnum intValue]); + } +} + +@end diff --git a/bind/objc/seq_test.go b/bind/objc/seq_test.go new file mode 100644 index 000000000..e6ef5e71d --- /dev/null +++ b/bind/objc/seq_test.go @@ -0,0 +1,1010 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objc + +import ( + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" +) + +// Use the Xcode XCTestCase framework to run the regular tests and the special SeqBench.m benchmarks. +// +// Regular tests run in the xcodetest project as normal unit test (logic test in Xcode lingo). +// Unit tests execute faster but cannot run on a real device. The benchmarks in SeqBench.m run as +// UI unit tests. +// +// The Xcode files embedded in this file were constructed in Xcode 9 by: +// +// - Creating a new project through Xcode. Both unit tests and UI tests were checked off. +// - Xcode schemes are per-user by default. The shared scheme is created by selecting +// Project => Schemes => Manage Schemes from the Xcode menu and selecting "Shared". +// - Remove files not needed for xcodebuild (determined empirically). In particular, the empty +// tests Xcode creates can be removed and the unused user scheme. +// +// All tests here require the Xcode command line tools. + +var destination = flag.String("device", "platform=iOS Simulator,name=iPhone 6s Plus", "Specify the -destination flag to xcodebuild") + +var gomobileBin string + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +func testMain(m *testing.M) int { + binDir, err := ioutil.TempDir("", "bind-objc-test-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(binDir) + + exe := "" + if runtime.GOOS == "windows" { + exe = ".exe" + } + if runtime.GOOS != "android" { + gocmd := filepath.Join(runtime.GOROOT(), "bin", "go") + gomobileBin = filepath.Join(binDir, "gomobile"+exe) + gobindBin := filepath.Join(binDir, "gobind"+exe) + if out, err := exec.Command(gocmd, "build", "-o", gomobileBin, "golang.org/x/mobile/cmd/gomobile").CombinedOutput(); err != nil { + log.Fatalf("gomobile build failed: %v: %s", err, out) + } + if out, err := exec.Command(gocmd, "build", "-o", gobindBin, "golang.org/x/mobile/cmd/gobind").CombinedOutput(); err != nil { + log.Fatalf("gobind build failed: %v: %s", err, out) + } + path := binDir + if oldPath := os.Getenv("PATH"); oldPath != "" { + path += string(filepath.ListSeparator) + oldPath + } + os.Setenv("PATH", path) + } + + return m.Run() +} + +// TestObjcSeqTest runs ObjC test SeqTest.m. +func TestObjcSeqTest(t *testing.T) { + runTest(t, []string{ + "golang.org/x/mobile/bind/testdata/testpkg", + "golang.org/x/mobile/bind/testdata/testpkg/secondpkg", + "golang.org/x/mobile/bind/testdata/testpkg/simplepkg", + }, "", "SeqTest.m", "Testpkg.framework", false, false) +} + +// TestObjcSeqBench runs ObjC test SeqBench.m. +func TestObjcSeqBench(t *testing.T) { + if testing.Short() { + t.Skip("skipping benchmark in short mode.") + } + runTest(t, []string{"golang.org/x/mobile/bind/testdata/benchmark"}, "", "SeqBench.m", "Benchmark.framework", true, true) +} + +// TestObjcSeqWrappers runs ObjC test SeqWrappers.m. +func TestObjcSeqWrappers(t *testing.T) { + runTest(t, []string{"golang.org/x/mobile/bind/testdata/testpkg/objcpkg"}, "", "SeqWrappers.m", "Objcpkg.framework", false, false) +} + +// TestObjcCustomPkg runs the ObjC test SeqCustom.m. +func TestObjcCustomPkg(t *testing.T) { + runTest(t, []string{"golang.org/x/mobile/bind/testdata/testpkg"}, "Custom", "SeqCustom.m", "Testpkg.framework", false, false) +} + +func runTest(t *testing.T, pkgNames []string, prefix, testfile, framework string, uitest, dumpOutput bool) { + if gomobileBin == "" { + t.Skipf("no gomobile on %s", runtime.GOOS) + } + if _, err := run("which xcodebuild"); err != nil { + t.Skip("command xcodebuild not found, skipping") + } + + tmpdir, err := ioutil.TempDir("", "bind-objc-seq-test-") + if err != nil { + t.Fatalf("failed to prepare temp dir: %v", err) + } + defer os.RemoveAll(tmpdir) + t.Logf("tmpdir = %s", tmpdir) + + if err := createProject(tmpdir, testfile, framework); err != nil { + t.Fatalf("failed to create project: %v", err) + } + + if err := cp(filepath.Join(tmpdir, testfile), testfile); err != nil { + t.Fatalf("failed to copy %s: %v", testfile, err) + } + + cmd := exec.Command(gomobileBin, "bind", "-target", "ios", "-tags", "aaa bbb") + if prefix != "" { + cmd.Args = append(cmd.Args, "-prefix", prefix) + } + cmd.Args = append(cmd.Args, pkgNames...) + cmd.Dir = filepath.Join(tmpdir, "xcodetest") + // Reverse binding doesn't work with Go module since imports starting with Java or ObjC are not valid FQDNs. + // Disable Go module explicitly until this problem is solved. See golang/go#27234. + cmd.Env = append(os.Environ(), "GO111MODULE=off") + buf, err := cmd.CombinedOutput() + if err != nil { + t.Logf("%s", buf) + t.Fatalf("failed to run gomobile bind: %v", err) + } + + testPattern := "xcodetestTests" + if uitest { + testPattern = "xcodetestUITests" + } + cmd = exec.Command("xcodebuild", "test", "-scheme", "xcodetest", "-destination", *destination, "-only-testing:"+testPattern) + cmd.Dir = tmpdir + buf, err = cmd.CombinedOutput() + if err != nil { + t.Logf("%s", buf) + t.Errorf("failed to run xcodebuild: %v", err) + } + if dumpOutput { + t.Logf("%s", buf) + } +} + +func run(cmd string) ([]byte, error) { + c := strings.Split(cmd, " ") + return exec.Command(c[0], c[1:]...).CombinedOutput() +} + +func cp(dst, src string) error { + r, err := os.Open(src) + if err != nil { + return fmt.Errorf("failed to read source: %v", err) + } + defer r.Close() + w, err := os.Create(dst) + if err != nil { + return fmt.Errorf("failed to open destination: %v", err) + } + _, err = io.Copy(w, r) + cerr := w.Close() + if err != nil { + return err + } + return cerr +} + +// createProject generates the files required for xcodebuild test to run a +// Objective-C testfile with a gomobile bind framework. +func createProject(dir, testfile, framework string) error { + for _, d := range []string{"xcodetest", "xcodetest.xcodeproj/xcshareddata/xcschemes", "xcodetestTests", "xcodetestUITests"} { + if err := os.MkdirAll(filepath.Join(dir, d), 0700); err != nil { + return err + } + } + files := []struct { + path string + content string + }{ + {"xcodetest/Info.plist", infoPlist}, + {"xcodetest.xcodeproj/project.pbxproj", fmt.Sprintf(pbxproj, testfile, framework)}, + {"xcodetest.xcodeproj/xcshareddata/xcschemes/xcodetest.xcscheme", xcodescheme}, + {"xcodetestTests/Info.plist", testInfoPlist}, + // For UI tests. Only UI tests run on a real idevice. + {"xcodetestUITests/Info.plist", testInfoPlist}, + {"xcodetest/AppDelegate.h", appdelegateh}, + {"xcodetest/main.m", mainm}, + {"xcodetest/AppDelegate.m", appdelegatem}, + } + for _, f := range files { + if err := ioutil.WriteFile(filepath.Join(dir, f.path), []byte(f.content), 0700); err != nil { + return err + } + } + return nil +} + +const infoPlist = ` + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + +` + +const testInfoPlist = ` + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + +` + +const pbxproj = `// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 642D058D2094883B00FE587C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 642D058C2094883B00FE587C /* AppDelegate.m */; }; + 642D05952094883C00FE587C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 642D05942094883C00FE587C /* Assets.xcassets */; }; + 642D059B2094883C00FE587C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 642D059A2094883C00FE587C /* main.m */; }; + 642D05A52094883C00FE587C /* xcodetestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 642D05A42094883C00FE587C /* xcodetestTests.m */; }; + 642D05B02094883C00FE587C /* xcodetestUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 642D05AF2094883C00FE587C /* xcodetestUITests.m */; }; + 642D05BE209488E400FE587C /* Testpkg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 642D05BD209488E400FE587C /* Testpkg.framework */; }; + 642D05BF209488E400FE587C /* Testpkg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 642D05BD209488E400FE587C /* Testpkg.framework */; }; + 642D05C0209488E400FE587C /* Testpkg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 642D05BD209488E400FE587C /* Testpkg.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 642D05A12094883C00FE587C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 642D05802094883B00FE587C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 642D05872094883B00FE587C; + remoteInfo = xcodetest; + }; + 642D05AC2094883C00FE587C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 642D05802094883B00FE587C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 642D05872094883B00FE587C; + remoteInfo = xcodetest; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 642D05882094883B00FE587C /* xcodetest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = xcodetest.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 642D058B2094883B00FE587C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 642D058C2094883B00FE587C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 642D05942094883C00FE587C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 642D05992094883C00FE587C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 642D059A2094883C00FE587C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 642D05A02094883C00FE587C /* xcodetestTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = xcodetestTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 642D05A42094883C00FE587C /* xcodetestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ../%[1]s; sourceTree = ""; }; + 642D05A62094883C00FE587C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 642D05AB2094883C00FE587C /* xcodetestUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = xcodetestUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 642D05AF2094883C00FE587C /* xcodetestUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ../%[1]s; sourceTree = ""; }; + 642D05B12094883C00FE587C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 642D05BD209488E400FE587C /* Testpkg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Testpkg.framework; path = %[2]s; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 642D05852094883B00FE587C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 642D05BE209488E400FE587C /* Testpkg.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 642D059D2094883C00FE587C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 642D05BF209488E400FE587C /* Testpkg.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 642D05A82094883C00FE587C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 642D05C0209488E400FE587C /* Testpkg.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 642D057F2094883B00FE587C = { + isa = PBXGroup; + children = ( + 642D058A2094883B00FE587C /* xcodetest */, + 642D05A32094883C00FE587C /* xcodetestTests */, + 642D05AE2094883C00FE587C /* xcodetestUITests */, + 642D05892094883B00FE587C /* Products */, + 642D05BD209488E400FE587C /* Testpkg.framework */, + ); + sourceTree = ""; + }; + 642D05892094883B00FE587C /* Products */ = { + isa = PBXGroup; + children = ( + 642D05882094883B00FE587C /* xcodetest.app */, + 642D05A02094883C00FE587C /* xcodetestTests.xctest */, + 642D05AB2094883C00FE587C /* xcodetestUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 642D058A2094883B00FE587C /* xcodetest */ = { + isa = PBXGroup; + children = ( + 642D058B2094883B00FE587C /* AppDelegate.h */, + 642D058C2094883B00FE587C /* AppDelegate.m */, + 642D05942094883C00FE587C /* Assets.xcassets */, + 642D05992094883C00FE587C /* Info.plist */, + 642D059A2094883C00FE587C /* main.m */, + ); + path = xcodetest; + sourceTree = ""; + }; + 642D05A32094883C00FE587C /* xcodetestTests */ = { + isa = PBXGroup; + children = ( + 642D05A42094883C00FE587C /* xcodetestTests.m */, + 642D05A62094883C00FE587C /* Info.plist */, + ); + path = xcodetestTests; + sourceTree = ""; + }; + 642D05AE2094883C00FE587C /* xcodetestUITests */ = { + isa = PBXGroup; + children = ( + 642D05AF2094883C00FE587C /* xcodetestUITests.m */, + 642D05B12094883C00FE587C /* Info.plist */, + ); + path = xcodetestUITests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 642D05872094883B00FE587C /* xcodetest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 642D05B42094883C00FE587C /* Build configuration list for PBXNativeTarget "xcodetest" */; + buildPhases = ( + 642D05842094883B00FE587C /* Sources */, + 642D05852094883B00FE587C /* Frameworks */, + 642D05862094883B00FE587C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = xcodetest; + productName = xcodetest; + productReference = 642D05882094883B00FE587C /* xcodetest.app */; + productType = "com.apple.product-type.application"; + }; + 642D059F2094883C00FE587C /* xcodetestTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 642D05B72094883C00FE587C /* Build configuration list for PBXNativeTarget "xcodetestTests" */; + buildPhases = ( + 642D059C2094883C00FE587C /* Sources */, + 642D059D2094883C00FE587C /* Frameworks */, + 642D059E2094883C00FE587C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 642D05A22094883C00FE587C /* PBXTargetDependency */, + ); + name = xcodetestTests; + productName = xcodetestTests; + productReference = 642D05A02094883C00FE587C /* xcodetestTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 642D05AA2094883C00FE587C /* xcodetestUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 642D05BA2094883C00FE587C /* Build configuration list for PBXNativeTarget "xcodetestUITests" */; + buildPhases = ( + 642D05A72094883C00FE587C /* Sources */, + 642D05A82094883C00FE587C /* Frameworks */, + 642D05A92094883C00FE587C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 642D05AD2094883C00FE587C /* PBXTargetDependency */, + ); + name = xcodetestUITests; + productName = xcodetestUITests; + productReference = 642D05AB2094883C00FE587C /* xcodetestUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 642D05802094883B00FE587C /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = golang; + TargetAttributes = { + 642D05872094883B00FE587C = { + CreatedOnToolsVersion = 9.3; + }; + 642D059F2094883C00FE587C = { + CreatedOnToolsVersion = 9.3; + TestTargetID = 642D05872094883B00FE587C; + }; + 642D05AA2094883C00FE587C = { + CreatedOnToolsVersion = 9.3; + TestTargetID = 642D05872094883B00FE587C; + }; + }; + }; + buildConfigurationList = 642D05832094883B00FE587C /* Build configuration list for PBXProject "xcodetest" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 642D057F2094883B00FE587C; + productRefGroup = 642D05892094883B00FE587C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 642D05872094883B00FE587C /* xcodetest */, + 642D059F2094883C00FE587C /* xcodetestTests */, + 642D05AA2094883C00FE587C /* xcodetestUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 642D05862094883B00FE587C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 642D05952094883C00FE587C /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 642D059E2094883C00FE587C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 642D05A92094883C00FE587C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 642D05842094883B00FE587C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 642D059B2094883C00FE587C /* main.m in Sources */, + 642D058D2094883B00FE587C /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 642D059C2094883C00FE587C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 642D05A52094883C00FE587C /* xcodetestTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 642D05A72094883C00FE587C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 642D05B02094883C00FE587C /* xcodetestUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 642D05A22094883C00FE587C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 642D05872094883B00FE587C /* xcodetest */; + targetProxy = 642D05A12094883C00FE587C /* PBXContainerItemProxy */; + }; + 642D05AD2094883C00FE587C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 642D05872094883B00FE587C /* xcodetest */; + targetProxy = 642D05AC2094883C00FE587C /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 642D05B22094883C00FE587C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 642D05B32094883C00FE587C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 642D05B52094883C00FE587C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/xcodetest", + ); + INFOPLIST_FILE = xcodetest/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.golang.xcodetest; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 642D05B62094883C00FE587C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/xcodetest", + ); + INFOPLIST_FILE = xcodetest/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.golang.xcodetest; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 642D05B82094883C00FE587C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/xcodetest", + ); + INFOPLIST_FILE = xcodetestTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.golang.xcodetestTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/xcodetest.app/xcodetest"; + }; + name = Debug; + }; + 642D05B92094883C00FE587C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/xcodetest", + ); + INFOPLIST_FILE = xcodetestTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.golang.xcodetestTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/xcodetest.app/xcodetest"; + }; + name = Release; + }; + 642D05BB2094883C00FE587C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/xcodetest", + ); + INFOPLIST_FILE = xcodetestUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.golang.xcodetestUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = xcodetest; + }; + name = Debug; + }; + 642D05BC2094883C00FE587C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/xcodetest", + ); + INFOPLIST_FILE = xcodetestUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.golang.xcodetestUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = xcodetest; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 642D05832094883B00FE587C /* Build configuration list for PBXProject "xcodetest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 642D05B22094883C00FE587C /* Debug */, + 642D05B32094883C00FE587C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 642D05B42094883C00FE587C /* Build configuration list for PBXNativeTarget "xcodetest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 642D05B52094883C00FE587C /* Debug */, + 642D05B62094883C00FE587C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 642D05B72094883C00FE587C /* Build configuration list for PBXNativeTarget "xcodetestTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 642D05B82094883C00FE587C /* Debug */, + 642D05B92094883C00FE587C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 642D05BA2094883C00FE587C /* Build configuration list for PBXNativeTarget "xcodetestUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 642D05BB2094883C00FE587C /* Debug */, + 642D05BC2094883C00FE587C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 642D05802094883B00FE587C /* Project object */; +}` + +const xcodescheme = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +` + +const appdelegateh = `#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end` + +const appdelegatem = `#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { +} + +- (void)applicationWillTerminate:(UIApplication *)application { +} + +@end` + +const mainm = `#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +}` diff --git a/bind/printer.go b/bind/printer.go new file mode 100644 index 000000000..3d24ea024 --- /dev/null +++ b/bind/printer.go @@ -0,0 +1,67 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bind + +import ( + "bytes" + "fmt" +) + +type Printer struct { + Buf *bytes.Buffer + IndentEach []byte + indentText []byte + needIndent bool +} + +func (p *Printer) writeIndent() error { + if !p.needIndent { + return nil + } + p.needIndent = false + _, err := p.Buf.Write(p.indentText) + return err +} + +func (p *Printer) Write(b []byte) (n int, err error) { + wrote := 0 + for len(b) > 0 { + if err := p.writeIndent(); err != nil { + return wrote, err + } + i := bytes.IndexByte(b, '\n') + if i < 0 { + break + } + n, err = p.Buf.Write(b[0 : i+1]) + wrote += n + if err != nil { + return wrote, err + } + b = b[i+1:] + p.needIndent = true + } + if len(b) > 0 { + n, err = p.Buf.Write(b) + wrote += n + } + return wrote, err +} + +func (p *Printer) Printf(format string, args ...interface{}) { + if _, err := fmt.Fprintf(p, format, args...); err != nil { + panic(fmt.Sprintf("printer: %v", err)) + } +} + +func (p *Printer) Indent() { + p.indentText = append(p.indentText, p.IndentEach...) +} + +func (p *Printer) Outdent() { + if len(p.indentText) > len(p.IndentEach)-1 { + p.indentText = p.indentText[len(p.IndentEach):] + } +} diff --git a/bind/seq.go.support b/bind/seq.go.support new file mode 100644 index 000000000..392ec09c0 --- /dev/null +++ b/bind/seq.go.support @@ -0,0 +1,52 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Go support functions for generated Go bindings. This file is +// copied into the generated main package, and compiled along +// with the bindings. + +// #cgo android CFLAGS: -D__GOBIND_ANDROID__ +// #cgo darwin CFLAGS: -D__GOBIND_DARWIN__ +// #include +// #include "seq.h" +import "C" + +import ( + "fmt" + "os" + "os/signal" + "syscall" + + _ "golang.org/x/mobile/bind/java" + _seq "golang.org/x/mobile/bind/seq" +) + +func init() { + _seq.FinalizeRef = func(ref *_seq.Ref) { + refnum := ref.Bind_Num + if refnum < 0 { + panic(fmt.Sprintf("not a foreign ref: %d", refnum)) + } + C.go_seq_dec_ref(C.int32_t(refnum)) + } + _seq.IncForeignRef = func(refnum int32) { + if refnum < 0 { + panic(fmt.Sprintf("not a foreign ref: %d", refnum)) + } + C.go_seq_inc_ref(C.int32_t(refnum)) + } + // Workaround for issue #17393. + signal.Notify(make(chan os.Signal), syscall.SIGPIPE) +} + +// IncGoRef is called by foreign code to pin a Go object while its refnum is crossing +// the language barrier +//export IncGoRef +func IncGoRef(refnum C.int32_t) { + _seq.Inc(int32(refnum)) +} + +func main() {} diff --git a/bind/seq/ref.go b/bind/seq/ref.go new file mode 100644 index 000000000..803d6923a --- /dev/null +++ b/bind/seq/ref.go @@ -0,0 +1,153 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package seq + +//#cgo LDFLAGS: -llog +//#include +//#include +//import "C" + +import ( + "fmt" + "runtime" + "sync" +) + +type countedObj struct { + obj interface{} + cnt int32 +} + +// also known to bind/java/Seq.java and bind/objc/seq_darwin.m +const NullRefNum = 41 + +// refs stores Go objects that have been passed to another language. +var refs struct { + sync.Mutex + next int32 // next reference number to use for Go object, always negative + refs map[interface{}]int32 + objs map[int32]countedObj +} + +func init() { + refs.Lock() + refs.next = -24 // Go objects get negative reference numbers. Arbitrary starting point. + refs.refs = make(map[interface{}]int32) + refs.objs = make(map[int32]countedObj) + refs.Unlock() +} + +// A Ref represents a Java or Go object passed across the language +// boundary. +type Ref struct { + Bind_Num int32 +} + +type proxy interface { + // Use a strange name and hope that user code does not implement it + Bind_proxy_refnum__() int32 +} + +// ToRefNum increments the reference count for an object and +// returns its refnum. +func ToRefNum(obj interface{}) int32 { + // We don't track foreign objects, so if obj is a proxy + // return its refnum. + if r, ok := obj.(proxy); ok { + refnum := r.Bind_proxy_refnum__() + if refnum <= 0 { + panic(fmt.Errorf("seq: proxy contained invalid Go refnum: %d", refnum)) + } + return refnum + } + refs.Lock() + num := refs.refs[obj] + if num != 0 { + s := refs.objs[num] + refs.objs[num] = countedObj{s.obj, s.cnt + 1} + } else { + num = refs.next + refs.next-- + if refs.next > 0 { + panic("refs.next underflow") + } + refs.refs[obj] = num + refs.objs[num] = countedObj{obj, 1} + } + refs.Unlock() + + return num +} + +// FromRefNum returns the Ref for a refnum. If the refnum specifies a +// foreign object, a finalizer is set to track its lifetime. +func FromRefNum(num int32) *Ref { + if num == NullRefNum { + return nil + } + ref := &Ref{num} + if num > 0 { + // This is a foreign object reference. + // Track its lifetime with a finalizer. + runtime.SetFinalizer(ref, FinalizeRef) + } + + return ref +} + +// Bind_IncNum increments the foreign reference count and +// return the refnum. +func (r *Ref) Bind_IncNum() int32 { + refnum := r.Bind_Num + IncForeignRef(refnum) + // Make sure this reference is not finalized before + // the foreign reference count is incremented. + runtime.KeepAlive(r) + return refnum +} + +// Get returns the underlying object. +func (r *Ref) Get() interface{} { + refnum := r.Bind_Num + refs.Lock() + o, ok := refs.objs[refnum] + refs.Unlock() + if !ok { + panic(fmt.Sprintf("unknown ref %d", refnum)) + } + // This is a Go reference and its refnum was incremented + // before crossing the language barrier. + Delete(refnum) + return o.obj +} + +// Inc increments the reference count for a refnum. Called from Bind_proxy_refnum +// functions. +func Inc(num int32) { + refs.Lock() + o, ok := refs.objs[num] + if !ok { + panic(fmt.Sprintf("seq.Inc: unknown refnum: %d", num)) + } + refs.objs[num] = countedObj{o.obj, o.cnt + 1} + refs.Unlock() +} + +// Delete decrements the reference count and removes the pinned object +// from the object map when the reference count becomes zero. +func Delete(num int32) { + refs.Lock() + defer refs.Unlock() + o, ok := refs.objs[num] + if !ok { + panic(fmt.Sprintf("seq.Delete unknown refnum: %d", num)) + } + if o.cnt <= 1 { + delete(refs.objs, num) + delete(refs.refs, o.obj) + } else { + refs.objs[num] = countedObj{o.obj, o.cnt - 1} + } +} diff --git a/bind/seq/seq.go b/bind/seq/seq.go new file mode 100644 index 000000000..0740ca80f --- /dev/null +++ b/bind/seq/seq.go @@ -0,0 +1,21 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package seq implements the machine-dependent seq serialization format. +// +// Implementations of Transact and FinalizeRef are provided by a +// specific foreign language binding package, e.g. go.mobile/bind/java. +// +// Designed only for use by the code generated by gobind. Don't try to +// use this directly. +package seq // import "golang.org/x/mobile/bind/seq" + +import _ "golang.org/x/mobile/internal/mobileinit" + +// FinalizeRef is the finalizer used on foreign objects. +var FinalizeRef func(ref *Ref) + +// IncRef increments the foreign reference count for ref while it is in transit. +// The count is decremented after the ref is received and translated on the foreign side. +var IncForeignRef func(refnum int32) diff --git a/bind/seq/string.go b/bind/seq/string.go new file mode 100644 index 000000000..b578d553d --- /dev/null +++ b/bind/seq/string.go @@ -0,0 +1,49 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package seq + +import "unicode/utf16" + +// Based heavily on package unicode/utf16 from the Go standard library. + +const ( + replacementChar = '\uFFFD' // Unicode replacement character + maxRune = '\U0010FFFF' // Maximum valid Unicode code point. +) + +const ( + // 0xd800-0xdc00 encodes the high 10 bits of a pair. + // 0xdc00-0xe000 encodes the low 10 bits of a pair. + // the value is those 20 bits plus 0x10000. + surr1 = 0xd800 + surr2 = 0xdc00 + surr3 = 0xe000 + + surrSelf = 0x10000 +) + +// UTF16Encode utf16 encodes s into chars. It returns the resulting +// length in units of uint16. It is assumed that the chars slice +// has enough room for the encoded string. +func UTF16Encode(s string, chars []uint16) int { + n := 0 + for _, v := range s { + switch { + case v < 0, surr1 <= v && v < surr3, v > maxRune: + v = replacementChar + fallthrough + case v < surrSelf: + chars[n] = uint16(v) + n += 1 + default: + // surrogate pair, two uint16 values + r1, r2 := utf16.EncodeRune(v) + chars[n] = uint16(r1) + chars[n+1] = uint16(r2) + n += 2 + } + } + return n +} diff --git a/bind/seq/string_test.go b/bind/seq/string_test.go new file mode 100644 index 000000000..21a54f618 --- /dev/null +++ b/bind/seq/string_test.go @@ -0,0 +1,28 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package seq + +import ( + "testing" + "unicode/utf16" +) + +var strData = []string{ + "abcxyz09{}", + "Hello, 世界", + string([]rune{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff}), +} + +func TestString(t *testing.T) { + for _, test := range strData { + chars := make([]uint16, 4*len(test)) + nchars := UTF16Encode(test, chars) + chars = chars[:nchars] + got := string(utf16.Decode(chars)) + if got != test { + t.Errorf("UTF16: got %q, want %q", got, test) + } + } +} diff --git a/bind/testdata/basictypes.go b/bind/testdata/basictypes.go new file mode 100644 index 000000000..1fc02e63a --- /dev/null +++ b/bind/testdata/basictypes.go @@ -0,0 +1,25 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package basictypes + +const ( + AString = "a string" + AnInt = 7 + AnInt2 = 1<<63 - 1 + AFloat = 0.2015 + ARune = rune(32) + ABool = true + ALongString = "LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString" +) + +func Ints(x int8, y int16, z int32, t int64, u int) {} + +func Error() error { return nil } + +func ErrorPair() (int, error) { return 0, nil } + +func ByteArrays(x []byte) []byte { return nil } + +func Bool(bool) bool { return true } diff --git a/bind/testdata/basictypes.go.golden b/bind/testdata/basictypes.go.golden new file mode 100644 index 000000000..2874b339c --- /dev/null +++ b/bind/testdata/basictypes.go.golden @@ -0,0 +1,73 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package basictypes. +// +// autogenerated by gobind -lang=go basictypes +package main + +/* +#include +#include +#include "seq.h" +#include "basictypes.h" + +*/ +import "C" + +import ( + "basictypes" + _seq "golang.org/x/mobile/bind/seq" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxybasictypes__Bool +func proxybasictypes__Bool(param_p0 C.char) C.char { + _param_p0 := param_p0 != 0 + res_0 := basictypes.Bool(_param_p0) + var _res_0 C.char = 0 + if res_0 { + _res_0 = 1 + } + return _res_0 +} + +//export proxybasictypes__ByteArrays +func proxybasictypes__ByteArrays(param_x C.nbyteslice) C.nbyteslice { + _param_x := toSlice(param_x, false) + res_0 := basictypes.ByteArrays(_param_x) + _res_0 := fromSlice(res_0, true) + return _res_0 +} + +//export proxybasictypes__Error +func proxybasictypes__Error() C.int32_t { + res_0 := basictypes.Error() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxybasictypes__ErrorPair +func proxybasictypes__ErrorPair() (C.nint, C.int32_t) { + res_0, res_1 := basictypes.ErrorPair() + _res_0 := C.nint(res_0) + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 +} + +//export proxybasictypes__Ints +func proxybasictypes__Ints(param_x C.int8_t, param_y C.int16_t, param_z C.int32_t, param_t C.int64_t, param_u C.nint) { + _param_x := int8(param_x) + _param_y := int16(param_y) + _param_z := int32(param_z) + _param_t := int64(param_t) + _param_u := int(param_u) + basictypes.Ints(_param_x, _param_y, _param_z, _param_t, _param_u) +} diff --git a/bind/testdata/basictypes.java.c.golden b/bind/testdata/basictypes.java.c.golden new file mode 100644 index 000000000..cb947a2e1 --- /dev/null +++ b/bind/testdata/basictypes.java.c.golden @@ -0,0 +1,61 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java basictypes + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "basictypes.h" + + +JNIEXPORT void JNICALL +Java_basictypes_Basictypes__1init(JNIEnv *env, jclass _unused) { + jclass clazz; +} + +JNIEXPORT jboolean JNICALL +Java_basictypes_Basictypes_bool(JNIEnv* env, jclass _clazz, jboolean p0) { + char _p0 = (char)p0; + char r0 = proxybasictypes__Bool(_p0); + jboolean _r0 = r0 ? JNI_TRUE : JNI_FALSE; + return _r0; +} + +JNIEXPORT jbyteArray JNICALL +Java_basictypes_Basictypes_byteArrays(JNIEnv* env, jclass _clazz, jbyteArray x) { + nbyteslice _x = go_seq_from_java_bytearray(env, x, 0); + nbyteslice r0 = proxybasictypes__ByteArrays(_x); + go_seq_release_byte_array(env, x, _x.ptr); + jbyteArray _r0 = go_seq_to_java_bytearray(env, r0, 1); + return _r0; +} + +JNIEXPORT void JNICALL +Java_basictypes_Basictypes_error(JNIEnv* env, jclass _clazz) { + int32_t r0 = proxybasictypes__Error(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r0); +} + +JNIEXPORT jlong JNICALL +Java_basictypes_Basictypes_errorPair(JNIEnv* env, jclass _clazz) { + struct proxybasictypes__ErrorPair_return res = proxybasictypes__ErrorPair(); + jlong _r0 = (jlong)res.r0; + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT void JNICALL +Java_basictypes_Basictypes_ints(JNIEnv* env, jclass _clazz, jbyte x, jshort y, jint z, jlong t, jlong u) { + int8_t _x = (int8_t)x; + int16_t _y = (int16_t)y; + int32_t _z = (int32_t)z; + int64_t _t = (int64_t)t; + nint _u = (nint)u; + proxybasictypes__Ints(_x, _y, _z, _t, _u); +} + diff --git a/bind/testdata/basictypes.java.golden b/bind/testdata/basictypes.java.golden new file mode 100644 index 000000000..5f3511b7d --- /dev/null +++ b/bind/testdata/basictypes.java.golden @@ -0,0 +1,37 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class basictypes.Basictypes is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java basictypes +package basictypes; + +import go.Seq; + +public abstract class Basictypes { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Basictypes() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + + public static final boolean ABool = true; + public static final double AFloat = 0.2015; + public static final String ALongString = "LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString"; + public static final int ARune = 32; + public static final String AString = "a string"; + public static final long AnInt = 7L; + public static final long AnInt2 = 9223372036854775807L; + + public static native boolean bool(boolean p0); + public static native byte[] byteArrays(byte[] x); + public static native void error() throws Exception; + public static native long errorPair() throws Exception; + public static native void ints(byte x, short y, int z, long t, long u); +} diff --git a/bind/testdata/basictypes.java.h.golden b/bind/testdata/basictypes.java.h.golden new file mode 100644 index 000000000..631ec94fb --- /dev/null +++ b/bind/testdata/basictypes.java.h.golden @@ -0,0 +1,12 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java basictypes + +#ifndef __Basictypes_H__ +#define __Basictypes_H__ + +#include + +#endif diff --git a/bind/testdata/basictypes.objc.go.h.golden b/bind/testdata/basictypes.objc.go.h.golden new file mode 100644 index 000000000..84cbbbda1 --- /dev/null +++ b/bind/testdata/basictypes.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to basictypes Go package. +// gobind -lang=objc basictypes +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_basictypes_H__ +#define __GO_basictypes_H__ + +#include +#include +#endif diff --git a/bind/testdata/basictypes.objc.h.golden b/bind/testdata/basictypes.objc.h.golden new file mode 100644 index 000000000..246b6b199 --- /dev/null +++ b/bind/testdata/basictypes.objc.h.golden @@ -0,0 +1,32 @@ +// Objective-C API for talking to basictypes Go package. +// gobind -lang=objc basictypes +// +// File is generated by gobind. Do not edit. + +#ifndef __Basictypes_H__ +#define __Basictypes_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +FOUNDATION_EXPORT const BOOL BasictypesABool; +FOUNDATION_EXPORT const double BasictypesAFloat; +FOUNDATION_EXPORT NSString* _Nonnull const BasictypesALongString; +FOUNDATION_EXPORT const int32_t BasictypesARune; +FOUNDATION_EXPORT NSString* _Nonnull const BasictypesAString; +FOUNDATION_EXPORT const int64_t BasictypesAnInt; +FOUNDATION_EXPORT const int64_t BasictypesAnInt2; + +FOUNDATION_EXPORT BOOL BasictypesBool(BOOL p0); + +FOUNDATION_EXPORT NSData* _Nullable BasictypesByteArrays(NSData* _Nullable x); + +FOUNDATION_EXPORT BOOL BasictypesError(NSError* _Nullable* _Nullable error); + +FOUNDATION_EXPORT BOOL BasictypesErrorPair(long* _Nullable ret0_, NSError* _Nullable* _Nullable error); + +FOUNDATION_EXPORT void BasictypesInts(int8_t x, int16_t y, int32_t z, int64_t t, long u); + +#endif diff --git a/bind/testdata/basictypes.objc.m.golden b/bind/testdata/basictypes.objc.m.golden new file mode 100644 index 000000000..b46775913 --- /dev/null +++ b/bind/testdata/basictypes.objc.m.golden @@ -0,0 +1,82 @@ +// Objective-C API for talking to basictypes Go package. +// gobind -lang=objc basictypes +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Basictypes.objc.h" + +const BOOL BasictypesABool = YES; +const double BasictypesAFloat = 0.2015; +NSString* const BasictypesALongString = @"LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString"; +const int32_t BasictypesARune = 32; +NSString* const BasictypesAString = @"a string"; +const int64_t BasictypesAnInt = 7LL; +const int64_t BasictypesAnInt2 = 9223372036854775807LL; + + +BOOL BasictypesBool(BOOL p0) { + char _p0 = (char)p0; + char r0 = proxybasictypes__Bool(_p0); + BOOL _ret0_ = r0 ? YES : NO; + return _ret0_; +} + +NSData* _Nullable BasictypesByteArrays(NSData* _Nullable x) { + nbyteslice _x = go_seq_from_objc_bytearray(x, 0); + nbyteslice r0 = proxybasictypes__ByteArrays(_x); + if (![x isKindOfClass:[NSMutableData class]]) { + free(_x.ptr); + } + NSData *_ret0_ = go_seq_to_objc_bytearray(r0, 1); + return _ret0_; +} + +BOOL BasictypesError(NSError* _Nullable* _Nullable error) { + int32_t r0 = proxybasictypes__Error(); + Universeerror* _error = nil; + GoSeqRef* _error_ref = go_seq_from_refnum(r0); + if (_error_ref != NULL) { + _error = _error_ref.obj; + if (_error == nil) { + _error = [[Universeerror alloc] initWithRef:_error_ref]; + } + } + if (_error != nil && error != nil) { + *error = _error; + } + return (_error == nil); +} + +BOOL BasictypesErrorPair(long* _Nullable ret0_, NSError* _Nullable* _Nullable error) { + struct proxybasictypes__ErrorPair_return res = proxybasictypes__ErrorPair(); + long _ret0_ = (long)res.r0; + Universeerror* _error = nil; + GoSeqRef* _error_ref = go_seq_from_refnum(res.r1); + if (_error_ref != NULL) { + _error = _error_ref.obj; + if (_error == nil) { + _error = [[Universeerror alloc] initWithRef:_error_ref]; + } + } + *ret0_ = _ret0_; + if (_error != nil && error != nil) { + *error = _error; + } + return (_error == nil); +} + +void BasictypesInts(int8_t x, int16_t y, int32_t z, int64_t t, long u) { + int8_t _x = (int8_t)x; + int16_t _y = (int16_t)y; + int32_t _z = (int32_t)z; + int64_t _t = (int64_t)t; + nint _u = (nint)u; + proxybasictypes__Ints(_x, _y, _z, _t, _u); +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/benchmark/benchmark.go b/bind/testdata/benchmark/benchmark.go new file mode 100644 index 000000000..d15f4c391 --- /dev/null +++ b/bind/testdata/benchmark/benchmark.go @@ -0,0 +1,171 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package benchmark contains benchmarking bound functions for internal use. +package benchmark + +import ( + "log" + "time" +) + +type Benchmarks interface { + // It seems to be much faster to call a native function from Java + // when there is already a native call earlier in the stack. + + // Run runs a named benchmark from a different thread, with + // no native call prior in the stack. + Run(name string, n int) + // RunDirect runs a named benchmark directly, with the native + // context from the call itself. + RunDirect(name string, n int) + + // Callbacks for Go benchmarks + NewI() I + Noargs() + Onearg(_ int) + Oneret() int + Ref(_ I) + Manyargs(_, _, _, _, _, _, _, _, _, _ int) + String(_ string) + StringRetShort() string + StringRetLong() string + Slice(_ []byte) +} + +type ( + I interface { + F() + } + + AnI struct { + } +) + +func (_ *AnI) F() { +} + +func NewI() I { + return new(AnI) +} + +func runBenchmark(name string, f func(n int)) { + // Run once for warmup + f(1) + n := 1000 + var dt time.Duration + minDuration := 1 * time.Second + for dt < minDuration { + n *= 2 + t0 := time.Now() + f(n) + dt = time.Since(t0) + } + log.Printf("Benchmark%s %d %d ns/op\n", name, n, dt.Nanoseconds()/int64(n)) +} + +func runGoBenchmark(name string, f func()) { + runBenchmark("Go"+name, func(n int) { + for i := 0; i < n; i++ { + f() + } + }) + runBenchmark("Go"+name+"Direct", func(n int) { + done := make(chan struct{}) + go func() { + for i := 0; i < n; i++ { + f() + } + close(done) + }() + <-done + }) +} + +func RunBenchmarks(b Benchmarks) { + names := []string{ + "Empty", + "Noargs", + "Onearg", + "Oneret", + "Manyargs", + "Refforeign", + "Refgo", + "StringShort", + "StringLong", + "StringShortUnicode", + "StringLongUnicode", + "StringRetShort", + "StringRetLong", + "SliceShort", + "SliceLong", + } + for _, name := range names { + runBenchmark("Foreign"+name, func(n int) { + b.Run(name, n) + }) + runBenchmark("Foreign"+name+"Direct", func(n int) { + b.RunDirect(name, n) + }) + } + runGoBenchmark("Empty", func() {}) + runGoBenchmark("Noarg", func() { b.Noargs() }) + runGoBenchmark("Onearg", func() { b.Onearg(0) }) + runGoBenchmark("Oneret", func() { b.Oneret() }) + foreignRef := b.NewI() + runGoBenchmark("Refforeign", func() { b.Ref(foreignRef) }) + goRef := NewI() + runGoBenchmark("Refgo", func() { b.Ref(goRef) }) + runGoBenchmark("Manyargs", func() { b.Manyargs(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }) + runGoBenchmark("StringShort", func() { b.String(ShortString) }) + runGoBenchmark("StringLong", func() { b.String(LongString) }) + runGoBenchmark("StringShortUnicode", func() { b.String(ShortStringUnicode) }) + runGoBenchmark("StringLongUnicode", func() { b.String(LongStringUnicode) }) + runGoBenchmark("StringRetShort", func() { b.StringRetShort() }) + runGoBenchmark("StringRetLong", func() { b.StringRetLong() }) + runGoBenchmark("SliceShort", func() { b.Slice(ShortSlice) }) + runGoBenchmark("SliceLong", func() { b.Slice(LongSlice) }) +} + +func Noargs() { +} + +func Onearg(_ int) { +} + +func Manyargs(_, _, _, _, _, _, _, _, _, _ int) { +} + +func Oneret() int { + return 0 +} + +func String(_ string) { +} + +func StringRetShort() string { + return ShortString +} + +func StringRetLong() string { + return LongString +} + +func Slice(_ []byte) { +} + +func Ref(_ I) { +} + +var ( + ShortSlice = make([]byte, 10) + LongSlice = make([]byte, 100000) +) + +const ( + ShortString = "Hello, World!" + LongString = "Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!, World!" + ShortStringUnicode = "Hello, 世界!" + LongStringUnicode = "Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界! Hello, 世界!, 世界!" +) diff --git a/bind/testdata/cgopkg/cgopkg.go b/bind/testdata/cgopkg/cgopkg.go new file mode 100644 index 000000000..efef3da38 --- /dev/null +++ b/bind/testdata/cgopkg/cgopkg.go @@ -0,0 +1,9 @@ +package cgopkg + +import "C" + +import ( + _ "golang.org/x/mobile/gl" +) + +func Dummy() {} diff --git a/bind/testdata/classes.go b/bind/testdata/classes.go new file mode 100644 index 000000000..7263ac771 --- /dev/null +++ b/bind/testdata/classes.go @@ -0,0 +1,62 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package java + +import ( + gopkg "Java/java" + "Java/java/io" + "Java/java/lang" + "Java/java/lang/System" + "Java/java/util/Spliterators" + "Java/java/util/concurrent" +) + +type Runnable struct { + lang.Runnable +} + +func (r *Runnable) Run(this gopkg.Runnable) { +} + +type InputStream struct { + io.InputStream +} + +func (_ *InputStream) Read() (int32, error) { + return 0, nil +} + +func NewInputStream() *InputStream { + return new(InputStream) +} + +type Future struct { + concurrent.Future +} + +func (_ *Future) Get() (lang.Object, error) { + return nil, nil +} + +// Use a trailing underscore to override multiple overloaded methods. +func (_ *Future) Get_(_ int64, _ concurrent.TimeUnit) (lang.Object, error) { + return nil, nil +} + +type Object struct { + lang.Object +} + +func innerClassTypes() { + // java.util.Spliterators.iterator use inner class types + // for the return value as well as parameters. + Spliterators.Iterator(nil) +} + +func returnType() { + // Implicit types (java.io.Console) should be wrapped. + cons := System.Console() + cons.Flush() +} diff --git a/bind/testdata/classes.go.golden b/bind/testdata/classes.go.golden new file mode 100644 index 000000000..fe6bf15cb --- /dev/null +++ b/bind/testdata/classes.go.golden @@ -0,0 +1,2136 @@ +// Code generated by gobind. DO NOT EDIT. + +package Runnable + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.lang.Runnable proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.lang.Runnable. + Cast func(v interface{}) Java.Java_lang_Runnable +) +// Code generated by gobind. DO NOT EDIT. + +package lang + +import "Java" + +const _ = Java.Dummy + +type Runnable Java.Java_lang_Runnable +type Object Java.Java_lang_Object +type System Java.Java_lang_System +// Code generated by gobind. DO NOT EDIT. + +package InputStream + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.io.InputStream proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.io.InputStream. + Cast func(v interface{}) Java.Java_io_InputStream +) +// Code generated by gobind. DO NOT EDIT. + +package io + +import "Java" + +const _ = Java.Dummy + +type InputStream Java.Java_io_InputStream +type Console Java.Java_io_Console +// Code generated by gobind. DO NOT EDIT. + +package Future + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.concurrent.Future proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.concurrent.Future. + Cast func(v interface{}) Java.Java_util_concurrent_Future +) +// Code generated by gobind. DO NOT EDIT. + +package concurrent + +import "Java" + +const _ = Java.Dummy + +type Future Java.Java_util_concurrent_Future +type TimeUnit Java.Java_util_concurrent_TimeUnit +// Code generated by gobind. DO NOT EDIT. + +package Object + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.lang.Object proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.lang.Object. + Cast func(v interface{}) Java.Java_lang_Object +) +// Code generated by gobind. DO NOT EDIT. + +package TimeUnit + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.concurrent.TimeUnit proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.concurrent.TimeUnit. + Cast func(v interface{}) Java.Java_util_concurrent_TimeUnit +) +// Code generated by gobind. DO NOT EDIT. + +package Spliterators + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + Iterator func(a0 Java.Java_util_Spliterator) Java.Java_util_Iterator + // Cast takes a proxy for a Java object and converts it to a java.util.Spliterators proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Spliterators. + Cast func(v interface{}) Java.Java_util_Spliterators +) +// Code generated by gobind. DO NOT EDIT. + +package util + +import "Java" + +const _ = Java.Dummy + +type Spliterators Java.Java_util_Spliterators +type Iterator Java.Java_util_Iterator +type Spliterator Java.Java_util_Spliterator +// Code generated by gobind. DO NOT EDIT. + +package System + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + Console func() Java.Java_io_Console + // Cast takes a proxy for a Java object and converts it to a java.lang.System proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.lang.System. + Cast func(v interface{}) Java.Java_lang_System +) +// Code generated by gobind. DO NOT EDIT. + +package Future + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.Future proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.Future. + Cast func(v interface{}) Java.Java_Future +) +// Code generated by gobind. DO NOT EDIT. + +package java + +import "Java" + +const _ = Java.Dummy + +type Future Java.Java_Future +type InputStream Java.Java_InputStream +type Object Java.Java_Object +type Runnable Java.Java_Runnable +// Code generated by gobind. DO NOT EDIT. + +package InputStream + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.InputStream proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.InputStream. + Cast func(v interface{}) Java.Java_InputStream +) +// Code generated by gobind. DO NOT EDIT. + +package Object + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.Object proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.Object. + Cast func(v interface{}) Java.Java_Object +) +// Code generated by gobind. DO NOT EDIT. + +package Runnable + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.Runnable proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.Runnable. + Cast func(v interface{}) Java.Java_Runnable +) +// Code generated by gobind. DO NOT EDIT. + +package Iterator + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Iterator proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Iterator. + Cast func(v interface{}) Java.Java_util_Iterator +) +// Code generated by gobind. DO NOT EDIT. + +package Spliterator + +import "Java" + +const _ = Java.Dummy + +type OfInt Java.Java_util_Spliterator_OfInt +type OfLong Java.Java_util_Spliterator_OfLong +type OfDouble Java.Java_util_Spliterator_OfDouble + +const ( + ORDERED = 16 + DISTINCT = 1 + SORTED = 4 + SIZED = 64 + NONNULL = 256 + IMMUTABLE = 1024 + CONCURRENT = 4096 + SUBSIZED = 16384 +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Spliterator proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Spliterator. + Cast func(v interface{}) Java.Java_util_Spliterator +) +// Code generated by gobind. DO NOT EDIT. + +package OfInt + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.PrimitiveIterator.OfInt proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.PrimitiveIterator.OfInt. + Cast func(v interface{}) Java.Java_util_PrimitiveIterator_OfInt +) +// Code generated by gobind. DO NOT EDIT. + +package PrimitiveIterator + +import "Java" + +const _ = Java.Dummy + +type OfInt Java.Java_util_PrimitiveIterator_OfInt +type OfLong Java.Java_util_PrimitiveIterator_OfLong +type OfDouble Java.Java_util_PrimitiveIterator_OfDouble +// Code generated by gobind. DO NOT EDIT. + +package OfInt + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Spliterator.OfInt proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Spliterator.OfInt. + Cast func(v interface{}) Java.Java_util_Spliterator_OfInt +) +// Code generated by gobind. DO NOT EDIT. + +package OfLong + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.PrimitiveIterator.OfLong proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.PrimitiveIterator.OfLong. + Cast func(v interface{}) Java.Java_util_PrimitiveIterator_OfLong +) +// Code generated by gobind. DO NOT EDIT. + +package OfLong + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Spliterator.OfLong proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Spliterator.OfLong. + Cast func(v interface{}) Java.Java_util_Spliterator_OfLong +) +// Code generated by gobind. DO NOT EDIT. + +package OfDouble + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.PrimitiveIterator.OfDouble proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.PrimitiveIterator.OfDouble. + Cast func(v interface{}) Java.Java_util_PrimitiveIterator_OfDouble +) +// Code generated by gobind. DO NOT EDIT. + +package OfDouble + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.util.Spliterator.OfDouble proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.util.Spliterator.OfDouble. + Cast func(v interface{}) Java.Java_util_Spliterator_OfDouble +) +// Code generated by gobind. DO NOT EDIT. + +package Console + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.io.Console proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.io.Console. + Cast func(v interface{}) Java.Java_io_Console +) +// Code generated by gobind. DO NOT EDIT. + +package Java + +// Used to silence this package not used errors +const Dummy = 0 + +type Java_lang_Runnable interface { + Run() +} + +type Java_io_InputStream interface { + Read(a0 ...interface{}) (int32, error) + ToString() string +} + +type Java_util_concurrent_Future interface { + Get(a0 ...interface{}) (Java_lang_Object, error) +} + +type Java_lang_Object interface { + ToString() string +} + +type Java_util_concurrent_TimeUnit interface { + ToString() string +} + +type Java_util_Spliterators interface { + ToString() string +} + +type Java_lang_System interface { + ToString() string +} + +type Java_Future interface { + Get(a0 ...interface{}) (Java_lang_Object, error) + Super() Java_Future + // Unwrap returns the Go object this Java instance + // is wrapping. + // The return value is a java.Future, but the delclared type is + // interface{} to avoid import cycles. + Unwrap() interface{} +} + +type Java_InputStream interface { + Read(a0 ...interface{}) (int32, error) + ToString() string + Super() Java_InputStream + // Unwrap returns the Go object this Java instance + // is wrapping. + // The return value is a java.InputStream, but the delclared type is + // interface{} to avoid import cycles. + Unwrap() interface{} +} + +type Java_Object interface { + ToString() string + Super() Java_Object + // Unwrap returns the Go object this Java instance + // is wrapping. + // The return value is a java.Object, but the delclared type is + // interface{} to avoid import cycles. + Unwrap() interface{} +} + +type Java_Runnable interface { + Run() + Super() Java_Runnable + // Unwrap returns the Go object this Java instance + // is wrapping. + // The return value is a java.Runnable, but the delclared type is + // interface{} to avoid import cycles. + Unwrap() interface{} +} + +type Java_util_Iterator interface { +} + +type Java_util_Spliterator interface { +} + +type Java_util_PrimitiveIterator_OfInt interface { +} + +type Java_util_Spliterator_OfInt interface { +} + +type Java_util_PrimitiveIterator_OfLong interface { +} + +type Java_util_Spliterator_OfLong interface { +} + +type Java_util_PrimitiveIterator_OfDouble interface { +} + +type Java_util_Spliterator_OfDouble interface { +} + +type Java_io_Console interface { + Flush() error + ToString() string +} +// Code generated by gobind. DO NOT EDIT. + +package main + +/* +#include // for free() +#include +#include "seq.h" +#include "classes.h" +*/ +import "C" + +import ( + "Java" + _seq "golang.org/x/mobile/bind/seq" +) + +import "Java/java/lang/Runnable" +import "Java/java/io/InputStream" +import "Java/java/util/concurrent/Future" +import "Java/java/lang/Object" +import "Java/java/util/concurrent/TimeUnit" +import "Java/java/util/Spliterators" +import "Java/java/lang/System" +import "Java/java/Future" +import "Java/java/InputStream" +import "Java/java/Object" +import "Java/java/Runnable" +import "Java/java/util/Iterator" +import "Java/java/util/Spliterator" +import "Java/java/util/PrimitiveIterator/OfInt" +import "Java/java/util/Spliterator/OfInt" +import "Java/java/util/PrimitiveIterator/OfLong" +import "Java/java/util/Spliterator/OfLong" +import "Java/java/util/PrimitiveIterator/OfDouble" +import "Java/java/util/Spliterator/OfDouble" +import "Java/java/io/Console" +import "testdata" +import "unsafe" + +import "reflect" + +import "fmt" + +type proxy interface{ Bind_proxy_refnum__() int32 } + +// Suppress unused package error + +var _ = _seq.FromRefNum + +const _ = Java.Dummy + +//export initClasses +func initClasses() { + C.init_proxies() + init_java_lang_Runnable() + init_java_io_InputStream() + init_java_util_concurrent_Future() + init_java_lang_Object() + init_java_util_concurrent_TimeUnit() + init_java_util_Spliterators() + init_java_lang_System() + init_java_Future() + init_java_InputStream() + init_java_Object() + init_java_Runnable() + init_java_util_Iterator() + init_java_util_Spliterator() + init_java_util_PrimitiveIterator_OfInt() + init_java_util_Spliterator_OfInt() + init_java_util_PrimitiveIterator_OfLong() + init_java_util_Spliterator_OfLong() + init_java_util_PrimitiveIterator_OfDouble() + init_java_util_Spliterator_OfDouble() + init_java_io_Console() +} + +var class_java_lang_Runnable C.jclass + +func init_java_lang_Runnable() { + cls := C.CString("java/lang/Runnable") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_lang_Runnable = clazz + Runnable.Cast = func(v interface{}) Java.Java_lang_Runnable { + t := reflect.TypeOf((*proxy_class_java_lang_Runnable)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_lang_Runnable) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_lang_Runnable) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.lang.Runnable")) + } + return cv + } +} + +type proxy_class_java_lang_Runnable _seq.Ref + +func (p *proxy_class_java_lang_Runnable) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_lang_Runnable) Run() { + res := C.cproxy_java_lang_Runnable_run(C.jint(p.Bind_proxy_refnum__())) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res)) + if _exc_ref != nil { + if res < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } +} + +var class_java_io_InputStream C.jclass + +func init_java_io_InputStream() { + cls := C.CString("java/io/InputStream") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_io_InputStream = clazz + InputStream.Cast = func(v interface{}) Java.Java_io_InputStream { + t := reflect.TypeOf((*proxy_class_java_io_InputStream)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_io_InputStream) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_io_InputStream) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.io.InputStream")) + } + return cv + } +} + +type proxy_class_java_io_InputStream _seq.Ref + +func (p *proxy_class_java_io_InputStream) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_io_InputStream) Read(a0 ...interface{}) (int32, error) { + switch 0 + len(a0) { + case 0: + res := C.cproxy_java_io_InputStream_read__(C.jint(p.Bind_proxy_refnum__())) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + case 1: + _a0, ok0 := a0[0].([]byte) + if ok0 { + __a0 := fromSlice(_a0, false) + res := C.cproxy_java_io_InputStream_read___3B(C.jint(p.Bind_proxy_refnum__()), __a0) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + case 3: + _a0, ok0 := a0[0].([]byte) + _a1, ok1 := a0[1].(int32) + _a2, ok2 := a0[2].(int32) + if ok0 && ok1 && ok2 { + __a0 := fromSlice(_a0, false) + __a1 := C.jint(_a1) + __a2 := C.jint(_a2) + res := C.cproxy_java_io_InputStream_read___3BII(C.jint(p.Bind_proxy_refnum__()), __a0, __a1, __a2) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + } + panic("no overloaded method found for java.io.InputStream.read that matched the arguments") +} + +func (p *proxy_class_java_io_InputStream) ToString() string { + res := C.cproxy_java_io_InputStream_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_util_concurrent_Future C.jclass + +func init_java_util_concurrent_Future() { + cls := C.CString("java/util/concurrent/Future") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_concurrent_Future = clazz + Future.Cast = func(v interface{}) Java.Java_util_concurrent_Future { + t := reflect.TypeOf((*proxy_class_java_util_concurrent_Future)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_concurrent_Future) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_concurrent_Future) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.concurrent.Future")) + } + return cv + } +} + +type proxy_class_java_util_concurrent_Future _seq.Ref + +func (p *proxy_class_java_util_concurrent_Future) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_util_concurrent_Future) Get(a0 ...interface{}) (Java.Java_lang_Object, error) { + switch 0 + len(a0) { + case 0: + res := C.cproxy_java_util_concurrent_Future_get__(C.jint(p.Bind_proxy_refnum__())) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + case 2: + _a0, ok0 := a0[0].(int64) + _a1, ok1 := a0[1].(Java.Java_util_concurrent_TimeUnit) + if ok0 && ok1 { + __a0 := C.jlong(_a0) + var __a1 C.jint = _seq.NullRefNum + if _a1 != nil { + __a1 = C.jint(_seq.ToRefNum(_a1)) + } + res := C.cproxy_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2(C.jint(p.Bind_proxy_refnum__()), __a0, __a1) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + } + panic("no overloaded method found for java.util.concurrent.Future.get that matched the arguments") +} + +var class_java_lang_Object C.jclass + +func init_java_lang_Object() { + cls := C.CString("java/lang/Object") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_lang_Object = clazz + Object.Cast = func(v interface{}) Java.Java_lang_Object { + t := reflect.TypeOf((*proxy_class_java_lang_Object)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_lang_Object) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_lang_Object) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.lang.Object")) + } + return cv + } +} + +type proxy_class_java_lang_Object _seq.Ref + +func (p *proxy_class_java_lang_Object) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_lang_Object) ToString() string { + res := C.cproxy_java_lang_Object_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_util_concurrent_TimeUnit C.jclass + +func init_java_util_concurrent_TimeUnit() { + cls := C.CString("java/util/concurrent/TimeUnit") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_concurrent_TimeUnit = clazz + TimeUnit.Cast = func(v interface{}) Java.Java_util_concurrent_TimeUnit { + t := reflect.TypeOf((*proxy_class_java_util_concurrent_TimeUnit)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_concurrent_TimeUnit) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_concurrent_TimeUnit) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.concurrent.TimeUnit")) + } + return cv + } +} + +type proxy_class_java_util_concurrent_TimeUnit _seq.Ref + +func (p *proxy_class_java_util_concurrent_TimeUnit) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_util_concurrent_TimeUnit) ToString() string { + res := C.cproxy_java_util_concurrent_TimeUnit_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_util_Spliterators C.jclass + +func init_java_util_Spliterators() { + cls := C.CString("java/util/Spliterators") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_Spliterators = clazz + Spliterators.Iterator = func(a0 Java.Java_util_Spliterator) Java.Java_util_Iterator { + { + var __a0 C.jint = _seq.NullRefNum + if a0 != nil { + __a0 = C.jint(_seq.ToRefNum(a0)) + } + res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2(__a0) + var _res Java.Java_util_Iterator + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_util_Iterator) + } else { // foreign object + _res = (*proxy_class_java_util_Iterator)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res + } + { + _a0, ok0 := a0.(Java.Java_util_Spliterator_OfInt) + if ok0 { + var __a0 C.jint = _seq.NullRefNum + if _a0 != nil { + __a0 = C.jint(_seq.ToRefNum(_a0)) + } + res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(__a0) + var _res Java.Java_util_PrimitiveIterator_OfInt + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_util_PrimitiveIterator_OfInt) + } else { // foreign object + _res = (*proxy_class_java_util_PrimitiveIterator_OfInt)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res + } + } + { + _a0, ok0 := a0.(Java.Java_util_Spliterator_OfLong) + if ok0 { + var __a0 C.jint = _seq.NullRefNum + if _a0 != nil { + __a0 = C.jint(_seq.ToRefNum(_a0)) + } + res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2(__a0) + var _res Java.Java_util_PrimitiveIterator_OfLong + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_util_PrimitiveIterator_OfLong) + } else { // foreign object + _res = (*proxy_class_java_util_PrimitiveIterator_OfLong)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res + } + } + { + _a0, ok0 := a0.(Java.Java_util_Spliterator_OfDouble) + if ok0 { + var __a0 C.jint = _seq.NullRefNum + if _a0 != nil { + __a0 = C.jint(_seq.ToRefNum(_a0)) + } + res := C.cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2(__a0) + var _res Java.Java_util_PrimitiveIterator_OfDouble + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_util_PrimitiveIterator_OfDouble) + } else { // foreign object + _res = (*proxy_class_java_util_PrimitiveIterator_OfDouble)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res + } + } + panic("no overloaded method found for java.util.Spliterators.iterator that matched the arguments") + } + + Spliterators.Cast = func(v interface{}) Java.Java_util_Spliterators { + t := reflect.TypeOf((*proxy_class_java_util_Spliterators)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterators) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Spliterators) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterators")) + } + return cv + } +} + +type proxy_class_java_util_Spliterators _seq.Ref + +func (p *proxy_class_java_util_Spliterators) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_util_Spliterators) ToString() string { + res := C.cproxy_java_util_Spliterators_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_lang_System C.jclass + +func init_java_lang_System() { + cls := C.CString("java/lang/System") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_lang_System = clazz + System.Console = func() Java.Java_io_Console { + res := C.cproxy_s_java_lang_System_console() + var _res Java.Java_io_Console + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_io_Console) + } else { // foreign object + _res = (*proxy_class_java_io_Console)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res + } + + System.Cast = func(v interface{}) Java.Java_lang_System { + t := reflect.TypeOf((*proxy_class_java_lang_System)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_lang_System) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_lang_System) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.lang.System")) + } + return cv + } +} + +type proxy_class_java_lang_System _seq.Ref + +func (p *proxy_class_java_lang_System) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_lang_System) ToString() string { + res := C.cproxy_java_lang_System_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_Future C.jclass + +func init_java_Future() { + cls := C.CString("java/Future") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_Future = clazz + Future.Cast = func(v interface{}) Java.Java_Future { + t := reflect.TypeOf((*proxy_class_java_Future)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_Future) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_Future) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.Future")) + } + return cv + } +} + +type proxy_class_java_Future _seq.Ref + +func (p *proxy_class_java_Future) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_Future) Get(a0 ...interface{}) (Java.Java_lang_Object, error) { + switch 0 + len(a0) { + case 0: + res := C.cproxy_java_Future_get__(C.jint(p.Bind_proxy_refnum__())) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + case 2: + _a0, ok0 := a0[0].(int64) + _a1, ok1 := a0[1].(Java.Java_util_concurrent_TimeUnit) + if ok0 && ok1 { + __a0 := C.jlong(_a0) + var __a1 C.jint = _seq.NullRefNum + if _a1 != nil { + __a1 = C.jint(_seq.ToRefNum(_a1)) + } + res := C.cproxy_java_Future_get__JLjava_util_concurrent_TimeUnit_2(C.jint(p.Bind_proxy_refnum__()), __a0, __a1) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + } + panic("no overloaded method found for java.Future.get that matched the arguments") +} + +func (p *proxy_class_java_Future) Super() Java.Java_Future { + return &super_java_Future{p} +} + +type super_java_Future struct{ *proxy_class_java_Future } + +func (p *proxy_class_java_Future) Unwrap() interface{} { + goRefnum := C.go_seq_unwrap(C.jint(p.Bind_proxy_refnum__())) + return _seq.FromRefNum(int32(goRefnum)).Get().(*java.Future) +} + +func (p *super_java_Future) Get(a0 ...interface{}) (Java.Java_lang_Object, error) { + switch 0 + len(a0) { + case 0: + res := C.csuper_java_Future_get__(C.jint(p.Bind_proxy_refnum__())) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + case 2: + _a0, ok0 := a0[0].(int64) + _a1, ok1 := a0[1].(Java.Java_util_concurrent_TimeUnit) + if ok0 && ok1 { + __a0 := C.jlong(_a0) + var __a1 C.jint = _seq.NullRefNum + if _a1 != nil { + __a1 = C.jint(_seq.ToRefNum(_a1)) + } + res := C.csuper_java_Future_get__JLjava_util_concurrent_TimeUnit_2(C.jint(p.Bind_proxy_refnum__()), __a0, __a1) + var _res Java.Java_lang_Object + _res_ref := _seq.FromRefNum(int32(res.res)) + if _res_ref != nil { + if res.res < 0 { // go object + _res = _res_ref.Get().(Java.Java_lang_Object) + } else { // foreign object + _res = (*proxy_class_java_lang_Object)(_res_ref) + } + } + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + } + panic("no overloaded method found for java.Future.get that matched the arguments") +} + +var class_java_InputStream C.jclass + +func init_java_InputStream() { + cls := C.CString("java/InputStream") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_InputStream = clazz + InputStream.Cast = func(v interface{}) Java.Java_InputStream { + t := reflect.TypeOf((*proxy_class_java_InputStream)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_InputStream) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_InputStream) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.InputStream")) + } + return cv + } +} + +type proxy_class_java_InputStream _seq.Ref + +func (p *proxy_class_java_InputStream) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_InputStream) Read(a0 ...interface{}) (int32, error) { + switch 0 + len(a0) { + case 0: + res := C.cproxy_java_InputStream_read__(C.jint(p.Bind_proxy_refnum__())) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + case 1: + _a0, ok0 := a0[0].([]byte) + if ok0 { + __a0 := fromSlice(_a0, false) + res := C.cproxy_java_InputStream_read___3B(C.jint(p.Bind_proxy_refnum__()), __a0) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + case 3: + _a0, ok0 := a0[0].([]byte) + _a1, ok1 := a0[1].(int32) + _a2, ok2 := a0[2].(int32) + if ok0 && ok1 && ok2 { + __a0 := fromSlice(_a0, false) + __a1 := C.jint(_a1) + __a2 := C.jint(_a2) + res := C.cproxy_java_InputStream_read___3BII(C.jint(p.Bind_proxy_refnum__()), __a0, __a1, __a2) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + } + panic("no overloaded method found for java.InputStream.read that matched the arguments") +} + +func (p *proxy_class_java_InputStream) ToString() string { + res := C.cproxy_java_InputStream_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +func (p *proxy_class_java_InputStream) Super() Java.Java_InputStream { + return &super_java_InputStream{p} +} + +type super_java_InputStream struct{ *proxy_class_java_InputStream } + +func (p *proxy_class_java_InputStream) Unwrap() interface{} { + goRefnum := C.go_seq_unwrap(C.jint(p.Bind_proxy_refnum__())) + return _seq.FromRefNum(int32(goRefnum)).Get().(*java.InputStream) +} + +func (p *super_java_InputStream) Read(a0 ...interface{}) (int32, error) { + switch 0 + len(a0) { + case 0: + res := C.csuper_java_InputStream_read__(C.jint(p.Bind_proxy_refnum__())) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + case 1: + _a0, ok0 := a0[0].([]byte) + if ok0 { + __a0 := fromSlice(_a0, false) + res := C.csuper_java_InputStream_read___3B(C.jint(p.Bind_proxy_refnum__()), __a0) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + case 3: + _a0, ok0 := a0[0].([]byte) + _a1, ok1 := a0[1].(int32) + _a2, ok2 := a0[2].(int32) + if ok0 && ok1 && ok2 { + __a0 := fromSlice(_a0, false) + __a1 := C.jint(_a1) + __a2 := C.jint(_a2) + res := C.csuper_java_InputStream_read___3BII(C.jint(p.Bind_proxy_refnum__()), __a0, __a1, __a2) + _res := int32(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _res, _exc + } + } + panic("no overloaded method found for java.InputStream.read that matched the arguments") +} + +func (p *super_java_InputStream) ToString() string { + res := C.csuper_java_InputStream_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_Object C.jclass + +func init_java_Object() { + cls := C.CString("java/Object") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_Object = clazz + Object.Cast = func(v interface{}) Java.Java_Object { + t := reflect.TypeOf((*proxy_class_java_Object)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_Object) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_Object) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.Object")) + } + return cv + } +} + +type proxy_class_java_Object _seq.Ref + +func (p *proxy_class_java_Object) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_Object) ToString() string { + res := C.cproxy_java_Object_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +func (p *proxy_class_java_Object) Super() Java.Java_Object { + return &super_java_Object{p} +} + +type super_java_Object struct{ *proxy_class_java_Object } + +func (p *proxy_class_java_Object) Unwrap() interface{} { + goRefnum := C.go_seq_unwrap(C.jint(p.Bind_proxy_refnum__())) + return _seq.FromRefNum(int32(goRefnum)).Get().(*java.Object) +} + +func (p *super_java_Object) ToString() string { + res := C.csuper_java_Object_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_Runnable C.jclass + +func init_java_Runnable() { + cls := C.CString("java/Runnable") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_Runnable = clazz + Runnable.Cast = func(v interface{}) Java.Java_Runnable { + t := reflect.TypeOf((*proxy_class_java_Runnable)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_Runnable) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_Runnable) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.Runnable")) + } + return cv + } +} + +type proxy_class_java_Runnable _seq.Ref + +func (p *proxy_class_java_Runnable) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_Runnable) Run() { + res := C.cproxy_java_Runnable_run(C.jint(p.Bind_proxy_refnum__())) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res)) + if _exc_ref != nil { + if res < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } +} + +func (p *proxy_class_java_Runnable) Super() Java.Java_Runnable { + return &super_java_Runnable{p} +} + +type super_java_Runnable struct{ *proxy_class_java_Runnable } + +func (p *proxy_class_java_Runnable) Unwrap() interface{} { + goRefnum := C.go_seq_unwrap(C.jint(p.Bind_proxy_refnum__())) + return _seq.FromRefNum(int32(goRefnum)).Get().(*java.Runnable) +} + +func (p *super_java_Runnable) Run() { + res := C.csuper_java_Runnable_run(C.jint(p.Bind_proxy_refnum__())) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res)) + if _exc_ref != nil { + if res < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } +} + +var class_java_util_Iterator C.jclass + +func init_java_util_Iterator() { + cls := C.CString("java/util/Iterator") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_Iterator = clazz + Iterator.Cast = func(v interface{}) Java.Java_util_Iterator { + t := reflect.TypeOf((*proxy_class_java_util_Iterator)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Iterator) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Iterator) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Iterator")) + } + return cv + } +} + +type proxy_class_java_util_Iterator _seq.Ref + +func (p *proxy_class_java_util_Iterator) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +var class_java_util_Spliterator C.jclass + +func init_java_util_Spliterator() { + cls := C.CString("java/util/Spliterator") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_Spliterator = clazz + Spliterator.Cast = func(v interface{}) Java.Java_util_Spliterator { + t := reflect.TypeOf((*proxy_class_java_util_Spliterator)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterator) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Spliterator) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterator")) + } + return cv + } +} + +type proxy_class_java_util_Spliterator _seq.Ref + +func (p *proxy_class_java_util_Spliterator) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +var class_java_util_PrimitiveIterator_OfInt C.jclass + +func init_java_util_PrimitiveIterator_OfInt() { + cls := C.CString("java/util/PrimitiveIterator$OfInt") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_PrimitiveIterator_OfInt = clazz + OfInt.Cast = func(v interface{}) Java.Java_util_PrimitiveIterator_OfInt { + t := reflect.TypeOf((*proxy_class_java_util_PrimitiveIterator_OfInt)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_PrimitiveIterator_OfInt) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_PrimitiveIterator_OfInt) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.PrimitiveIterator.OfInt")) + } + return cv + } +} + +type proxy_class_java_util_PrimitiveIterator_OfInt _seq.Ref + +func (p *proxy_class_java_util_PrimitiveIterator_OfInt) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +var class_java_util_Spliterator_OfInt C.jclass + +func init_java_util_Spliterator_OfInt() { + cls := C.CString("java/util/Spliterator$OfInt") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_Spliterator_OfInt = clazz + OfInt.Cast = func(v interface{}) Java.Java_util_Spliterator_OfInt { + t := reflect.TypeOf((*proxy_class_java_util_Spliterator_OfInt)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterator_OfInt) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Spliterator_OfInt) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterator.OfInt")) + } + return cv + } +} + +type proxy_class_java_util_Spliterator_OfInt _seq.Ref + +func (p *proxy_class_java_util_Spliterator_OfInt) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +var class_java_util_PrimitiveIterator_OfLong C.jclass + +func init_java_util_PrimitiveIterator_OfLong() { + cls := C.CString("java/util/PrimitiveIterator$OfLong") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_PrimitiveIterator_OfLong = clazz + OfLong.Cast = func(v interface{}) Java.Java_util_PrimitiveIterator_OfLong { + t := reflect.TypeOf((*proxy_class_java_util_PrimitiveIterator_OfLong)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_PrimitiveIterator_OfLong) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_PrimitiveIterator_OfLong) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.PrimitiveIterator.OfLong")) + } + return cv + } +} + +type proxy_class_java_util_PrimitiveIterator_OfLong _seq.Ref + +func (p *proxy_class_java_util_PrimitiveIterator_OfLong) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +var class_java_util_Spliterator_OfLong C.jclass + +func init_java_util_Spliterator_OfLong() { + cls := C.CString("java/util/Spliterator$OfLong") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_Spliterator_OfLong = clazz + OfLong.Cast = func(v interface{}) Java.Java_util_Spliterator_OfLong { + t := reflect.TypeOf((*proxy_class_java_util_Spliterator_OfLong)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterator_OfLong) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Spliterator_OfLong) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterator.OfLong")) + } + return cv + } +} + +type proxy_class_java_util_Spliterator_OfLong _seq.Ref + +func (p *proxy_class_java_util_Spliterator_OfLong) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +var class_java_util_PrimitiveIterator_OfDouble C.jclass + +func init_java_util_PrimitiveIterator_OfDouble() { + cls := C.CString("java/util/PrimitiveIterator$OfDouble") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_PrimitiveIterator_OfDouble = clazz + OfDouble.Cast = func(v interface{}) Java.Java_util_PrimitiveIterator_OfDouble { + t := reflect.TypeOf((*proxy_class_java_util_PrimitiveIterator_OfDouble)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_PrimitiveIterator_OfDouble) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_PrimitiveIterator_OfDouble) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.PrimitiveIterator.OfDouble")) + } + return cv + } +} + +type proxy_class_java_util_PrimitiveIterator_OfDouble _seq.Ref + +func (p *proxy_class_java_util_PrimitiveIterator_OfDouble) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +var class_java_util_Spliterator_OfDouble C.jclass + +func init_java_util_Spliterator_OfDouble() { + cls := C.CString("java/util/Spliterator$OfDouble") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_util_Spliterator_OfDouble = clazz + OfDouble.Cast = func(v interface{}) Java.Java_util_Spliterator_OfDouble { + t := reflect.TypeOf((*proxy_class_java_util_Spliterator_OfDouble)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_util_Spliterator_OfDouble) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_util_Spliterator_OfDouble) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.util.Spliterator.OfDouble")) + } + return cv + } +} + +type proxy_class_java_util_Spliterator_OfDouble _seq.Ref + +func (p *proxy_class_java_util_Spliterator_OfDouble) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +var class_java_io_Console C.jclass + +func init_java_io_Console() { + cls := C.CString("java/io/Console") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_io_Console = clazz + Console.Cast = func(v interface{}) Java.Java_io_Console { + t := reflect.TypeOf((*proxy_class_java_io_Console)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_io_Console) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_io_Console) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.io.Console")) + } + return cv + } +} + +type proxy_class_java_io_Console _seq.Ref + +func (p *proxy_class_java_io_Console) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_io_Console) Flush() error { + res := C.cproxy_java_io_Console_flush(C.jint(p.Bind_proxy_refnum__())) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res)) + if _exc_ref != nil { + if res < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + return _exc +} + +func (p *proxy_class_java_io_Console) ToString() string { + res := C.cproxy_java_io_Console_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package java. +// +// autogenerated by gobind -lang=go classes +package main + +/* +#include +#include +#include "seq.h" +#include "java.h" + +*/ +import "C" + +import ( + java_1 "Java/java" + "Java/java/io" + "Java/java/lang" + "Java/java/util/concurrent" + "classes" + _seq "golang.org/x/mobile/bind/seq" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyjava_Future_Future_Set +func proxyjava_Future_Future_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v concurrent.Future + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(concurrent.Future) + } else { // foreign object + _v = (*proxy_class_java_util_concurrent_Future)(_v_ref) + } + } + ref.Get().(*java.Future).Future = _v +} + +//export proxyjava_Future_Future_Get +func proxyjava_Future_Future_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*java.Future).Future + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxyjava_Future_Get +func proxyjava_Future_Get(refnum C.int32_t) (C.int32_t, C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*java.Future) + res_0, res_1 := v.Get() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 +} + +//export proxyjava_Future_Get_ +func proxyjava_Future_Get_(refnum C.int32_t, param_p0 C.int64_t, param_p1 C.int32_t) (C.int32_t, C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*java.Future) + _param_p0 := int64(param_p0) + var _param_p1 concurrent.TimeUnit + _param_p1_ref := _seq.FromRefNum(int32(param_p1)) + if _param_p1_ref != nil { + if param_p1 < 0 { // go object + _param_p1 = _param_p1_ref.Get().(concurrent.TimeUnit) + } else { // foreign object + _param_p1 = (*proxy_class_java_util_concurrent_TimeUnit)(_param_p1_ref) + } + } + res_0, res_1 := v.Get_(_param_p0, _param_p1) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 +} + +//export new_java_Future +func new_java_Future() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(java.Future))) +} + +//export proxyjava_InputStream_InputStream_Set +func proxyjava_InputStream_InputStream_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v io.InputStream + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(io.InputStream) + } else { // foreign object + _v = (*proxy_class_java_io_InputStream)(_v_ref) + } + } + ref.Get().(*java.InputStream).InputStream = _v +} + +//export proxyjava_InputStream_InputStream_Get +func proxyjava_InputStream_InputStream_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*java.InputStream).InputStream + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxyjava_InputStream_Read +func proxyjava_InputStream_Read(refnum C.int32_t) (C.int32_t, C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*java.InputStream) + res_0, res_1 := v.Read() + _res_0 := C.int32_t(res_0) + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 +} + +//export new_java_InputStream +func new_java_InputStream() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(java.InputStream))) +} + +//export proxyjava_Object_Object_Set +func proxyjava_Object_Object_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v lang.Object + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(lang.Object) + } else { // foreign object + _v = (*proxy_class_java_lang_Object)(_v_ref) + } + } + ref.Get().(*java.Object).Object = _v +} + +//export proxyjava_Object_Object_Get +func proxyjava_Object_Object_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*java.Object).Object + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export new_java_Object +func new_java_Object() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(java.Object))) +} + +//export proxyjava_Runnable_Runnable_Set +func proxyjava_Runnable_Runnable_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v lang.Runnable + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(lang.Runnable) + } else { // foreign object + _v = (*proxy_class_java_lang_Runnable)(_v_ref) + } + } + ref.Get().(*java.Runnable).Runnable = _v +} + +//export proxyjava_Runnable_Runnable_Get +func proxyjava_Runnable_Runnable_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*java.Runnable).Runnable + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxyjava_Runnable_Run +func proxyjava_Runnable_Run(refnum C.int32_t, param_this C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*java.Runnable) + var _param_this java_1.Runnable + _param_this_ref := _seq.FromRefNum(int32(param_this)) + if _param_this_ref != nil { + if param_this < 0 { // go object + _param_this = _param_this_ref.Get().(java_1.Runnable) + } else { // foreign object + _param_this = (*proxy_class_java_Runnable)(_param_this_ref) + } + } + v.Run(_param_this) +} + +//export new_java_Runnable +func new_java_Runnable() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(java.Runnable))) +} + +//export proxyjava__NewInputStream +func proxyjava__NewInputStream() C.int32_t { + res_0 := java.NewInputStream() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} diff --git a/bind/testdata/classes.java.c.golden b/bind/testdata/classes.java.c.golden new file mode 100644 index 000000000..811f9612e --- /dev/null +++ b/bind/testdata/classes.java.c.golden @@ -0,0 +1,892 @@ +// Code generated by gobind. DO NOT EDIT. + + +#include +#include "seq.h" +#include "classes.h" + +static jclass class_java_lang_Runnable; +static jmethodID m_java_lang_Runnable_run; +static jclass class_java_io_InputStream; +static jmethodID m_java_io_InputStream_read__; +static jmethodID m_java_io_InputStream_read___3B; +static jmethodID m_java_io_InputStream_read___3BII; +static jmethodID m_java_io_InputStream_toString; +static jclass class_java_util_concurrent_Future; +static jmethodID m_java_util_concurrent_Future_get__; +static jmethodID m_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2; +static jclass class_java_lang_Object; +static jmethodID m_java_lang_Object_toString; +static jclass class_java_util_concurrent_TimeUnit; +static jmethodID m_java_util_concurrent_TimeUnit_toString; +static jclass class_java_util_Spliterators; +static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2; +static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2; +static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2; +static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2; +static jmethodID m_java_util_Spliterators_toString; +ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2(jint a0) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL); + jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2, _a0); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(jint a0) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL); + jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2, _a0); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2(jint a0) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL); + jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2, _a0); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2(jint a0) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL); + jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2, _a0); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +static jclass class_java_lang_System; +static jmethodID m_s_java_lang_System_console; +static jmethodID m_java_lang_System_toString; +ret_jint cproxy_s_java_lang_System_console() { + JNIEnv *env = go_seq_push_local_frame(0); + jobject res = (*env)->CallStaticObjectMethod(env, class_java_lang_System, m_s_java_lang_System_console); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +static jclass class_java_Future; +static jclass sclass_java_Future; +static jmethodID m_java_Future_get__; +static jmethodID sm_java_Future_get__; +static jmethodID m_java_Future_get__JLjava_util_concurrent_TimeUnit_2; +static jmethodID sm_java_Future_get__JLjava_util_concurrent_TimeUnit_2; +static jclass class_java_InputStream; +static jclass sclass_java_InputStream; +static jmethodID m_java_InputStream_read__; +static jmethodID sm_java_InputStream_read__; +static jmethodID m_java_InputStream_read___3B; +static jmethodID sm_java_InputStream_read___3B; +static jmethodID m_java_InputStream_read___3BII; +static jmethodID sm_java_InputStream_read___3BII; +static jmethodID m_java_InputStream_toString; +static jmethodID sm_java_InputStream_toString; +static jclass class_java_Object; +static jclass sclass_java_Object; +static jmethodID m_java_Object_toString; +static jmethodID sm_java_Object_toString; +static jclass class_java_Runnable; +static jclass sclass_java_Runnable; +static jmethodID m_java_Runnable_run; +static jmethodID sm_java_Runnable_run; +static jclass class_java_util_Iterator; +static jclass class_java_util_Spliterator; +static jclass class_java_util_PrimitiveIterator_OfInt; +static jclass class_java_util_Spliterator_OfInt; +static jclass class_java_util_PrimitiveIterator_OfLong; +static jclass class_java_util_Spliterator_OfLong; +static jclass class_java_util_PrimitiveIterator_OfDouble; +static jclass class_java_util_Spliterator_OfDouble; +static jclass class_java_io_Console; +static jmethodID m_java_io_Console_flush; +static jmethodID m_java_io_Console_toString; + +void init_proxies() { + JNIEnv *env = go_seq_push_local_frame(20); + jclass clazz; + clazz = go_seq_find_class("java/lang/Runnable"); + if (clazz != NULL) { + class_java_lang_Runnable = (*env)->NewGlobalRef(env, clazz); + m_java_lang_Runnable_run = go_seq_get_method_id(clazz, "run", "()V"); + } + clazz = go_seq_find_class("java/io/InputStream"); + if (clazz != NULL) { + class_java_io_InputStream = (*env)->NewGlobalRef(env, clazz); + m_java_io_InputStream_read__ = go_seq_get_method_id(clazz, "read", "()I"); + m_java_io_InputStream_read___3B = go_seq_get_method_id(clazz, "read", "([B)I"); + m_java_io_InputStream_read___3BII = go_seq_get_method_id(clazz, "read", "([BII)I"); + m_java_io_InputStream_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/util/concurrent/Future"); + if (clazz != NULL) { + class_java_util_concurrent_Future = (*env)->NewGlobalRef(env, clazz); + m_java_util_concurrent_Future_get__ = go_seq_get_method_id(clazz, "get", "()Ljava/lang/Object;"); + m_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2 = go_seq_get_method_id(clazz, "get", "(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object;"); + } + clazz = go_seq_find_class("java/lang/Object"); + if (clazz != NULL) { + class_java_lang_Object = (*env)->NewGlobalRef(env, clazz); + m_java_lang_Object_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/util/concurrent/TimeUnit"); + if (clazz != NULL) { + class_java_util_concurrent_TimeUnit = (*env)->NewGlobalRef(env, clazz); + m_java_util_concurrent_TimeUnit_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/util/Spliterators"); + if (clazz != NULL) { + class_java_util_Spliterators = (*env)->NewGlobalRef(env, clazz); + m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator;)Ljava/util/Iterator;"); + m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfInt;)Ljava/util/PrimitiveIterator$OfInt;"); + m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfLong;)Ljava/util/PrimitiveIterator$OfLong;"); + m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfDouble;)Ljava/util/PrimitiveIterator$OfDouble;"); + m_java_util_Spliterators_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/lang/System"); + if (clazz != NULL) { + class_java_lang_System = (*env)->NewGlobalRef(env, clazz); + m_s_java_lang_System_console = go_seq_get_static_method_id(clazz, "console", "()Ljava/io/Console;"); + m_java_lang_System_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/Future"); + if (clazz != NULL) { + class_java_Future = (*env)->NewGlobalRef(env, clazz); + sclass_java_Future = (*env)->GetSuperclass(env, clazz); + sclass_java_Future = (*env)->NewGlobalRef(env, sclass_java_Future); + m_java_Future_get__ = go_seq_get_method_id(clazz, "get", "()Ljava/lang/Object;"); + sm_java_Future_get__ = go_seq_get_method_id(sclass_java_Future, "get", "()Ljava/lang/Object;"); + m_java_Future_get__JLjava_util_concurrent_TimeUnit_2 = go_seq_get_method_id(clazz, "get", "(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object;"); + sm_java_Future_get__JLjava_util_concurrent_TimeUnit_2 = go_seq_get_method_id(sclass_java_Future, "get", "(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object;"); + } + clazz = go_seq_find_class("java/InputStream"); + if (clazz != NULL) { + class_java_InputStream = (*env)->NewGlobalRef(env, clazz); + sclass_java_InputStream = (*env)->GetSuperclass(env, clazz); + sclass_java_InputStream = (*env)->NewGlobalRef(env, sclass_java_InputStream); + m_java_InputStream_read__ = go_seq_get_method_id(clazz, "read", "()I"); + sm_java_InputStream_read__ = go_seq_get_method_id(sclass_java_InputStream, "read", "()I"); + m_java_InputStream_read___3B = go_seq_get_method_id(clazz, "read", "([B)I"); + sm_java_InputStream_read___3B = go_seq_get_method_id(sclass_java_InputStream, "read", "([B)I"); + m_java_InputStream_read___3BII = go_seq_get_method_id(clazz, "read", "([BII)I"); + sm_java_InputStream_read___3BII = go_seq_get_method_id(sclass_java_InputStream, "read", "([BII)I"); + m_java_InputStream_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + sm_java_InputStream_toString = go_seq_get_method_id(sclass_java_InputStream, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/Object"); + if (clazz != NULL) { + class_java_Object = (*env)->NewGlobalRef(env, clazz); + sclass_java_Object = (*env)->GetSuperclass(env, clazz); + sclass_java_Object = (*env)->NewGlobalRef(env, sclass_java_Object); + m_java_Object_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + sm_java_Object_toString = go_seq_get_method_id(sclass_java_Object, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/Runnable"); + if (clazz != NULL) { + class_java_Runnable = (*env)->NewGlobalRef(env, clazz); + sclass_java_Runnable = (*env)->GetSuperclass(env, clazz); + sclass_java_Runnable = (*env)->NewGlobalRef(env, sclass_java_Runnable); + m_java_Runnable_run = go_seq_get_method_id(clazz, "run", "()V"); + sm_java_Runnable_run = go_seq_get_method_id(sclass_java_Runnable, "run", "()V"); + } + clazz = go_seq_find_class("java/util/Iterator"); + if (clazz != NULL) { + class_java_util_Iterator = (*env)->NewGlobalRef(env, clazz); + } + clazz = go_seq_find_class("java/util/Spliterator"); + if (clazz != NULL) { + class_java_util_Spliterator = (*env)->NewGlobalRef(env, clazz); + } + clazz = go_seq_find_class("java/util/PrimitiveIterator$OfInt"); + if (clazz != NULL) { + class_java_util_PrimitiveIterator_OfInt = (*env)->NewGlobalRef(env, clazz); + } + clazz = go_seq_find_class("java/util/Spliterator$OfInt"); + if (clazz != NULL) { + class_java_util_Spliterator_OfInt = (*env)->NewGlobalRef(env, clazz); + } + clazz = go_seq_find_class("java/util/PrimitiveIterator$OfLong"); + if (clazz != NULL) { + class_java_util_PrimitiveIterator_OfLong = (*env)->NewGlobalRef(env, clazz); + } + clazz = go_seq_find_class("java/util/Spliterator$OfLong"); + if (clazz != NULL) { + class_java_util_Spliterator_OfLong = (*env)->NewGlobalRef(env, clazz); + } + clazz = go_seq_find_class("java/util/PrimitiveIterator$OfDouble"); + if (clazz != NULL) { + class_java_util_PrimitiveIterator_OfDouble = (*env)->NewGlobalRef(env, clazz); + } + clazz = go_seq_find_class("java/util/Spliterator$OfDouble"); + if (clazz != NULL) { + class_java_util_Spliterator_OfDouble = (*env)->NewGlobalRef(env, clazz); + } + clazz = go_seq_find_class("java/io/Console"); + if (clazz != NULL) { + class_java_io_Console = (*env)->NewGlobalRef(env, clazz); + m_java_io_Console_flush = go_seq_get_method_id(clazz, "flush", "()V"); + m_java_io_Console_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + go_seq_pop_local_frame(env); +} + +jint cproxy_java_lang_Runnable_run(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + (*env)->CallVoidMethod(env, _this, m_java_lang_Runnable_run); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + go_seq_pop_local_frame(env); + return _exc_ref; +} + +ret_jint cproxy_java_io_InputStream_read__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jint res = (*env)->CallIntMethod(env, _this, m_java_io_InputStream_read__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_io_InputStream_read___3B(jint this, nbyteslice a0) { + JNIEnv *env = go_seq_push_local_frame(2); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint res = (*env)->CallIntMethod(env, _this, m_java_io_InputStream_read___3B, _a0); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_io_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) { + JNIEnv *env = go_seq_push_local_frame(4); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint _a1 = a1; + jint _a2 = a2; + jint res = (*env)->CallIntMethod(env, _this, m_java_io_InputStream_read___3BII, _a0, _a1, _a2); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_io_InputStream_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_io_InputStream_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_util_concurrent_Future_get__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jobject res = (*env)->CallObjectMethod(env, _this, m_java_util_concurrent_Future_get__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1) { + JNIEnv *env = go_seq_push_local_frame(3); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jlong _a0 = a0; + jobject _a1 = go_seq_from_refnum(env, a1, NULL, NULL); + jobject res = (*env)->CallObjectMethod(env, _this, m_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2, _a0, _a1); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_lang_Object_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_lang_Object_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_util_concurrent_TimeUnit_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_util_concurrent_TimeUnit_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_util_Spliterators_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_util_Spliterators_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_lang_System_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_lang_System_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_Future_get__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jobject res = (*env)->CallObjectMethod(env, _this, m_java_Future_get__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint csuper_java_Future_get__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jobject res = (*env)->CallNonvirtualObjectMethod(env, _this, sclass_java_Future, sm_java_Future_get__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1) { + JNIEnv *env = go_seq_push_local_frame(3); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jlong _a0 = a0; + jobject _a1 = go_seq_from_refnum(env, a1, NULL, NULL); + jobject res = (*env)->CallObjectMethod(env, _this, m_java_Future_get__JLjava_util_concurrent_TimeUnit_2, _a0, _a1); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint csuper_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1) { + JNIEnv *env = go_seq_push_local_frame(3); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jlong _a0 = a0; + jobject _a1 = go_seq_from_refnum(env, a1, NULL, NULL); + jobject res = (*env)->CallNonvirtualObjectMethod(env, _this, sclass_java_Future, sm_java_Future_get__JLjava_util_concurrent_TimeUnit_2, _a0, _a1); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + jint _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_InputStream_read__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jint res = (*env)->CallIntMethod(env, _this, m_java_InputStream_read__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint csuper_java_InputStream_read__(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jint res = (*env)->CallNonvirtualIntMethod(env, _this, sclass_java_InputStream, sm_java_InputStream_read__); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_InputStream_read___3B(jint this, nbyteslice a0) { + JNIEnv *env = go_seq_push_local_frame(2); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint res = (*env)->CallIntMethod(env, _this, m_java_InputStream_read___3B, _a0); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint csuper_java_InputStream_read___3B(jint this, nbyteslice a0) { + JNIEnv *env = go_seq_push_local_frame(2); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint res = (*env)->CallNonvirtualIntMethod(env, _this, sclass_java_InputStream, sm_java_InputStream_read___3B, _a0); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint cproxy_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) { + JNIEnv *env = go_seq_push_local_frame(4); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint _a1 = a1; + jint _a2 = a2; + jint res = (*env)->CallIntMethod(env, _this, m_java_InputStream_read___3BII, _a0, _a1, _a2); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_jint csuper_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) { + JNIEnv *env = go_seq_push_local_frame(4); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0); + jint _a1 = a1; + jint _a2 = a2; + jint res = (*env)->CallNonvirtualIntMethod(env, _this, sclass_java_InputStream, sm_java_InputStream_read___3BII, _a0, _a1, _a2); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = 0; + } + jint _res = res; + go_seq_pop_local_frame(env); + ret_jint __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_InputStream_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_InputStream_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring csuper_java_InputStream_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallNonvirtualObjectMethod(env, _this, sclass_java_InputStream, sm_java_InputStream_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_Object_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_Object_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring csuper_java_Object_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallNonvirtualObjectMethod(env, _this, sclass_java_Object, sm_java_Object_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +jint cproxy_java_Runnable_run(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + (*env)->CallVoidMethod(env, _this, m_java_Runnable_run); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + go_seq_pop_local_frame(env); + return _exc_ref; +} + +jint csuper_java_Runnable_run(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + (*env)->CallNonvirtualVoidMethod(env, _this, sclass_java_Runnable, sm_java_Runnable_run); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + go_seq_pop_local_frame(env); + return _exc_ref; +} + +jint cproxy_java_io_Console_flush(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + (*env)->CallVoidMethod(env, _this, m_java_io_Console_flush); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + go_seq_pop_local_frame(env); + return _exc_ref; +} + +ret_nstring cproxy_java_io_Console_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_io_Console_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java classes + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "java.h" + +jclass proxy_class_java_Future; +jmethodID proxy_class_java_Future_cons; +jclass proxy_class_java_InputStream; +jmethodID proxy_class_java_InputStream_cons; +jclass proxy_class_java_Object; +jmethodID proxy_class_java_Object_cons; +jclass proxy_class_java_Runnable; +jmethodID proxy_class_java_Runnable_cons; + +JNIEXPORT void JNICALL +Java_java_Java__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "java/Future"); + proxy_class_java_Future = (*env)->NewGlobalRef(env, clazz); + proxy_class_java_Future_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "java/Object"); + proxy_class_java_Object = (*env)->NewGlobalRef(env, clazz); + proxy_class_java_Object_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "java/Runnable"); + proxy_class_java_Runnable = (*env)->NewGlobalRef(env, clazz); + proxy_class_java_Runnable_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); +} + +JNIEXPORT jobject JNICALL +Java_java_Java_newInputStream(JNIEnv* env, jclass _clazz) { + int32_t r0 = proxyjava__NewInputStream(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_java_InputStream, proxy_class_java_InputStream_cons); + return _r0; +} + +JNIEXPORT jint JNICALL +Java_java_Future__1_1New(JNIEnv *env, jclass clazz) { + return new_java_Future(); +} + +JNIEXPORT jobject JNICALL +Java_java_Future_get__(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + struct proxyjava_Future_Get_return res = proxyjava_Future_Get(o); + jobject _r0 = go_seq_from_refnum(env, res.r0, NULL, NULL); + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT jobject JNICALL +Java_java_Future_get__JLjava_util_concurrent_TimeUnit_2(JNIEnv* env, jobject __this__, jlong p0, jobject p1) { + int32_t o = go_seq_to_refnum_go(env, __this__); + int64_t _p0 = (int64_t)p0; + int32_t _p1 = go_seq_to_refnum(env, p1); + struct proxyjava_Future_Get__return res = proxyjava_Future_Get_(o, _p0, _p1); + jobject _r0 = go_seq_from_refnum(env, res.r0, NULL, NULL); + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT void JNICALL +Java_java_Future_setFuture(JNIEnv *env, jobject this, jobject v) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t _v = go_seq_to_refnum(env, v); + proxyjava_Future_Future_Set(o, _v); +} + +JNIEXPORT jobject JNICALL +Java_java_Future_getFuture(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t r0 = proxyjava_Future_Future_Get(o); + jobject _r0 = go_seq_from_refnum(env, r0, NULL, NULL); + return _r0; +} + +JNIEXPORT jint JNICALL +Java_java_InputStream__1_1NewInputStream(JNIEnv *env, jclass clazz) { + int32_t refnum = proxyjava__NewInputStream(); + return refnum; +} + +JNIEXPORT jint JNICALL +Java_java_InputStream_read__(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + struct proxyjava_InputStream_Read_return res = proxyjava_InputStream_Read(o); + jint _r0 = (jint)res.r0; + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT void JNICALL +Java_java_InputStream_setInputStream(JNIEnv *env, jobject this, jobject v) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t _v = go_seq_to_refnum(env, v); + proxyjava_InputStream_InputStream_Set(o, _v); +} + +JNIEXPORT jobject JNICALL +Java_java_InputStream_getInputStream(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t r0 = proxyjava_InputStream_InputStream_Get(o); + jobject _r0 = go_seq_from_refnum(env, r0, NULL, NULL); + return _r0; +} + +JNIEXPORT jint JNICALL +Java_java_Object__1_1New(JNIEnv *env, jclass clazz) { + return new_java_Object(); +} + +JNIEXPORT void JNICALL +Java_java_Object_setObject(JNIEnv *env, jobject this, jobject v) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t _v = go_seq_to_refnum(env, v); + proxyjava_Object_Object_Set(o, _v); +} + +JNIEXPORT jobject JNICALL +Java_java_Object_getObject(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t r0 = proxyjava_Object_Object_Get(o); + jobject _r0 = go_seq_from_refnum(env, r0, NULL, NULL); + return _r0; +} + +JNIEXPORT jint JNICALL +Java_java_Runnable__1_1New(JNIEnv *env, jclass clazz) { + return new_java_Runnable(); +} + +JNIEXPORT void JNICALL +Java_java_Runnable_run(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + int32_t _this_ = go_seq_to_refnum(env, __this__); + proxyjava_Runnable_Run(o, _this_); +} + +JNIEXPORT void JNICALL +Java_java_Runnable_setRunnable(JNIEnv *env, jobject this, jobject v) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t _v = go_seq_to_refnum(env, v); + proxyjava_Runnable_Runnable_Set(o, _v); +} + +JNIEXPORT jobject JNICALL +Java_java_Runnable_getRunnable(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t r0 = proxyjava_Runnable_Runnable_Get(o); + jobject _r0 = go_seq_from_refnum(env, r0, NULL, NULL); + return _r0; +} + diff --git a/bind/testdata/classes.java.golden b/bind/testdata/classes.java.golden new file mode 100644 index 000000000..f4ad0a17a --- /dev/null +++ b/bind/testdata/classes.java.golden @@ -0,0 +1,155 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class java.Future is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java classes +package java; + +import go.Seq; + +public final class Future implements Seq.GoObject, java.util.concurrent.Future { + static { Java.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + Future(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public Future() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public final native java.util.concurrent.Future getFuture(); + public final native void setFuture(java.util.concurrent.Future v); + + @Override public native java.lang.Object get() throws java.lang.InterruptedException, java.util.concurrent.ExecutionException; + /** + * Use a trailing underscore to override multiple overloaded methods. + */ + @Override public native java.lang.Object get(long p0, java.util.concurrent.TimeUnit p1) throws java.lang.InterruptedException, java.util.concurrent.ExecutionException, java.util.concurrent.TimeoutException; +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class java.InputStream is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java classes +package java; + +import go.Seq; + +public final class InputStream extends java.io.InputStream implements Seq.GoObject { + static { Java.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + public InputStream() { + super(); + this.refnum = __NewInputStream(); + Seq.trackGoRef(refnum, this); + } + + private static native int __NewInputStream(); + + public final native java.io.InputStream getInputStream(); + public final native void setInputStream(java.io.InputStream v); + + @Override public native int read() throws java.io.IOException; +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class java.Object is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java classes +package java; + +import go.Seq; + +public final class Object extends java.lang.Object implements Seq.GoObject { + static { Java.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + Object(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public Object() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public final native java.lang.Object getObject(); + public final native void setObject(java.lang.Object v); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class java.Runnable is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java classes +package java; + +import go.Seq; + +public final class Runnable implements Seq.GoObject, java.lang.Runnable { + static { Java.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + Runnable(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public Runnable() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public final native java.lang.Runnable getRunnable(); + public final native void setRunnable(java.lang.Runnable v); + + @Override public native void run(); +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class java.Java is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java classes +package java; + +import go.Seq; + +public abstract class Java { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Java() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + + + public static native InputStream newInputStream(); +} diff --git a/bind/testdata/classes.java.h.golden b/bind/testdata/classes.java.h.golden new file mode 100644 index 000000000..5368d26fa --- /dev/null +++ b/bind/testdata/classes.java.h.golden @@ -0,0 +1,103 @@ +// Code generated by gobind. DO NOT EDIT. + + +#include +#include "seq.h" + +extern void init_proxies(); + +typedef struct ret_jint { + jint res; + jint exc; +} ret_jint; +typedef struct ret_jboolean { + jboolean res; + jint exc; +} ret_jboolean; +typedef struct ret_jshort { + jshort res; + jint exc; +} ret_jshort; +typedef struct ret_jchar { + jchar res; + jint exc; +} ret_jchar; +typedef struct ret_jbyte { + jbyte res; + jint exc; +} ret_jbyte; +typedef struct ret_jlong { + jlong res; + jint exc; +} ret_jlong; +typedef struct ret_jfloat { + jfloat res; + jint exc; +} ret_jfloat; +typedef struct ret_jdouble { + jdouble res; + jint exc; +} ret_jdouble; +typedef struct ret_nstring { + nstring res; + jint exc; +} ret_nstring; +typedef struct ret_nbyteslice { + nbyteslice res; + jint exc; +} ret_nbyteslice; + +extern jint cproxy_java_lang_Runnable_run(jint this); +extern ret_jint cproxy_java_io_InputStream_read__(jint this); +extern ret_jint cproxy_java_io_InputStream_read___3B(jint this, nbyteslice a0); +extern ret_jint cproxy_java_io_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2); +extern ret_nstring cproxy_java_io_InputStream_toString(jint this); +extern ret_jint cproxy_java_util_concurrent_Future_get__(jint this); +extern ret_jint cproxy_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1); +extern ret_nstring cproxy_java_lang_Object_toString(jint this); +extern ret_nstring cproxy_java_util_concurrent_TimeUnit_toString(jint this); +extern ret_nstring cproxy_java_util_Spliterators_toString(jint this); +extern ret_nstring cproxy_java_lang_System_toString(jint this); +extern ret_jint cproxy_java_Future_get__(jint this); +extern ret_jint csuper_java_Future_get__(jint this); +extern ret_jint cproxy_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1); +extern ret_jint csuper_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1); +extern ret_jint cproxy_java_InputStream_read__(jint this); +extern ret_jint csuper_java_InputStream_read__(jint this); +extern ret_jint cproxy_java_InputStream_read___3B(jint this, nbyteslice a0); +extern ret_jint csuper_java_InputStream_read___3B(jint this, nbyteslice a0); +extern ret_jint cproxy_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2); +extern ret_jint csuper_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2); +extern ret_nstring cproxy_java_InputStream_toString(jint this); +extern ret_nstring csuper_java_InputStream_toString(jint this); +extern ret_nstring cproxy_java_Object_toString(jint this); +extern ret_nstring csuper_java_Object_toString(jint this); +extern jint cproxy_java_Runnable_run(jint this); +extern jint csuper_java_Runnable_run(jint this); +extern jint cproxy_java_io_Console_flush(jint this); +extern ret_nstring cproxy_java_io_Console_toString(jint this); +extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2(jint a0); +extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(jint a0); +extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2(jint a0); +extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2(jint a0); +extern ret_jint cproxy_s_java_lang_System_console(); +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java classes + +#ifndef __Java_H__ +#define __Java_H__ + +#include + +extern jclass proxy_class_java_Future; +extern jmethodID proxy_class_java_Future_cons; +extern jclass proxy_class_java_InputStream; +extern jmethodID proxy_class_java_InputStream_cons; +extern jclass proxy_class_java_Object; +extern jmethodID proxy_class_java_Object_cons; +extern jclass proxy_class_java_Runnable; +extern jmethodID proxy_class_java_Runnable_cons; +#endif diff --git a/bind/testdata/customprefix.go b/bind/testdata/customprefix.go new file mode 100644 index 000000000..b3a0967bb --- /dev/null +++ b/bind/testdata/customprefix.go @@ -0,0 +1,10 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Data for -pkgpath and -prefix options. + +package customprefix + +func F() { +} diff --git a/bind/testdata/customprefix.java.c.golden b/bind/testdata/customprefix.java.c.golden new file mode 100644 index 000000000..4c9e4712c --- /dev/null +++ b/bind/testdata/customprefix.java.c.golden @@ -0,0 +1,23 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java -javapkg=com.example customprefix + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "customprefix.h" + + +JNIEXPORT void JNICALL +Java_com_example_customprefix_Customprefix__1init(JNIEnv *env, jclass _unused) { + jclass clazz; +} + +JNIEXPORT void JNICALL +Java_com_example_customprefix_Customprefix_f(JNIEnv* env, jclass _clazz) { + proxycustomprefix__F(); +} + diff --git a/bind/testdata/customprefix.java.golden b/bind/testdata/customprefix.java.golden new file mode 100644 index 000000000..3073bf108 --- /dev/null +++ b/bind/testdata/customprefix.java.golden @@ -0,0 +1,26 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class com.example.customprefix.Customprefix is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java -javapkg=com.example customprefix +package com.example.customprefix; + +import go.Seq; + +public abstract class Customprefix { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Customprefix() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + + + public static native void f(); +} diff --git a/bind/testdata/customprefix.java.h.golden b/bind/testdata/customprefix.java.h.golden new file mode 100644 index 000000000..12a6f5a7e --- /dev/null +++ b/bind/testdata/customprefix.java.h.golden @@ -0,0 +1,12 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java -javapkg=com.example customprefix + +#ifndef __Customprefix_H__ +#define __Customprefix_H__ + +#include + +#endif diff --git a/bind/testdata/customprefix.objc.go.h.golden b/bind/testdata/customprefix.objc.go.h.golden new file mode 100644 index 000000000..8e5e9be47 --- /dev/null +++ b/bind/testdata/customprefix.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to customprefix Go package. +// gobind -lang=objc customprefix +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_customprefix_H__ +#define __GO_customprefix_H__ + +#include +#include +#endif diff --git a/bind/testdata/customprefix.objc.h.golden b/bind/testdata/customprefix.objc.h.golden new file mode 100644 index 000000000..ec805b254 --- /dev/null +++ b/bind/testdata/customprefix.objc.h.golden @@ -0,0 +1,16 @@ +// Objective-C API for talking to customprefix Go package. +// gobind -lang=objc customprefix +// +// File is generated by gobind. Do not edit. + +#ifndef __Customprefix_H__ +#define __Customprefix_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +FOUNDATION_EXPORT void CustomprefixF(void); + +#endif diff --git a/bind/testdata/customprefix.objc.m.golden b/bind/testdata/customprefix.objc.m.golden new file mode 100644 index 000000000..f7b6433a8 --- /dev/null +++ b/bind/testdata/customprefix.objc.m.golden @@ -0,0 +1,18 @@ +// Objective-C API for talking to customprefix Go package. +// gobind -lang=objc customprefix +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Customprefix.objc.h" + + +void CustomprefixF(void) { + proxycustomprefix__F(); +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/customprefixEX.objc.go.h.golden b/bind/testdata/customprefixEX.objc.go.h.golden new file mode 100644 index 000000000..334a29a44 --- /dev/null +++ b/bind/testdata/customprefixEX.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to customprefix Go package. +// gobind -lang=objc -prefix="EX" customprefix +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_customprefix_H__ +#define __GO_customprefix_H__ + +#include +#include +#endif diff --git a/bind/testdata/customprefixEX.objc.h.golden b/bind/testdata/customprefixEX.objc.h.golden new file mode 100644 index 000000000..058f9efbb --- /dev/null +++ b/bind/testdata/customprefixEX.objc.h.golden @@ -0,0 +1,16 @@ +// Objective-C API for talking to customprefix Go package. +// gobind -lang=objc -prefix="EX" customprefix +// +// File is generated by gobind. Do not edit. + +#ifndef __EXCustomprefix_H__ +#define __EXCustomprefix_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +FOUNDATION_EXPORT void EXCustomprefixF(void); + +#endif diff --git a/bind/testdata/customprefixEX.objc.m.golden b/bind/testdata/customprefixEX.objc.m.golden new file mode 100644 index 000000000..db708cc70 --- /dev/null +++ b/bind/testdata/customprefixEX.objc.m.golden @@ -0,0 +1,18 @@ +// Objective-C API for talking to customprefix Go package. +// gobind -lang=objc -prefix="EX" customprefix +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "EXCustomprefix.objc.h" + + +void EXCustomprefixF(void) { + proxycustomprefix__F(); +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/doc.go b/bind/testdata/doc.go new file mode 100644 index 000000000..c17da8295 --- /dev/null +++ b/bind/testdata/doc.go @@ -0,0 +1,59 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package doc tests that Go documentation is transferred +// to the generated code. +package doc + +// F is a function. +func F() {} + +// C is a constant. +const C = true + +// V is a var. +var V string + +// A group of vars. +var ( + // A specific var. + Specific string + NoDocVar float64 +) + +// Before is a method. +func (_ *S) Before() {} + +// S is a struct. +type S struct { + // SF is a field. + SF string + // blank (unexported) field. + _ string + // Anonymous field. + *S2 + // Multiple fields. + F1, F2 string +} + +// After is another method. +func (_ *S) After() {} + +// A generic comment with . +type ( + // S2 is a struct. + S2 struct{} + NoDoc struct{} +) + +// NewS is a constructor. +func NewS() *S { + return nil +} + +// I is an interface. +type I interface { + // IM is a method. + IM() +} diff --git a/bind/testdata/doc.go.golden b/bind/testdata/doc.go.golden new file mode 100644 index 000000000..bdcbe288f --- /dev/null +++ b/bind/testdata/doc.go.golden @@ -0,0 +1,190 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package doc. +// +// autogenerated by gobind -lang=go doc +package main + +/* +#include +#include +#include "seq.h" +#include "doc.h" + +*/ +import "C" + +import ( + "doc" + _seq "golang.org/x/mobile/bind/seq" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export new_doc_NoDoc +func new_doc_NoDoc() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(doc.NoDoc))) +} + +//export proxydoc_S_SF_Set +func proxydoc_S_SF_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v := decodeString(v) + ref.Get().(*doc.S).SF = _v +} + +//export proxydoc_S_SF_Get +func proxydoc_S_SF_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*doc.S).SF + _v := encodeString(v) + return _v +} + +//export proxydoc_S_S2_Set +func proxydoc_S_S2_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + // Must be a Go object + var _v *doc.S2 + if _v_ref := _seq.FromRefNum(int32(v)); _v_ref != nil { + _v = _v_ref.Get().(*doc.S2) + } + ref.Get().(*doc.S).S2 = _v +} + +//export proxydoc_S_S2_Get +func proxydoc_S_S2_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*doc.S).S2 + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxydoc_S_F1_Set +func proxydoc_S_F1_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v := decodeString(v) + ref.Get().(*doc.S).F1 = _v +} + +//export proxydoc_S_F1_Get +func proxydoc_S_F1_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*doc.S).F1 + _v := encodeString(v) + return _v +} + +//export proxydoc_S_F2_Set +func proxydoc_S_F2_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v := decodeString(v) + ref.Get().(*doc.S).F2 = _v +} + +//export proxydoc_S_F2_Get +func proxydoc_S_F2_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*doc.S).F2 + _v := encodeString(v) + return _v +} + +//export proxydoc_S_After +func proxydoc_S_After(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*doc.S) + v.After() +} + +//export proxydoc_S_Before +func proxydoc_S_Before(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*doc.S) + v.Before() +} + +//export new_doc_S +func new_doc_S() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(doc.S))) +} + +//export new_doc_S2 +func new_doc_S2() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(doc.S2))) +} + +//export proxydoc_I_IM +func proxydoc_I_IM(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(doc.I) + v.IM() +} + +type proxydoc_I _seq.Ref + +func (p *proxydoc_I) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxydoc_I) IM() { + C.cproxydoc_I_IM(C.int32_t(p.Bind_proxy_refnum__())) +} + +//export var_setdoc_NoDocVar +func var_setdoc_NoDocVar(v C.double) { + _v := float64(v) + doc.NoDocVar = _v +} + +//export var_getdoc_NoDocVar +func var_getdoc_NoDocVar() C.double { + v := doc.NoDocVar + _v := C.double(v) + return _v +} + +//export var_setdoc_Specific +func var_setdoc_Specific(v C.nstring) { + _v := decodeString(v) + doc.Specific = _v +} + +//export var_getdoc_Specific +func var_getdoc_Specific() C.nstring { + v := doc.Specific + _v := encodeString(v) + return _v +} + +//export var_setdoc_V +func var_setdoc_V(v C.nstring) { + _v := decodeString(v) + doc.V = _v +} + +//export var_getdoc_V +func var_getdoc_V() C.nstring { + v := doc.V + _v := encodeString(v) + return _v +} + +//export proxydoc__F +func proxydoc__F() { + doc.F() +} + +//export proxydoc__NewS +func proxydoc__NewS() C.int32_t { + res_0 := doc.NewS() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} diff --git a/bind/testdata/doc.java.c.golden b/bind/testdata/doc.java.c.golden new file mode 100644 index 000000000..fe365be58 --- /dev/null +++ b/bind/testdata/doc.java.c.golden @@ -0,0 +1,194 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java doc + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "doc.h" + +jclass proxy_class_doc_I; +jmethodID proxy_class_doc_I_cons; +static jmethodID mid_I_IM; +jclass proxy_class_doc_NoDoc; +jmethodID proxy_class_doc_NoDoc_cons; +jclass proxy_class_doc_S; +jmethodID proxy_class_doc_S_cons; +jclass proxy_class_doc_S2; +jmethodID proxy_class_doc_S2_cons; + +JNIEXPORT void JNICALL +Java_doc_Doc__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "doc/NoDoc"); + proxy_class_doc_NoDoc = (*env)->NewGlobalRef(env, clazz); + proxy_class_doc_NoDoc_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "doc/S"); + proxy_class_doc_S = (*env)->NewGlobalRef(env, clazz); + proxy_class_doc_S_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "doc/S2"); + proxy_class_doc_S2 = (*env)->NewGlobalRef(env, clazz); + proxy_class_doc_S2_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "doc/Doc$proxyI"); + proxy_class_doc_I = (*env)->NewGlobalRef(env, clazz); + proxy_class_doc_I_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "doc/I"); + mid_I_IM = (*env)->GetMethodID(env, clazz, "im", "()V"); + +} + +JNIEXPORT void JNICALL +Java_doc_Doc_f(JNIEnv* env, jclass _clazz) { + proxydoc__F(); +} + +JNIEXPORT jobject JNICALL +Java_doc_Doc_newS(JNIEnv* env, jclass _clazz) { + int32_t r0 = proxydoc__NewS(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_doc_S, proxy_class_doc_S_cons); + return _r0; +} + +JNIEXPORT jint JNICALL +Java_doc_NoDoc__1_1New(JNIEnv *env, jclass clazz) { + return new_doc_NoDoc(); +} + +JNIEXPORT jint JNICALL +Java_doc_S__1_1NewS(JNIEnv *env, jclass clazz) { + int32_t refnum = proxydoc__NewS(); + return refnum; +} + +JNIEXPORT void JNICALL +Java_doc_S_after(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxydoc_S_After(o); +} + +JNIEXPORT void JNICALL +Java_doc_S_before(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxydoc_S_Before(o); +} + +JNIEXPORT void JNICALL +Java_doc_S_setSF(JNIEnv *env, jobject this, jstring v) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring _v = go_seq_from_java_string(env, v); + proxydoc_S_SF_Set(o, _v); +} + +JNIEXPORT jstring JNICALL +Java_doc_S_getSF(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring r0 = proxydoc_S_SF_Get(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT void JNICALL +Java_doc_S_setS2(JNIEnv *env, jobject this, jobject v) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t _v = go_seq_to_refnum(env, v); + proxydoc_S_S2_Set(o, _v); +} + +JNIEXPORT jobject JNICALL +Java_doc_S_getS2(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t r0 = proxydoc_S_S2_Get(o); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_doc_S2, proxy_class_doc_S2_cons); + return _r0; +} + +JNIEXPORT void JNICALL +Java_doc_S_setF1(JNIEnv *env, jobject this, jstring v) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring _v = go_seq_from_java_string(env, v); + proxydoc_S_F1_Set(o, _v); +} + +JNIEXPORT jstring JNICALL +Java_doc_S_getF1(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring r0 = proxydoc_S_F1_Get(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT void JNICALL +Java_doc_S_setF2(JNIEnv *env, jobject this, jstring v) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring _v = go_seq_from_java_string(env, v); + proxydoc_S_F2_Set(o, _v); +} + +JNIEXPORT jstring JNICALL +Java_doc_S_getF2(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring r0 = proxydoc_S_F2_Get(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT jint JNICALL +Java_doc_S2__1_1New(JNIEnv *env, jclass clazz) { + return new_doc_S2(); +} + +JNIEXPORT void JNICALL +Java_doc_Doc_00024proxyI_im(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxydoc_I_IM(o); +} + +void cproxydoc_I_IM(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_doc_I, proxy_class_doc_I_cons); + (*env)->CallVoidMethod(env, o, mid_I_IM); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_doc_Doc_setNoDocVar(JNIEnv *env, jclass clazz, jdouble v) { + double _v = (double)v; + var_setdoc_NoDocVar(_v); +} + +JNIEXPORT jdouble JNICALL +Java_doc_Doc_getNoDocVar(JNIEnv *env, jclass clazz) { + double r0 = var_getdoc_NoDocVar(); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_doc_Doc_setSpecific(JNIEnv *env, jclass clazz, jstring v) { + nstring _v = go_seq_from_java_string(env, v); + var_setdoc_Specific(_v); +} + +JNIEXPORT jstring JNICALL +Java_doc_Doc_getSpecific(JNIEnv *env, jclass clazz) { + nstring r0 = var_getdoc_Specific(); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT void JNICALL +Java_doc_Doc_setV(JNIEnv *env, jclass clazz, jstring v) { + nstring _v = go_seq_from_java_string(env, v); + var_setdoc_V(_v); +} + +JNIEXPORT jstring JNICALL +Java_doc_Doc_getV(JNIEnv *env, jclass clazz) { + nstring r0 = var_getdoc_V(); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + diff --git a/bind/testdata/doc.java.golden b/bind/testdata/doc.java.golden new file mode 100644 index 000000000..9819a2b57 --- /dev/null +++ b/bind/testdata/doc.java.golden @@ -0,0 +1,324 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class doc.NoDoc is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java doc +package doc; + +import go.Seq; + +/** + * A generic comment with <HTML>. + */ +public final class NoDoc implements Seq.Proxy { + static { Doc.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + NoDoc(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public NoDoc() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof NoDoc)) { + return false; + } + NoDoc that = (NoDoc)o; + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("NoDoc").append("{"); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class doc.S is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java doc +package doc; + +import go.Seq; + +/** + * S is a struct. + */ +public final class S implements Seq.Proxy { + static { Doc.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + /** + * NewS is a constructor. + */ + public S() { + this.refnum = __NewS(); + Seq.trackGoRef(refnum, this); + } + + private static native int __NewS(); + + S(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + /** + * SF is a field. + */ + public final native String getSF(); + /** + * SF is a field. + */ + public final native void setSF(String v); + + /** + * Anonymous field. + */ + public final native S2 getS2(); + /** + * Anonymous field. + */ + public final native void setS2(S2 v); + + /** + * Multiple fields. + */ + public final native String getF1(); + /** + * Multiple fields. + */ + public final native void setF1(String v); + + /** + * Multiple fields. + */ + public final native String getF2(); + /** + * Multiple fields. + */ + public final native void setF2(String v); + + /** + * After is another method. + */ + public native void after(); + public native void before(); + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof S)) { + return false; + } + S that = (S)o; + String thisSF = getSF(); + String thatSF = that.getSF(); + if (thisSF == null) { + if (thatSF != null) { + return false; + } + } else if (!thisSF.equals(thatSF)) { + return false; + } + S2 thisS2 = getS2(); + S2 thatS2 = that.getS2(); + if (thisS2 == null) { + if (thatS2 != null) { + return false; + } + } else if (!thisS2.equals(thatS2)) { + return false; + } + String thisF1 = getF1(); + String thatF1 = that.getF1(); + if (thisF1 == null) { + if (thatF1 != null) { + return false; + } + } else if (!thisF1.equals(thatF1)) { + return false; + } + String thisF2 = getF2(); + String thatF2 = that.getF2(); + if (thisF2 == null) { + if (thatF2 != null) { + return false; + } + } else if (!thisF2.equals(thatF2)) { + return false; + } + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {getSF(), getS2(), getF1(), getF2()}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("S").append("{"); + b.append("SF:").append(getSF()).append(","); + b.append("S2:").append(getS2()).append(","); + b.append("F1:").append(getF1()).append(","); + b.append("F2:").append(getF2()).append(","); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class doc.S2 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java doc +package doc; + +import go.Seq; + +/** + * S2 is a struct. + */ +public final class S2 implements Seq.Proxy { + static { Doc.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + S2(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public S2() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof S2)) { + return false; + } + S2 that = (S2)o; + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("S2").append("{"); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class doc.I is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java doc +package doc; + +import go.Seq; + +/** + * I is an interface. + */ +public interface I { + /** + * IM is a method. + */ + public void im(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class doc.Doc is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java doc +package doc; + +import go.Seq; + +public abstract class Doc { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Doc() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyI implements Seq.Proxy, I { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyI(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void im(); + } + + /** + * C is a constant. + */ + public static final boolean C = true; + + /** + * A group of vars. + */ + public static native void setNoDocVar(double v); + /** + * A group of vars. + */ + public static native double getNoDocVar(); + + /** + * A specific var. + */ + public static native void setSpecific(String v); + /** + * A specific var. + */ + public static native String getSpecific(); + + /** + * V is a var. + */ + public static native void setV(String v); + /** + * V is a var. + */ + public static native String getV(); + + /** + * F is a function. + */ + public static native void f(); + /** + * NewS is a constructor. + */ + public static native S newS(); +} diff --git a/bind/testdata/doc.java.h.golden b/bind/testdata/doc.java.h.golden new file mode 100644 index 000000000..e4eff379d --- /dev/null +++ b/bind/testdata/doc.java.h.golden @@ -0,0 +1,23 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java doc + +#ifndef __Doc_H__ +#define __Doc_H__ + +#include + +extern jclass proxy_class_doc_I; +extern jmethodID proxy_class_doc_I_cons; + +void cproxydoc_I_IM(int32_t refnum); + +extern jclass proxy_class_doc_NoDoc; +extern jmethodID proxy_class_doc_NoDoc_cons; +extern jclass proxy_class_doc_S; +extern jmethodID proxy_class_doc_S_cons; +extern jclass proxy_class_doc_S2; +extern jmethodID proxy_class_doc_S2_cons; +#endif diff --git a/bind/testdata/doc.objc.go.h.golden b/bind/testdata/doc.objc.go.h.golden new file mode 100644 index 000000000..803e31ad5 --- /dev/null +++ b/bind/testdata/doc.objc.go.h.golden @@ -0,0 +1,13 @@ +// Objective-C API for talking to doc Go package. +// gobind -lang=objc doc +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_doc_H__ +#define __GO_doc_H__ + +#include +#include +void cproxydoc_I_IM(int32_t refnum); + +#endif diff --git a/bind/testdata/doc.objc.h.golden b/bind/testdata/doc.objc.h.golden new file mode 100644 index 000000000..f0ea479a3 --- /dev/null +++ b/bind/testdata/doc.objc.h.golden @@ -0,0 +1,136 @@ +// Objective-C API for talking to doc Go package. +// gobind -lang=objc doc +// +// File is generated by gobind. Do not edit. + +#ifndef __Doc_H__ +#define __Doc_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class DocNoDoc; +@class DocS; +@class DocS2; +@protocol DocI; +@class DocI; + +@protocol DocI +/** + * IM is a method. + */ +- (void)im; +@end + +/** + * A generic comment with . + */ +@interface DocNoDoc : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +@end + +/** + * S is a struct. + */ +@interface DocS : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +/** + * NewS is a constructor. + */ +- (nullable instancetype)init; +/** + * SF is a field. + */ +@property (nonatomic) NSString* _Nonnull sf; +/** + * Anonymous field. + */ +@property (nonatomic) DocS2* _Nullable s2; +/** + * Multiple fields. + */ +@property (nonatomic) NSString* _Nonnull f1; +/** + * Multiple fields. + */ +@property (nonatomic) NSString* _Nonnull f2; +/** + * After is another method. + */ +- (void)after; +- (void)before; +@end + +/** + * S2 is a struct. + */ +@interface DocS2 : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +@end + +/** + * C is a constant. + */ +FOUNDATION_EXPORT const BOOL DocC; + +@interface Doc : NSObject +/** + * A group of vars. + */ ++ (double) noDocVar; ++ (void) setNoDocVar:(double)v; + +/** + * A specific var. + */ ++ (NSString* _Nonnull) specific; ++ (void) setSpecific:(NSString* _Nonnull)v; + +/** + * V is a var. + */ ++ (NSString* _Nonnull) v; ++ (void) setV:(NSString* _Nonnull)v; + +@end + +/** + * F is a function. + */ +FOUNDATION_EXPORT void DocF(void); + +/** + * NewS is a constructor. + */ +FOUNDATION_EXPORT DocS* _Nullable DocNewS(void); + +@class DocI; + +/** + * I is an interface. + */ +@interface DocI : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +/** + * IM is a method. + */ +- (void)im; +@end + +#endif diff --git a/bind/testdata/doc.objc.m.golden b/bind/testdata/doc.objc.m.golden new file mode 100644 index 000000000..cb8c7c8d3 --- /dev/null +++ b/bind/testdata/doc.objc.m.golden @@ -0,0 +1,231 @@ +// Objective-C API for talking to doc Go package. +// gobind -lang=objc doc +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Doc.objc.h" + + +@implementation DocNoDoc { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_doc_NoDoc()); + } + return self; +} + +@end + + + +@implementation DocS { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + int32_t refnum = proxydoc__NewS(); + __ref = go_seq_from_refnum(refnum); + return self; +} + +- (NSString* _Nonnull)sf { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxydoc_S_SF_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + +- (void)setSF:(NSString* _Nonnull)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxydoc_S_SF_Set(refnum, _v); +} + +- (DocS2* _Nullable)s2 { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxydoc_S_S2_Get(refnum); + DocS2* _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[DocS2 alloc] initWithRef:_r0_ref]; + } + } + return _r0; +} + +- (void)setS2:(DocS2* _Nullable)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t _v; + if ([v conformsToProtocol:@protocol(goSeqRefInterface)]) { + id v_proxy = (id)(v); + _v = go_seq_go_to_refnum(v_proxy._ref); + } else { + _v = go_seq_to_refnum(v); + } + proxydoc_S_S2_Set(refnum, _v); +} + +- (NSString* _Nonnull)f1 { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxydoc_S_F1_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + +- (void)setF1:(NSString* _Nonnull)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxydoc_S_F1_Set(refnum, _v); +} + +- (NSString* _Nonnull)f2 { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxydoc_S_F2_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + +- (void)setF2:(NSString* _Nonnull)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxydoc_S_F2_Set(refnum, _v); +} + +- (void)after { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxydoc_S_After(refnum); +} + +- (void)before { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxydoc_S_Before(refnum); +} + +@end + + + +@implementation DocS2 { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_doc_S2()); + } + return self; +} + +@end + + +@implementation DocI { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)im { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxydoc_I_IM(refnum); +} + +@end + + +const BOOL DocC = YES; + +@implementation Doc ++ (void) setNoDocVar:(double)v { + double _v = (double)v; + var_setdoc_NoDocVar(_v); +} + ++ (double) noDocVar { + double r0 = var_getdoc_NoDocVar(); + double _r0 = (double)r0; + return _r0; +} + ++ (void) setSpecific:(NSString* _Nonnull)v { + nstring _v = go_seq_from_objc_string(v); + var_setdoc_Specific(_v); +} + ++ (NSString* _Nonnull) specific { + nstring r0 = var_getdoc_Specific(); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + ++ (void) setV:(NSString* _Nonnull)v { + nstring _v = go_seq_from_objc_string(v); + var_setdoc_V(_v); +} + ++ (NSString* _Nonnull) v { + nstring r0 = var_getdoc_V(); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + +@end + + +void DocF(void) { + proxydoc__F(); +} + +DocS* _Nullable DocNewS(void) { + int32_t r0 = proxydoc__NewS(); + DocS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[DocS alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +void cproxydoc_I_IM(int32_t refnum) { + @autoreleasepool { + DocI* o = go_seq_objc_from_refnum(refnum); + [o im]; + } +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/ignore.go b/bind/testdata/ignore.go new file mode 100644 index 000000000..2d3e1a686 --- /dev/null +++ b/bind/testdata/ignore.go @@ -0,0 +1,59 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package ignore tests that exported, but otherwise +// unsupported functions, variables, fields and methods +// are ignored by the generators +package ignore + +var Var interface{} + +type ( + NamedString string +) + +const NamedConst NamedString = "foo" + +var V interface{} + +func Argument(_ interface{}) { +} + +func Result() interface{} { + return nil +} + +type S struct { + F interface{} +} + +type ( + F func() +) + +func (_ *S) Argument(_ interface{}) { +} + +func (_ *S) Result() interface{} { + return nil +} + +type I interface { + Argument(_ interface{}) + Result() interface{} +} + +var ( + Uint uint + Uint32 uint32 + Uint64 uint64 + C64 complex64 = 0 + C128 complex128 = 0 +) + +const ( + Cuint uint = 0 + Cuint32 uint32 = 0 + Cuint64 uint64 = 0 +) diff --git a/bind/testdata/ignore.go.golden b/bind/testdata/ignore.go.golden new file mode 100644 index 000000000..486db372c --- /dev/null +++ b/bind/testdata/ignore.go.golden @@ -0,0 +1,63 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package ignore. +// +// autogenerated by gobind -lang=go ignore +package main + +/* +#include +#include +#include "seq.h" +#include "ignore.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "ignore" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +// skipped field S.F with unsupported type: interface{} + +// skipped method S.Argument with unsupported parameter or return types + +// skipped method S.Result with unsupported parameter or return types + +//export new_ignore_S +func new_ignore_S() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(ignore.S))) +} + +// skipped method I.Argument with unsupported parameter or return types + +// skipped method I.Result with unsupported parameter or return types + +type proxyignore_I _seq.Ref + +func (p *proxyignore_I) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +// skipped method I.Argument with unsupported parameter or result types +// skipped method I.Result with unsupported parameter or result types +// skipped variable C128 with unsupported type complex128 + +// skipped variable C64 with unsupported type complex64 + +// skipped variable Uint with unsupported type uint + +// skipped variable Uint32 with unsupported type uint32 + +// skipped variable Uint64 with unsupported type uint64 + +// skipped variable V with unsupported type interface{} + +// skipped variable Var with unsupported type interface{} + +// skipped function Argument with unsupported parameter or result types +// skipped function Result with unsupported parameter or result types diff --git a/bind/testdata/ignore.java.c.golden b/bind/testdata/ignore.java.c.golden new file mode 100644 index 000000000..d5110417c --- /dev/null +++ b/bind/testdata/ignore.java.c.golden @@ -0,0 +1,75 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java ignore + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "ignore.h" + +jclass proxy_class_ignore_I; +jmethodID proxy_class_ignore_I_cons; +// skipped method I.Argument with unsupported parameter or return types + +// skipped method I.Result with unsupported parameter or return types + +jclass proxy_class_ignore_S; +jmethodID proxy_class_ignore_S_cons; + +JNIEXPORT void JNICALL +Java_ignore_Ignore__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "ignore/S"); + proxy_class_ignore_S = (*env)->NewGlobalRef(env, clazz); + proxy_class_ignore_S_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "ignore/Ignore$proxyI"); + proxy_class_ignore_I = (*env)->NewGlobalRef(env, clazz); + proxy_class_ignore_I_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "ignore/I"); + // skipped method I.Argument with unsupported parameter or return types + + // skipped method I.Result with unsupported parameter or return types + + +} + +// skipped function Argument with unsupported parameter or return types + +// skipped function Result with unsupported parameter or return types + +JNIEXPORT jint JNICALL +Java_ignore_S__1_1New(JNIEnv *env, jclass clazz) { + return new_ignore_S(); +} + +// skipped function S.Argument with unsupported parameter or return types + +// skipped function S.Result with unsupported parameter or return types + +// skipped field S with unsupported type: interface{} + +// skipped function I.Argument with unsupported parameter or return types + +// skipped method I with unsupported parameter or return types + +// skipped function I.Result with unsupported parameter or return types + +// skipped method I with unsupported parameter or return types + +// skipped variable C128 with unsupported type: complex128 + +// skipped variable C64 with unsupported type: complex64 + +// skipped variable Uint with unsupported type: uint + +// skipped variable Uint32 with unsupported type: uint32 + +// skipped variable Uint64 with unsupported type: uint64 + +// skipped variable V with unsupported type: interface{} + +// skipped variable Var with unsupported type: interface{} + diff --git a/bind/testdata/ignore.java.golden b/bind/testdata/ignore.java.golden new file mode 100644 index 000000000..21894d9f9 --- /dev/null +++ b/bind/testdata/ignore.java.golden @@ -0,0 +1,135 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class ignore.S is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java ignore +package ignore; + +import go.Seq; + +public final class S implements Seq.Proxy, I { + static { Ignore.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + S(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public S() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + // skipped field S.F with unsupported type: interface{} + + // skipped method S.Argument with unsupported parameter or return types + + // skipped method S.Result with unsupported parameter or return types + + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof S)) { + return false; + } + S that = (S)o; + // skipped field S.F with unsupported type: interface{} + + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("S").append("{"); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class ignore.I is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java ignore +package ignore; + +import go.Seq; + +public interface I { + // skipped method I.Argument with unsupported parameter or return types + + // skipped method I.Result with unsupported parameter or return types + + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class ignore.Ignore is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java ignore +package ignore; + +import go.Seq; + +public abstract class Ignore { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Ignore() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyI implements Seq.Proxy, I { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyI(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + // skipped method I.Argument with unsupported parameter or return types + + // skipped method I.Result with unsupported parameter or return types + + } + + // skipped const Cuint with unsupported type: uint + + // skipped const Cuint32 with unsupported type: uint32 + + // skipped const Cuint64 with unsupported type: uint64 + + // skipped const NamedConst with unsupported type: ignore.NamedString + + + // skipped variable C128 with unsupported type: complex128 + + // skipped variable C64 with unsupported type: complex64 + + // skipped variable Uint with unsupported type: uint + + // skipped variable Uint32 with unsupported type: uint32 + + // skipped variable Uint64 with unsupported type: uint64 + + // skipped variable V with unsupported type: interface{} + + // skipped variable Var with unsupported type: interface{} + + // skipped function Argument with unsupported parameter or return types + + // skipped function Result with unsupported parameter or return types + +} diff --git a/bind/testdata/ignore.java.h.golden b/bind/testdata/ignore.java.h.golden new file mode 100644 index 000000000..857dc1901 --- /dev/null +++ b/bind/testdata/ignore.java.h.golden @@ -0,0 +1,21 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java ignore + +#ifndef __Ignore_H__ +#define __Ignore_H__ + +#include + +extern jclass proxy_class_ignore_I; +extern jmethodID proxy_class_ignore_I_cons; + +// skipped method I.Argument with unsupported parameter or return types + +// skipped method I.Result with unsupported parameter or return types + +extern jclass proxy_class_ignore_S; +extern jmethodID proxy_class_ignore_S_cons; +#endif diff --git a/bind/testdata/ignore.objc.go.h.golden b/bind/testdata/ignore.objc.go.h.golden new file mode 100644 index 000000000..7924f01c7 --- /dev/null +++ b/bind/testdata/ignore.objc.go.h.golden @@ -0,0 +1,15 @@ +// Objective-C API for talking to ignore Go package. +// gobind -lang=objc ignore +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_ignore_H__ +#define __GO_ignore_H__ + +#include +#include +// skipped method I.Argument with unsupported parameter or return types + +// skipped method I.Result with unsupported parameter or return types + +#endif diff --git a/bind/testdata/ignore.objc.h.golden b/bind/testdata/ignore.objc.h.golden new file mode 100644 index 000000000..bcb03df45 --- /dev/null +++ b/bind/testdata/ignore.objc.h.golden @@ -0,0 +1,84 @@ +// Objective-C API for talking to ignore Go package. +// gobind -lang=objc ignore +// +// File is generated by gobind. Do not edit. + +#ifndef __Ignore_H__ +#define __Ignore_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class IgnoreS; +@protocol IgnoreI; +@class IgnoreI; + +@protocol IgnoreI +// skipped method I.Argument with unsupported parameter or return types + +// skipped method I.Result with unsupported parameter or return types + +@end + +@interface IgnoreS : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +// skipped field S.F with unsupported type: interface{} + +// skipped method S.Argument with unsupported parameter or return types + +// skipped method S.Result with unsupported parameter or return types + +@end + +// skipped const Cuint with unsupported type: uint + +// skipped const Cuint32 with unsupported type: uint32 + +// skipped const Cuint64 with unsupported type: uint64 + +// skipped const NamedConst with unsupported type: ignore.NamedString + + +@interface Ignore : NSObject +// skipped variable C128 with unsupported type: complex128 + +// skipped variable C64 with unsupported type: complex64 + +// skipped variable Uint with unsupported type: uint + +// skipped variable Uint32 with unsupported type: uint32 + +// skipped variable Uint64 with unsupported type: uint64 + +// skipped variable V with unsupported type: interface{} + +// skipped variable Var with unsupported type: interface{} + +@end + +// skipped function Argument with unsupported parameter or return types + + +// skipped function Result with unsupported parameter or return types + + +@class IgnoreI; + +@interface IgnoreI : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +// skipped method I.Argument with unsupported parameter or return types + +// skipped method I.Result with unsupported parameter or return types + +@end + +#endif diff --git a/bind/testdata/ignore.objc.m.golden b/bind/testdata/ignore.objc.m.golden new file mode 100644 index 000000000..2415812b8 --- /dev/null +++ b/bind/testdata/ignore.objc.m.golden @@ -0,0 +1,91 @@ +// Objective-C API for talking to ignore Go package. +// gobind -lang=objc ignore +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Ignore.objc.h" + + +@implementation IgnoreS { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_ignore_S()); + } + return self; +} + +// skipped unsupported field F with type interface{} + +// skipped method S.Argument with unsupported parameter or return types + +// skipped method S.Result with unsupported parameter or return types + +@end + + +@implementation IgnoreI { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +// skipped method I.Argument with unsupported parameter or return types + +// skipped method I.Result with unsupported parameter or return types + +@end + + +// skipped const Cuint with unsupported type: uint + +// skipped const Cuint32 with unsupported type: uint32 + +// skipped const Cuint64 with unsupported type: uint64 + +// skipped const NamedConst with unsupported type: ignore.NamedString + + +@implementation Ignore +// skipped variable C128 with unsupported type: complex128 + +// skipped variable C64 with unsupported type: complex64 + +// skipped variable Uint with unsupported type: uint + +// skipped variable Uint32 with unsupported type: uint32 + +// skipped variable Uint64 with unsupported type: uint64 + +// skipped variable V with unsupported type: interface{} + +// skipped variable Var with unsupported type: interface{} + +@end + + +// skipped function Argument with unsupported parameter or return types + +// skipped function Result with unsupported parameter or return types + +// skipped method I.Argument with unsupported parameter or return types + +// skipped method I.Result with unsupported parameter or return types + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/interfaces.go b/bind/testdata/interfaces.go new file mode 100644 index 000000000..9e2da3a34 --- /dev/null +++ b/bind/testdata/interfaces.go @@ -0,0 +1,69 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package interfaces + +type I interface { + Rand() int32 +} + +type SameI interface { + Rand() int32 +} + +type LargerI interface { + Rand() int32 + AnotherFunc() +} + +func Add3(r I) int32 { + return r.Rand() + r.Rand() + r.Rand() +} + +// chosen by fair dice roll. +// guaranteed to be random. +type seven struct{} + +func (seven) Rand() int32 { return 7 } + +func Seven() I { return seven{} } + +type WithParam interface { + HasParam(p bool) +} + +type Error interface { + Err() error +} + +func CallErr(e Error) error { + return e.Err() +} + +// not implementable +type I1 interface { + J() + H() *seven // not bound +} + +// not implementable +type I2 interface { + f() + G() +} + +// implementable +// (the implementor has to find a source of I1s) +type I3 interface { + F() I1 +} + +// not bound +func F() seven { return seven{} } +func G(u seven) {} + +// Interfaces is an interface with the same name as its package. +type Interfaces interface { + SomeMethod() +} diff --git a/bind/testdata/interfaces.go.golden b/bind/testdata/interfaces.go.golden new file mode 100644 index 000000000..866bf163f --- /dev/null +++ b/bind/testdata/interfaces.go.golden @@ -0,0 +1,257 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package interfaces. +// +// autogenerated by gobind -lang=go interfaces +package main + +/* +#include +#include +#include "seq.h" +#include "interfaces.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "interfaces" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyinterfaces_Error_Err +func proxyinterfaces_Error_Err(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.Error) + res_0 := v.Err() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +type proxyinterfaces_Error _seq.Ref + +func (p *proxyinterfaces_Error) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyinterfaces_Error) Err() error { + res := C.cproxyinterfaces_Error_Err(C.int32_t(p.Bind_proxy_refnum__())) + var _res error + _res_ref := _seq.FromRefNum(int32(res)) + if _res_ref != nil { + if res < 0 { // go object + _res = _res_ref.Get().(error) + } else { // foreign object + _res = (*proxy_error)(_res_ref) + } + } + return _res +} + +//export proxyinterfaces_I_Rand +func proxyinterfaces_I_Rand(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.I) + res_0 := v.Rand() + _res_0 := C.int32_t(res_0) + return _res_0 +} + +type proxyinterfaces_I _seq.Ref + +func (p *proxyinterfaces_I) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyinterfaces_I) Rand() int32 { + res := C.cproxyinterfaces_I_Rand(C.int32_t(p.Bind_proxy_refnum__())) + _res := int32(res) + return _res +} + +//export proxyinterfaces_I1_J +func proxyinterfaces_I1_J(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.I1) + v.J() +} + +//export proxyinterfaces_I2_G +func proxyinterfaces_I2_G(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.I2) + v.G() +} + +//export proxyinterfaces_I3_F +func proxyinterfaces_I3_F(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.I3) + res_0 := v.F() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +type proxyinterfaces_I3 _seq.Ref + +func (p *proxyinterfaces_I3) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyinterfaces_I3) F() interfaces.I1 { + res := C.cproxyinterfaces_I3_F(C.int32_t(p.Bind_proxy_refnum__())) + var _res interfaces.I1 + _res_ref := _seq.FromRefNum(int32(res)) + if _res_ref != nil { + if res < 0 { // go object + _res = _res_ref.Get().(interfaces.I1) + } + } + return _res +} + +//export proxyinterfaces_Interfaces_SomeMethod +func proxyinterfaces_Interfaces_SomeMethod(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.Interfaces) + v.SomeMethod() +} + +type proxyinterfaces_Interfaces _seq.Ref + +func (p *proxyinterfaces_Interfaces) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyinterfaces_Interfaces) SomeMethod() { + C.cproxyinterfaces_Interfaces_SomeMethod(C.int32_t(p.Bind_proxy_refnum__())) +} + +//export proxyinterfaces_LargerI_AnotherFunc +func proxyinterfaces_LargerI_AnotherFunc(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.LargerI) + v.AnotherFunc() +} + +//export proxyinterfaces_LargerI_Rand +func proxyinterfaces_LargerI_Rand(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.LargerI) + res_0 := v.Rand() + _res_0 := C.int32_t(res_0) + return _res_0 +} + +type proxyinterfaces_LargerI _seq.Ref + +func (p *proxyinterfaces_LargerI) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyinterfaces_LargerI) AnotherFunc() { + C.cproxyinterfaces_LargerI_AnotherFunc(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxyinterfaces_LargerI) Rand() int32 { + res := C.cproxyinterfaces_LargerI_Rand(C.int32_t(p.Bind_proxy_refnum__())) + _res := int32(res) + return _res +} + +//export proxyinterfaces_SameI_Rand +func proxyinterfaces_SameI_Rand(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.SameI) + res_0 := v.Rand() + _res_0 := C.int32_t(res_0) + return _res_0 +} + +type proxyinterfaces_SameI _seq.Ref + +func (p *proxyinterfaces_SameI) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyinterfaces_SameI) Rand() int32 { + res := C.cproxyinterfaces_SameI_Rand(C.int32_t(p.Bind_proxy_refnum__())) + _res := int32(res) + return _res +} + +//export proxyinterfaces_WithParam_HasParam +func proxyinterfaces_WithParam_HasParam(refnum C.int32_t, param_p0 C.char) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(interfaces.WithParam) + _param_p0 := param_p0 != 0 + v.HasParam(_param_p0) +} + +type proxyinterfaces_WithParam _seq.Ref + +func (p *proxyinterfaces_WithParam) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyinterfaces_WithParam) HasParam(param_p0 bool) { + var _param_p0 C.char = 0 + if param_p0 { + _param_p0 = 1 + } + C.cproxyinterfaces_WithParam_HasParam(C.int32_t(p.Bind_proxy_refnum__()), _param_p0) +} + +//export proxyinterfaces__Add3 +func proxyinterfaces__Add3(param_r C.int32_t) C.int32_t { + var _param_r interfaces.I + _param_r_ref := _seq.FromRefNum(int32(param_r)) + if _param_r_ref != nil { + if param_r < 0 { // go object + _param_r = _param_r_ref.Get().(interfaces.I) + } else { // foreign object + _param_r = (*proxyinterfaces_I)(_param_r_ref) + } + } + res_0 := interfaces.Add3(_param_r) + _res_0 := C.int32_t(res_0) + return _res_0 +} + +//export proxyinterfaces__CallErr +func proxyinterfaces__CallErr(param_e C.int32_t) C.int32_t { + var _param_e interfaces.Error + _param_e_ref := _seq.FromRefNum(int32(param_e)) + if _param_e_ref != nil { + if param_e < 0 { // go object + _param_e = _param_e_ref.Get().(interfaces.Error) + } else { // foreign object + _param_e = (*proxyinterfaces_Error)(_param_e_ref) + } + } + res_0 := interfaces.CallErr(_param_e) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxyinterfaces__Seven +func proxyinterfaces__Seven() C.int32_t { + res_0 := interfaces.Seven() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} diff --git a/bind/testdata/interfaces.java.c.golden b/bind/testdata/interfaces.java.c.golden new file mode 100644 index 000000000..255daaf38 --- /dev/null +++ b/bind/testdata/interfaces.java.c.golden @@ -0,0 +1,277 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java interfaces + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "interfaces.h" + +jclass proxy_class_interfaces_Error; +jmethodID proxy_class_interfaces_Error_cons; +static jmethodID mid_Error_Err; +jclass proxy_class_interfaces_I; +jmethodID proxy_class_interfaces_I_cons; +static jmethodID mid_I_Rand; +jclass proxy_class_interfaces_I1; +jmethodID proxy_class_interfaces_I1_cons; +static jmethodID mid_I1_J; +jclass proxy_class_interfaces_I2; +jmethodID proxy_class_interfaces_I2_cons; +static jmethodID mid_I2_G; +jclass proxy_class_interfaces_I3; +jmethodID proxy_class_interfaces_I3_cons; +static jmethodID mid_I3_F; +jclass proxy_class_interfaces_Interfaces; +jmethodID proxy_class_interfaces_Interfaces_cons; +static jmethodID mid_Interfaces_SomeMethod; +jclass proxy_class_interfaces_LargerI; +jmethodID proxy_class_interfaces_LargerI_cons; +static jmethodID mid_LargerI_AnotherFunc; +static jmethodID mid_LargerI_Rand; +jclass proxy_class_interfaces_SameI; +jmethodID proxy_class_interfaces_SameI_cons; +static jmethodID mid_SameI_Rand; +jclass proxy_class_interfaces_WithParam; +jmethodID proxy_class_interfaces_WithParam_cons; +static jmethodID mid_WithParam_HasParam; + +JNIEXPORT void JNICALL +Java_interfaces_Interfaces__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyError"); + proxy_class_interfaces_Error = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_Error_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/Error"); + mid_Error_Err = (*env)->GetMethodID(env, clazz, "err", "()V"); + + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyI"); + proxy_class_interfaces_I = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_I_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/I"); + mid_I_Rand = (*env)->GetMethodID(env, clazz, "rand", "()I"); + + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyI1"); + proxy_class_interfaces_I1 = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_I1_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/I1"); + mid_I1_J = (*env)->GetMethodID(env, clazz, "j", "()V"); + + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyI2"); + proxy_class_interfaces_I2 = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_I2_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/I2"); + mid_I2_G = (*env)->GetMethodID(env, clazz, "g", "()V"); + + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyI3"); + proxy_class_interfaces_I3 = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_I3_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/I3"); + mid_I3_F = (*env)->GetMethodID(env, clazz, "f", "()Linterfaces/I1;"); + + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyInterfaces"); + proxy_class_interfaces_Interfaces = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_Interfaces_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/Interfaces_"); + mid_Interfaces_SomeMethod = (*env)->GetMethodID(env, clazz, "someMethod", "()V"); + + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyLargerI"); + proxy_class_interfaces_LargerI = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_LargerI_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/LargerI"); + mid_LargerI_AnotherFunc = (*env)->GetMethodID(env, clazz, "anotherFunc", "()V"); + mid_LargerI_Rand = (*env)->GetMethodID(env, clazz, "rand", "()I"); + + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxySameI"); + proxy_class_interfaces_SameI = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_SameI_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/SameI"); + mid_SameI_Rand = (*env)->GetMethodID(env, clazz, "rand", "()I"); + + clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyWithParam"); + proxy_class_interfaces_WithParam = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_WithParam_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "interfaces/WithParam"); + mid_WithParam_HasParam = (*env)->GetMethodID(env, clazz, "hasParam", "(Z)V"); + +} + +JNIEXPORT jint JNICALL +Java_interfaces_Interfaces_add3(JNIEnv* env, jclass _clazz, jobject r) { + int32_t _r = go_seq_to_refnum(env, r); + int32_t r0 = proxyinterfaces__Add3(_r); + jint _r0 = (jint)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_interfaces_Interfaces_callErr(JNIEnv* env, jclass _clazz, jobject e) { + int32_t _e = go_seq_to_refnum(env, e); + int32_t r0 = proxyinterfaces__CallErr(_e); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r0); +} + +JNIEXPORT jobject JNICALL +Java_interfaces_Interfaces_seven(JNIEnv* env, jclass _clazz) { + int32_t r0 = proxyinterfaces__Seven(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_interfaces_I, proxy_class_interfaces_I_cons); + return _r0; +} + +JNIEXPORT void JNICALL +Java_interfaces_Interfaces_00024proxyError_err(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + int32_t r0 = proxyinterfaces_Error_Err(o); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r0); +} + +int32_t cproxyinterfaces_Error_Err(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_Error, proxy_class_interfaces_Error_cons); + (*env)->CallVoidMethod(env, o, mid_Error_Err); + jobject exc = go_seq_get_exception(env); + int32_t _exc = go_seq_to_refnum(env, exc); + go_seq_pop_local_frame(env); + return _exc; +} + +JNIEXPORT jint JNICALL +Java_interfaces_Interfaces_00024proxyI_rand(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + int32_t r0 = proxyinterfaces_I_Rand(o); + jint _r0 = (jint)r0; + return _r0; +} + +int32_t cproxyinterfaces_I_Rand(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_I, proxy_class_interfaces_I_cons); + jint res = (*env)->CallIntMethod(env, o, mid_I_Rand); + int32_t _res = (int32_t)res; + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT void JNICALL +Java_interfaces_Interfaces_00024proxyI1_j(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxyinterfaces_I1_J(o); +} + +void cproxyinterfaces_I1_J(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_I1, proxy_class_interfaces_I1_cons); + (*env)->CallVoidMethod(env, o, mid_I1_J); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_interfaces_Interfaces_00024proxyI2_g(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxyinterfaces_I2_G(o); +} + +void cproxyinterfaces_I2_G(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_I2, proxy_class_interfaces_I2_cons); + (*env)->CallVoidMethod(env, o, mid_I2_G); + go_seq_pop_local_frame(env); +} + +JNIEXPORT jobject JNICALL +Java_interfaces_Interfaces_00024proxyI3_f(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + int32_t r0 = proxyinterfaces_I3_F(o); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_interfaces_I1, proxy_class_interfaces_I1_cons); + return _r0; +} + +int32_t cproxyinterfaces_I3_F(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_I3, proxy_class_interfaces_I3_cons); + jobject res = (*env)->CallObjectMethod(env, o, mid_I3_F); + int32_t _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT void JNICALL +Java_interfaces_Interfaces_00024proxyInterfaces_someMethod(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxyinterfaces_Interfaces_SomeMethod(o); +} + +void cproxyinterfaces_Interfaces_SomeMethod(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_Interfaces, proxy_class_interfaces_Interfaces_cons); + (*env)->CallVoidMethod(env, o, mid_Interfaces_SomeMethod); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_interfaces_Interfaces_00024proxyLargerI_anotherFunc(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxyinterfaces_LargerI_AnotherFunc(o); +} + +void cproxyinterfaces_LargerI_AnotherFunc(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_LargerI, proxy_class_interfaces_LargerI_cons); + (*env)->CallVoidMethod(env, o, mid_LargerI_AnotherFunc); + go_seq_pop_local_frame(env); +} + +JNIEXPORT jint JNICALL +Java_interfaces_Interfaces_00024proxyLargerI_rand(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + int32_t r0 = proxyinterfaces_LargerI_Rand(o); + jint _r0 = (jint)r0; + return _r0; +} + +int32_t cproxyinterfaces_LargerI_Rand(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_LargerI, proxy_class_interfaces_LargerI_cons); + jint res = (*env)->CallIntMethod(env, o, mid_LargerI_Rand); + int32_t _res = (int32_t)res; + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT jint JNICALL +Java_interfaces_Interfaces_00024proxySameI_rand(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + int32_t r0 = proxyinterfaces_SameI_Rand(o); + jint _r0 = (jint)r0; + return _r0; +} + +int32_t cproxyinterfaces_SameI_Rand(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_SameI, proxy_class_interfaces_SameI_cons); + jint res = (*env)->CallIntMethod(env, o, mid_SameI_Rand); + int32_t _res = (int32_t)res; + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT void JNICALL +Java_interfaces_Interfaces_00024proxyWithParam_hasParam(JNIEnv* env, jobject __this__, jboolean p0) { + int32_t o = go_seq_to_refnum_go(env, __this__); + char _p0 = (char)p0; + proxyinterfaces_WithParam_HasParam(o, _p0); +} + +void cproxyinterfaces_WithParam_HasParam(int32_t refnum, char p0) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_WithParam, proxy_class_interfaces_WithParam_cons); + jboolean _p0 = p0 ? JNI_TRUE : JNI_FALSE; + (*env)->CallVoidMethod(env, o, mid_WithParam_HasParam, _p0); + go_seq_pop_local_frame(env); +} + diff --git a/bind/testdata/interfaces.java.golden b/bind/testdata/interfaces.java.golden new file mode 100644 index 000000000..f17d6dca9 --- /dev/null +++ b/bind/testdata/interfaces.java.golden @@ -0,0 +1,277 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.Error is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +public interface Error { + public void err() throws Exception; + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.I is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +public interface I { + public int rand(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.I1 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +/** + * not implementable + */ +public interface I1 { + public void j(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.I2 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +/** + * not implementable + */ +public interface I2 { + public void g(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.I3 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +/** + * implementable +(the implementor has to find a source of I1s) + */ +public interface I3 { + public I1 f(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.Interfaces_ is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +/** + * Interfaces is an interface with the same name as its package. + */ +public interface Interfaces_ { + public void someMethod(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.LargerI is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +public interface LargerI extends I, SameI { + public void anotherFunc(); + public int rand(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.SameI is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +public interface SameI { + public int rand(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.WithParam is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +public interface WithParam { + public void hasParam(boolean p0); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class interfaces.Interfaces is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java interfaces +package interfaces; + +import go.Seq; + +public abstract class Interfaces { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Interfaces() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyError implements Seq.Proxy, Error { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyError(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void err() throws Exception; + } + private static final class proxyI implements Seq.Proxy, I { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyI(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native int rand(); + } + private static final class proxyI1 implements Seq.Proxy, I1 { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyI1(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void j(); + } + private static final class proxyI2 implements Seq.Proxy, I2 { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyI2(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void g(); + } + private static final class proxyI3 implements Seq.Proxy, I3 { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyI3(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native I1 f(); + } + private static final class proxyInterfaces implements Seq.Proxy, Interfaces_ { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyInterfaces(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void someMethod(); + } + private static final class proxyLargerI implements Seq.Proxy, LargerI { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyLargerI(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void anotherFunc(); + public native int rand(); + } + private static final class proxySameI implements Seq.Proxy, SameI { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxySameI(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native int rand(); + } + private static final class proxyWithParam implements Seq.Proxy, WithParam { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyWithParam(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void hasParam(boolean p0); + } + + + public static native int add3(I r); + public static native void callErr(Error e) throws Exception; + public static native I seven(); +} diff --git a/bind/testdata/interfaces.java.h.golden b/bind/testdata/interfaces.java.h.golden new file mode 100644 index 000000000..fb51082a9 --- /dev/null +++ b/bind/testdata/interfaces.java.h.golden @@ -0,0 +1,59 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java interfaces + +#ifndef __Interfaces_H__ +#define __Interfaces_H__ + +#include + +extern jclass proxy_class_interfaces_Error; +extern jmethodID proxy_class_interfaces_Error_cons; + +int32_t cproxyinterfaces_Error_Err(int32_t refnum); + +extern jclass proxy_class_interfaces_I; +extern jmethodID proxy_class_interfaces_I_cons; + +int32_t cproxyinterfaces_I_Rand(int32_t refnum); + +extern jclass proxy_class_interfaces_I1; +extern jmethodID proxy_class_interfaces_I1_cons; + +void cproxyinterfaces_I1_J(int32_t refnum); + +extern jclass proxy_class_interfaces_I2; +extern jmethodID proxy_class_interfaces_I2_cons; + +void cproxyinterfaces_I2_G(int32_t refnum); + +extern jclass proxy_class_interfaces_I3; +extern jmethodID proxy_class_interfaces_I3_cons; + +int32_t cproxyinterfaces_I3_F(int32_t refnum); + +extern jclass proxy_class_interfaces_Interfaces; +extern jmethodID proxy_class_interfaces_Interfaces_cons; + +void cproxyinterfaces_Interfaces_SomeMethod(int32_t refnum); + +extern jclass proxy_class_interfaces_LargerI; +extern jmethodID proxy_class_interfaces_LargerI_cons; + +void cproxyinterfaces_LargerI_AnotherFunc(int32_t refnum); + +int32_t cproxyinterfaces_LargerI_Rand(int32_t refnum); + +extern jclass proxy_class_interfaces_SameI; +extern jmethodID proxy_class_interfaces_SameI_cons; + +int32_t cproxyinterfaces_SameI_Rand(int32_t refnum); + +extern jclass proxy_class_interfaces_WithParam; +extern jmethodID proxy_class_interfaces_WithParam_cons; + +void cproxyinterfaces_WithParam_HasParam(int32_t refnum, char p0); + +#endif diff --git a/bind/testdata/interfaces.objc.go.h.golden b/bind/testdata/interfaces.objc.go.h.golden new file mode 100644 index 000000000..6b77787ae --- /dev/null +++ b/bind/testdata/interfaces.objc.go.h.golden @@ -0,0 +1,27 @@ +// Objective-C API for talking to interfaces Go package. +// gobind -lang=objc interfaces +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_interfaces_H__ +#define __GO_interfaces_H__ + +#include +#include +int32_t cproxyinterfaces_Error_Err(int32_t refnum); + +int32_t cproxyinterfaces_I_Rand(int32_t refnum); + +int32_t cproxyinterfaces_I3_F(int32_t refnum); + +void cproxyinterfaces_Interfaces_SomeMethod(int32_t refnum); + +void cproxyinterfaces_LargerI_AnotherFunc(int32_t refnum); + +int32_t cproxyinterfaces_LargerI_Rand(int32_t refnum); + +int32_t cproxyinterfaces_SameI_Rand(int32_t refnum); + +void cproxyinterfaces_WithParam_HasParam(int32_t refnum, char p0); + +#endif diff --git a/bind/testdata/interfaces.objc.h.golden b/bind/testdata/interfaces.objc.h.golden new file mode 100644 index 000000000..ed5c50760 --- /dev/null +++ b/bind/testdata/interfaces.objc.h.golden @@ -0,0 +1,166 @@ +// Objective-C API for talking to interfaces Go package. +// gobind -lang=objc interfaces +// +// File is generated by gobind. Do not edit. + +#ifndef __Interfaces_H__ +#define __Interfaces_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@protocol InterfacesError; +@class InterfacesError; +@protocol InterfacesI; +@class InterfacesI; +@protocol InterfacesI1; +@protocol InterfacesI2; +@protocol InterfacesI3; +@class InterfacesI3; +@protocol InterfacesInterfaces; +@class InterfacesInterfaces; +@protocol InterfacesLargerI; +@class InterfacesLargerI; +@protocol InterfacesSameI; +@class InterfacesSameI; +@protocol InterfacesWithParam; +@class InterfacesWithParam; + +@protocol InterfacesError +- (BOOL)err:(NSError* _Nullable* _Nullable)error; +@end + +@protocol InterfacesI +- (int32_t)rand; +@end + +/** + * not implementable + */ +@interface InterfacesI1 : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (void)j; +@end + +/** + * not implementable + */ +@interface InterfacesI2 : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (void)g; +@end + +@protocol InterfacesI3 +- (InterfacesI1* _Nullable)f; +@end + +@protocol InterfacesInterfaces +- (void)someMethod; +@end + +@protocol InterfacesLargerI +- (void)anotherFunc; +- (int32_t)rand; +@end + +@protocol InterfacesSameI +- (int32_t)rand; +@end + +@protocol InterfacesWithParam +- (void)hasParam:(BOOL)p0; +@end + +FOUNDATION_EXPORT int32_t InterfacesAdd3(id _Nullable r); + +FOUNDATION_EXPORT BOOL InterfacesCallErr(id _Nullable e, NSError* _Nullable* _Nullable error); + +FOUNDATION_EXPORT id _Nullable InterfacesSeven(void); + +@class InterfacesError; + +@class InterfacesI; + +@class InterfacesI3; + +@class InterfacesInterfaces; + +@class InterfacesLargerI; + +@class InterfacesSameI; + +@class InterfacesWithParam; + +@interface InterfacesError : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (BOOL)err:(NSError* _Nullable* _Nullable)error; +@end + +@interface InterfacesI : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (int32_t)rand; +@end + +/** + * implementable +(the implementor has to find a source of I1s) + */ +@interface InterfacesI3 : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (InterfacesI1* _Nullable)f; +@end + +/** + * Interfaces is an interface with the same name as its package. + */ +@interface InterfacesInterfaces : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (void)someMethod; +@end + +@interface InterfacesLargerI : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (void)anotherFunc; +- (int32_t)rand; +@end + +@interface InterfacesSameI : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (int32_t)rand; +@end + +@interface InterfacesWithParam : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (void)hasParam:(BOOL)p0; +@end + +#endif diff --git a/bind/testdata/interfaces.objc.m.golden b/bind/testdata/interfaces.objc.m.golden new file mode 100644 index 000000000..6148d5a8c --- /dev/null +++ b/bind/testdata/interfaces.objc.m.golden @@ -0,0 +1,351 @@ +// Objective-C API for talking to interfaces Go package. +// gobind -lang=objc interfaces +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Interfaces.objc.h" + +@implementation InterfacesError { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (BOOL)err:(NSError* _Nullable* _Nullable)error { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxyinterfaces_Error_Err(refnum); + Universeerror* _error = nil; + GoSeqRef* _error_ref = go_seq_from_refnum(r0); + if (_error_ref != NULL) { + _error = _error_ref.obj; + if (_error == nil) { + _error = [[Universeerror alloc] initWithRef:_error_ref]; + } + } + if (_error != nil && error != nil) { + *error = _error; + } + return (_error == nil); +} + +@end + + +@implementation InterfacesI { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (int32_t)rand { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxyinterfaces_I_Rand(refnum); + int32_t _ret0_ = (int32_t)r0; + return _ret0_; +} + +@end + + +@implementation InterfacesI1 { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)j { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxyinterfaces_I1_J(refnum); +} + +@end + + +@implementation InterfacesI2 { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)g { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxyinterfaces_I2_G(refnum); +} + +@end + + +@implementation InterfacesI3 { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (InterfacesI1* _Nullable)f { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxyinterfaces_I3_F(refnum); + InterfacesI1* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[InterfacesI1 alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +@end + + +@implementation InterfacesInterfaces { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)someMethod { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxyinterfaces_Interfaces_SomeMethod(refnum); +} + +@end + + +@implementation InterfacesLargerI { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)anotherFunc { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxyinterfaces_LargerI_AnotherFunc(refnum); +} + +- (int32_t)rand { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxyinterfaces_LargerI_Rand(refnum); + int32_t _ret0_ = (int32_t)r0; + return _ret0_; +} + +@end + + +@implementation InterfacesSameI { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (int32_t)rand { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxyinterfaces_SameI_Rand(refnum); + int32_t _ret0_ = (int32_t)r0; + return _ret0_; +} + +@end + + +@implementation InterfacesWithParam { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)hasParam:(BOOL)p0 { + int32_t refnum = go_seq_go_to_refnum(self._ref); + char _p0 = (char)p0; + proxyinterfaces_WithParam_HasParam(refnum, _p0); +} + +@end + + + +int32_t InterfacesAdd3(id _Nullable r) { + int32_t _r; + if ([r conformsToProtocol:@protocol(goSeqRefInterface)]) { + id r_proxy = (id)(r); + _r = go_seq_go_to_refnum(r_proxy._ref); + } else { + _r = go_seq_to_refnum(r); + } + int32_t r0 = proxyinterfaces__Add3(_r); + int32_t _ret0_ = (int32_t)r0; + return _ret0_; +} + +BOOL InterfacesCallErr(id _Nullable e, NSError* _Nullable* _Nullable error) { + int32_t _e; + if ([e conformsToProtocol:@protocol(goSeqRefInterface)]) { + id e_proxy = (id)(e); + _e = go_seq_go_to_refnum(e_proxy._ref); + } else { + _e = go_seq_to_refnum(e); + } + int32_t r0 = proxyinterfaces__CallErr(_e); + Universeerror* _error = nil; + GoSeqRef* _error_ref = go_seq_from_refnum(r0); + if (_error_ref != NULL) { + _error = _error_ref.obj; + if (_error == nil) { + _error = [[Universeerror alloc] initWithRef:_error_ref]; + } + } + if (_error != nil && error != nil) { + *error = _error; + } + return (_error == nil); +} + +id _Nullable InterfacesSeven(void) { + int32_t r0 = proxyinterfaces__Seven(); + InterfacesI* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[InterfacesI alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +int32_t cproxyinterfaces_Error_Err(int32_t refnum) { + @autoreleasepool { + InterfacesError* o = go_seq_objc_from_refnum(refnum); + NSError* error = nil; + BOOL returnVal = [o err:&error]; + NSError *_error = nil; + if (!returnVal) { + _error = error; + } + int32_t __error; + if ([_error conformsToProtocol:@protocol(goSeqRefInterface)]) { + id _error_proxy = (id)(_error); + __error = go_seq_go_to_refnum(_error_proxy._ref); + } else { + __error = go_seq_to_refnum(_error); + } + return __error; + } +} + +int32_t cproxyinterfaces_I_Rand(int32_t refnum) { + @autoreleasepool { + InterfacesI* o = go_seq_objc_from_refnum(refnum); + int32_t ret0_; + ret0_ = [o rand]; + int32_t _ret0_ = (int32_t)ret0_; + return _ret0_; + } +} + +void cproxyinterfaces_I1_J(int32_t refnum) { + @autoreleasepool { + InterfacesI1* o = go_seq_objc_from_refnum(refnum); + [o j]; + } +} + +void cproxyinterfaces_I2_G(int32_t refnum) { + @autoreleasepool { + InterfacesI2* o = go_seq_objc_from_refnum(refnum); + [o g]; + } +} + +int32_t cproxyinterfaces_I3_F(int32_t refnum) { + @autoreleasepool { + InterfacesI3* o = go_seq_objc_from_refnum(refnum); + InterfacesI1* _Nullable ret0_; + ret0_ = [o f]; + int32_t _ret0_; + if ([ret0_ conformsToProtocol:@protocol(goSeqRefInterface)]) { + id ret0__proxy = (id)(ret0_); + _ret0_ = go_seq_go_to_refnum(ret0__proxy._ref); + } else { + _ret0_ = go_seq_to_refnum(ret0_); + } + return _ret0_; + } +} + +void cproxyinterfaces_Interfaces_SomeMethod(int32_t refnum) { + @autoreleasepool { + InterfacesInterfaces* o = go_seq_objc_from_refnum(refnum); + [o someMethod]; + } +} + +void cproxyinterfaces_LargerI_AnotherFunc(int32_t refnum) { + @autoreleasepool { + InterfacesLargerI* o = go_seq_objc_from_refnum(refnum); + [o anotherFunc]; + } +} + +int32_t cproxyinterfaces_LargerI_Rand(int32_t refnum) { + @autoreleasepool { + InterfacesLargerI* o = go_seq_objc_from_refnum(refnum); + int32_t ret0_; + ret0_ = [o rand]; + int32_t _ret0_ = (int32_t)ret0_; + return _ret0_; + } +} + +int32_t cproxyinterfaces_SameI_Rand(int32_t refnum) { + @autoreleasepool { + InterfacesSameI* o = go_seq_objc_from_refnum(refnum); + int32_t ret0_; + ret0_ = [o rand]; + int32_t _ret0_ = (int32_t)ret0_; + return _ret0_; + } +} + +void cproxyinterfaces_WithParam_HasParam(int32_t refnum, char p0) { + @autoreleasepool { + InterfacesWithParam* o = go_seq_objc_from_refnum(refnum); + BOOL _p0 = p0 ? YES : NO; + [o hasParam:_p0]; + } +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/issue10788.go b/bind/testdata/issue10788.go new file mode 100644 index 000000000..af487218e --- /dev/null +++ b/bind/testdata/issue10788.go @@ -0,0 +1,14 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue10788 + +type TestStruct struct { + Value string +} + +type TestInterface interface { + DoSomeWork(s *TestStruct) + MultipleUnnamedParams(_ int, p0 string, 日本 int64) +} diff --git a/bind/testdata/issue10788.go.golden b/bind/testdata/issue10788.go.golden new file mode 100644 index 000000000..3c6954dbf --- /dev/null +++ b/bind/testdata/issue10788.go.golden @@ -0,0 +1,86 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package issue10788. +// +// autogenerated by gobind -lang=go issue10788 +package main + +/* +#include +#include +#include "seq.h" +#include "issue10788.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "issue10788" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyissue10788_TestStruct_Value_Set +func proxyissue10788_TestStruct_Value_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v := decodeString(v) + ref.Get().(*issue10788.TestStruct).Value = _v +} + +//export proxyissue10788_TestStruct_Value_Get +func proxyissue10788_TestStruct_Value_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*issue10788.TestStruct).Value + _v := encodeString(v) + return _v +} + +//export new_issue10788_TestStruct +func new_issue10788_TestStruct() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(issue10788.TestStruct))) +} + +//export proxyissue10788_TestInterface_DoSomeWork +func proxyissue10788_TestInterface_DoSomeWork(refnum C.int32_t, param_s C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(issue10788.TestInterface) + // Must be a Go object + var _param_s *issue10788.TestStruct + if _param_s_ref := _seq.FromRefNum(int32(param_s)); _param_s_ref != nil { + _param_s = _param_s_ref.Get().(*issue10788.TestStruct) + } + v.DoSomeWork(_param_s) +} + +//export proxyissue10788_TestInterface_MultipleUnnamedParams +func proxyissue10788_TestInterface_MultipleUnnamedParams(refnum C.int32_t, param_p0 C.nint, param_p1 C.nstring, param_日本 C.int64_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(issue10788.TestInterface) + _param_p0 := int(param_p0) + _param_p1 := decodeString(param_p1) + _param_日本 := int64(param_日本) + v.MultipleUnnamedParams(_param_p0, _param_p1, _param_日本) +} + +type proxyissue10788_TestInterface _seq.Ref + +func (p *proxyissue10788_TestInterface) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyissue10788_TestInterface) DoSomeWork(param_s *issue10788.TestStruct) { + var _param_s C.int32_t = _seq.NullRefNum + if param_s != nil { + _param_s = C.int32_t(_seq.ToRefNum(param_s)) + } + C.cproxyissue10788_TestInterface_DoSomeWork(C.int32_t(p.Bind_proxy_refnum__()), _param_s) +} + +func (p *proxyissue10788_TestInterface) MultipleUnnamedParams(param_p0 int, param_p1 string, param_日本 int64) { + _param_p0 := C.nint(param_p0) + _param_p1 := encodeString(param_p1) + _param_日本 := C.int64_t(param_日本) + C.cproxyissue10788_TestInterface_MultipleUnnamedParams(C.int32_t(p.Bind_proxy_refnum__()), _param_p0, _param_p1, _param_日本) +} diff --git a/bind/testdata/issue10788.java.c.golden b/bind/testdata/issue10788.java.c.golden new file mode 100644 index 000000000..da1bcfb62 --- /dev/null +++ b/bind/testdata/issue10788.java.c.golden @@ -0,0 +1,88 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java issue10788 + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "issue10788.h" + +jclass proxy_class_issue10788_TestInterface; +jmethodID proxy_class_issue10788_TestInterface_cons; +static jmethodID mid_TestInterface_DoSomeWork; +static jmethodID mid_TestInterface_MultipleUnnamedParams; +jclass proxy_class_issue10788_TestStruct; +jmethodID proxy_class_issue10788_TestStruct_cons; + +JNIEXPORT void JNICALL +Java_issue10788_Issue10788__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "issue10788/TestStruct"); + proxy_class_issue10788_TestStruct = (*env)->NewGlobalRef(env, clazz); + proxy_class_issue10788_TestStruct_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "issue10788/Issue10788$proxyTestInterface"); + proxy_class_issue10788_TestInterface = (*env)->NewGlobalRef(env, clazz); + proxy_class_issue10788_TestInterface_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "issue10788/TestInterface"); + mid_TestInterface_DoSomeWork = (*env)->GetMethodID(env, clazz, "doSomeWork", "(Lissue10788/TestStruct;)V"); + mid_TestInterface_MultipleUnnamedParams = (*env)->GetMethodID(env, clazz, "multipleUnnamedParams", "(JLjava/lang/String;J)V"); + +} + +JNIEXPORT jint JNICALL +Java_issue10788_TestStruct__1_1New(JNIEnv *env, jclass clazz) { + return new_issue10788_TestStruct(); +} + +JNIEXPORT void JNICALL +Java_issue10788_TestStruct_setValue(JNIEnv *env, jobject this, jstring v) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring _v = go_seq_from_java_string(env, v); + proxyissue10788_TestStruct_Value_Set(o, _v); +} + +JNIEXPORT jstring JNICALL +Java_issue10788_TestStruct_getValue(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring r0 = proxyissue10788_TestStruct_Value_Get(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT void JNICALL +Java_issue10788_Issue10788_00024proxyTestInterface_doSomeWork(JNIEnv* env, jobject __this__, jobject s) { + int32_t o = go_seq_to_refnum_go(env, __this__); + int32_t _s = go_seq_to_refnum(env, s); + proxyissue10788_TestInterface_DoSomeWork(o, _s); +} + +void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue10788_TestInterface, proxy_class_issue10788_TestInterface_cons); + jobject _s = go_seq_from_refnum(env, s, proxy_class_issue10788_TestStruct, proxy_class_issue10788_TestStruct_cons); + (*env)->CallVoidMethod(env, o, mid_TestInterface_DoSomeWork, _s); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_issue10788_Issue10788_00024proxyTestInterface_multipleUnnamedParams(JNIEnv* env, jobject __this__, jlong p0, jstring p1, jlong p2) { + int32_t o = go_seq_to_refnum_go(env, __this__); + nint _p0 = (nint)p0; + nstring _p1 = go_seq_from_java_string(env, p1); + int64_t _p2 = (int64_t)p2; + proxyissue10788_TestInterface_MultipleUnnamedParams(o, _p0, _p1, _p2); +} + +void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t p2) { + JNIEnv *env = go_seq_push_local_frame(3); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue10788_TestInterface, proxy_class_issue10788_TestInterface_cons); + jlong _p0 = (jlong)p0; + jstring _p1 = go_seq_to_java_string(env, p1); + jlong _p2 = (jlong)p2; + (*env)->CallVoidMethod(env, o, mid_TestInterface_MultipleUnnamedParams, _p0, _p1, _p2); + go_seq_pop_local_frame(env); +} + diff --git a/bind/testdata/issue10788.java.golden b/bind/testdata/issue10788.java.golden new file mode 100644 index 000000000..9b4877f44 --- /dev/null +++ b/bind/testdata/issue10788.java.golden @@ -0,0 +1,110 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class issue10788.TestStruct is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java issue10788 +package issue10788; + +import go.Seq; + +public final class TestStruct implements Seq.Proxy { + static { Issue10788.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + TestStruct(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public TestStruct() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public final native String getValue(); + public final native void setValue(String v); + + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof TestStruct)) { + return false; + } + TestStruct that = (TestStruct)o; + String thisValue = getValue(); + String thatValue = that.getValue(); + if (thisValue == null) { + if (thatValue != null) { + return false; + } + } else if (!thisValue.equals(thatValue)) { + return false; + } + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {getValue()}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("TestStruct").append("{"); + b.append("Value:").append(getValue()).append(","); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class issue10788.TestInterface is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java issue10788 +package issue10788; + +import go.Seq; + +public interface TestInterface { + public void doSomeWork(TestStruct s); + public void multipleUnnamedParams(long p0, String p1, long p2); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class issue10788.Issue10788 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java issue10788 +package issue10788; + +import go.Seq; + +public abstract class Issue10788 { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Issue10788() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyTestInterface implements Seq.Proxy, TestInterface { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyTestInterface(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void doSomeWork(TestStruct s); + public native void multipleUnnamedParams(long p0, String p1, long p2); + } + + +} diff --git a/bind/testdata/issue10788.java.h.golden b/bind/testdata/issue10788.java.h.golden new file mode 100644 index 000000000..2a0b28f0b --- /dev/null +++ b/bind/testdata/issue10788.java.h.golden @@ -0,0 +1,21 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java issue10788 + +#ifndef __Issue10788_H__ +#define __Issue10788_H__ + +#include + +extern jclass proxy_class_issue10788_TestInterface; +extern jmethodID proxy_class_issue10788_TestInterface_cons; + +void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s); + +void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t p2); + +extern jclass proxy_class_issue10788_TestStruct; +extern jmethodID proxy_class_issue10788_TestStruct_cons; +#endif diff --git a/bind/testdata/issue10788.objc.go.h.golden b/bind/testdata/issue10788.objc.go.h.golden new file mode 100644 index 000000000..3001a05b5 --- /dev/null +++ b/bind/testdata/issue10788.objc.go.h.golden @@ -0,0 +1,15 @@ +// Objective-C API for talking to issue10788 Go package. +// gobind -lang=objc issue10788 +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_issue10788_H__ +#define __GO_issue10788_H__ + +#include +#include +void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s); + +void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t 日本); + +#endif diff --git a/bind/testdata/issue10788.objc.h.golden b/bind/testdata/issue10788.objc.h.golden new file mode 100644 index 000000000..556560de6 --- /dev/null +++ b/bind/testdata/issue10788.objc.h.golden @@ -0,0 +1,43 @@ +// Objective-C API for talking to issue10788 Go package. +// gobind -lang=objc issue10788 +// +// File is generated by gobind. Do not edit. + +#ifndef __Issue10788_H__ +#define __Issue10788_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class Issue10788TestStruct; +@protocol Issue10788TestInterface; +@class Issue10788TestInterface; + +@protocol Issue10788TestInterface +- (void)doSomeWork:(Issue10788TestStruct* _Nullable)s; +- (void)multipleUnnamedParams:(long)p0 p1:(NSString* _Nullable)p1 日本:(int64_t)日本; +@end + +@interface Issue10788TestStruct : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +@property (nonatomic) NSString* _Nonnull value; +@end + +@class Issue10788TestInterface; + +@interface Issue10788TestInterface : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (void)doSomeWork:(Issue10788TestStruct* _Nullable)s; +- (void)multipleUnnamedParams:(long)p0 p1:(NSString* _Nullable)p1 日本:(int64_t)日本; +@end + +#endif diff --git a/bind/testdata/issue10788.objc.m.golden b/bind/testdata/issue10788.objc.m.golden new file mode 100644 index 000000000..8aad517e4 --- /dev/null +++ b/bind/testdata/issue10788.objc.m.golden @@ -0,0 +1,105 @@ +// Objective-C API for talking to issue10788 Go package. +// gobind -lang=objc issue10788 +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Issue10788.objc.h" + + +@implementation Issue10788TestStruct { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_issue10788_TestStruct()); + } + return self; +} + +- (NSString* _Nonnull)value { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxyissue10788_TestStruct_Value_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + +- (void)setValue:(NSString* _Nonnull)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxyissue10788_TestStruct_Value_Set(refnum, _v); +} + +@end + + +@implementation Issue10788TestInterface { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)doSomeWork:(Issue10788TestStruct* _Nullable)s { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t _s; + if ([s conformsToProtocol:@protocol(goSeqRefInterface)]) { + id s_proxy = (id)(s); + _s = go_seq_go_to_refnum(s_proxy._ref); + } else { + _s = go_seq_to_refnum(s); + } + proxyissue10788_TestInterface_DoSomeWork(refnum, _s); +} + +- (void)multipleUnnamedParams:(long)p0 p1:(NSString* _Nullable)p1 日本:(int64_t)日本 { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nint _p0 = (nint)p0; + nstring _p1 = go_seq_from_objc_string(p1); + int64_t _日本 = (int64_t)日本; + proxyissue10788_TestInterface_MultipleUnnamedParams(refnum, _p0, _p1, _日本); +} + +@end + + + +void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s) { + @autoreleasepool { + Issue10788TestInterface* o = go_seq_objc_from_refnum(refnum); + Issue10788TestStruct* _s = nil; + GoSeqRef* _s_ref = go_seq_from_refnum(s); + if (_s_ref != NULL) { + _s = _s_ref.obj; + if (_s == nil) { + _s = [[Issue10788TestStruct alloc] initWithRef:_s_ref]; + } + } + [o doSomeWork:_s]; + } +} + +void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t 日本) { + @autoreleasepool { + Issue10788TestInterface* o = go_seq_objc_from_refnum(refnum); + long _p0 = (long)p0; + NSString *_p1 = go_seq_to_objc_string(p1); + int64_t _日本 = (int64_t)日本; + [o multipleUnnamedParams:_p0 p1:_p1 日本:_日本]; + } +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/issue12328.go b/bind/testdata/issue12328.go new file mode 100644 index 000000000..2b4ab887f --- /dev/null +++ b/bind/testdata/issue12328.go @@ -0,0 +1,9 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue12328 + +type T struct { + Err error +} diff --git a/bind/testdata/issue12328.go.golden b/bind/testdata/issue12328.go.golden new file mode 100644 index 000000000..91b2bb84d --- /dev/null +++ b/bind/testdata/issue12328.go.golden @@ -0,0 +1,54 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package issue12328. +// +// autogenerated by gobind -lang=go issue12328 +package main + +/* +#include +#include +#include "seq.h" +#include "issue12328.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "issue12328" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyissue12328_T_Err_Set +func proxyissue12328_T_Err_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v error + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(error) + } else { // foreign object + _v = (*proxy_error)(_v_ref) + } + } + ref.Get().(*issue12328.T).Err = _v +} + +//export proxyissue12328_T_Err_Get +func proxyissue12328_T_Err_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*issue12328.T).Err + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export new_issue12328_T +func new_issue12328_T() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(issue12328.T))) +} diff --git a/bind/testdata/issue12328.java.c.golden b/bind/testdata/issue12328.java.c.golden new file mode 100644 index 000000000..da8798935 --- /dev/null +++ b/bind/testdata/issue12328.java.c.golden @@ -0,0 +1,43 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java issue12328 + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "issue12328.h" + +jclass proxy_class_issue12328_T; +jmethodID proxy_class_issue12328_T_cons; + +JNIEXPORT void JNICALL +Java_issue12328_Issue12328__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "issue12328/T"); + proxy_class_issue12328_T = (*env)->NewGlobalRef(env, clazz); + proxy_class_issue12328_T_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); +} + +JNIEXPORT jint JNICALL +Java_issue12328_T__1_1New(JNIEnv *env, jclass clazz) { + return new_issue12328_T(); +} + +JNIEXPORT void JNICALL +Java_issue12328_T_setErr(JNIEnv *env, jobject this, jobject v) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t _v = go_seq_to_refnum(env, v); + proxyissue12328_T_Err_Set(o, _v); +} + +JNIEXPORT jobject JNICALL +Java_issue12328_T_getErr(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + int32_t r0 = proxyissue12328_T_Err_Get(o); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class__error, proxy_class__error_cons); + return _r0; +} + diff --git a/bind/testdata/issue12328.java.golden b/bind/testdata/issue12328.java.golden new file mode 100644 index 000000000..957a67de6 --- /dev/null +++ b/bind/testdata/issue12328.java.golden @@ -0,0 +1,82 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class issue12328.T is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java issue12328 +package issue12328; + +import go.Seq; + +public final class T implements Seq.Proxy { + static { Issue12328.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + T(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public T() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public final native java.lang.Exception getErr(); + public final native void setErr(java.lang.Exception v); + + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof T)) { + return false; + } + T that = (T)o; + java.lang.Exception thisErr = getErr(); + java.lang.Exception thatErr = that.getErr(); + if (thisErr == null) { + if (thatErr != null) { + return false; + } + } else if (!thisErr.equals(thatErr)) { + return false; + } + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {getErr()}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("T").append("{"); + b.append("Err:").append(getErr()).append(","); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class issue12328.Issue12328 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java issue12328 +package issue12328; + +import go.Seq; + +public abstract class Issue12328 { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Issue12328() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + + +} diff --git a/bind/testdata/issue12328.java.h.golden b/bind/testdata/issue12328.java.h.golden new file mode 100644 index 000000000..ee1c5de51 --- /dev/null +++ b/bind/testdata/issue12328.java.h.golden @@ -0,0 +1,14 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java issue12328 + +#ifndef __Issue12328_H__ +#define __Issue12328_H__ + +#include + +extern jclass proxy_class_issue12328_T; +extern jmethodID proxy_class_issue12328_T_cons; +#endif diff --git a/bind/testdata/issue12328.objc.go.h.golden b/bind/testdata/issue12328.objc.go.h.golden new file mode 100644 index 000000000..2ae70c1c3 --- /dev/null +++ b/bind/testdata/issue12328.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to issue12328 Go package. +// gobind -lang=objc issue12328 +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_issue12328_H__ +#define __GO_issue12328_H__ + +#include +#include +#endif diff --git a/bind/testdata/issue12328.objc.h.golden b/bind/testdata/issue12328.objc.h.golden new file mode 100644 index 000000000..d81f50336 --- /dev/null +++ b/bind/testdata/issue12328.objc.h.golden @@ -0,0 +1,25 @@ +// Objective-C API for talking to issue12328 Go package. +// gobind -lang=objc issue12328 +// +// File is generated by gobind. Do not edit. + +#ifndef __Issue12328_H__ +#define __Issue12328_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class Issue12328T; + +@interface Issue12328T : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +@property (nonatomic) NSError* _Nullable err; +@end + +#endif diff --git a/bind/testdata/issue12328.objc.m.golden b/bind/testdata/issue12328.objc.m.golden new file mode 100644 index 000000000..08adc6af9 --- /dev/null +++ b/bind/testdata/issue12328.objc.m.golden @@ -0,0 +1,61 @@ +// Objective-C API for talking to issue12328 Go package. +// gobind -lang=objc issue12328 +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Issue12328.objc.h" + + +@implementation Issue12328T { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_issue12328_T()); + } + return self; +} + +- (NSError* _Nullable)err { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxyissue12328_T_Err_Get(refnum); + Universeerror* _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[Universeerror alloc] initWithRef:_r0_ref]; + } + } + return _r0; +} + +- (void)setErr:(NSError* _Nullable)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t _v; + if ([v conformsToProtocol:@protocol(goSeqRefInterface)]) { + id v_proxy = (id)(v); + _v = go_seq_go_to_refnum(v_proxy._ref); + } else { + _v = go_seq_to_refnum(v); + } + proxyissue12328_T_Err_Set(refnum, _v); +} + +@end + + + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/issue12403.go b/bind/testdata/issue12403.go new file mode 100644 index 000000000..bf5556765 --- /dev/null +++ b/bind/testdata/issue12403.go @@ -0,0 +1,6 @@ +package issue12403 + +type Parsable interface { + FromJSON(jstr string) string + ToJSON() (string, error) +} diff --git a/bind/testdata/issue12403.go.golden b/bind/testdata/issue12403.go.golden new file mode 100644 index 000000000..e979f5d03 --- /dev/null +++ b/bind/testdata/issue12403.go.golden @@ -0,0 +1,74 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package issue12403. +// +// autogenerated by gobind -lang=go issue12403 +package main + +/* +#include +#include +#include "seq.h" +#include "issue12403.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "issue12403" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyissue12403_Parsable_FromJSON +func proxyissue12403_Parsable_FromJSON(refnum C.int32_t, param_jstr C.nstring) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(issue12403.Parsable) + _param_jstr := decodeString(param_jstr) + res_0 := v.FromJSON(_param_jstr) + _res_0 := encodeString(res_0) + return _res_0 +} + +//export proxyissue12403_Parsable_ToJSON +func proxyissue12403_Parsable_ToJSON(refnum C.int32_t) (C.nstring, C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(issue12403.Parsable) + res_0, res_1 := v.ToJSON() + _res_0 := encodeString(res_0) + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 +} + +type proxyissue12403_Parsable _seq.Ref + +func (p *proxyissue12403_Parsable) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyissue12403_Parsable) FromJSON(param_jstr string) string { + _param_jstr := encodeString(param_jstr) + res := C.cproxyissue12403_Parsable_FromJSON(C.int32_t(p.Bind_proxy_refnum__()), _param_jstr) + _res := decodeString(res) + return _res +} + +func (p *proxyissue12403_Parsable) ToJSON() (string, error) { + res := C.cproxyissue12403_Parsable_ToJSON(C.int32_t(p.Bind_proxy_refnum__())) + res_0 := decodeString(res.r0) + var res_1 error + res_1_ref := _seq.FromRefNum(int32(res.r1)) + if res_1_ref != nil { + if res.r1 < 0 { // go object + res_1 = res_1_ref.Get().(error) + } else { // foreign object + res_1 = (*proxy_error)(res_1_ref) + } + } + return res_0, res_1 +} diff --git a/bind/testdata/issue12403.java.c.golden b/bind/testdata/issue12403.java.c.golden new file mode 100644 index 000000000..cffa17758 --- /dev/null +++ b/bind/testdata/issue12403.java.c.golden @@ -0,0 +1,75 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java issue12403 + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "issue12403.h" + +jclass proxy_class_issue12403_Parsable; +jmethodID proxy_class_issue12403_Parsable_cons; +static jmethodID mid_Parsable_FromJSON; +static jmethodID mid_Parsable_ToJSON; + +JNIEXPORT void JNICALL +Java_issue12403_Issue12403__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "issue12403/Issue12403$proxyParsable"); + proxy_class_issue12403_Parsable = (*env)->NewGlobalRef(env, clazz); + proxy_class_issue12403_Parsable_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "issue12403/Parsable"); + mid_Parsable_FromJSON = (*env)->GetMethodID(env, clazz, "fromJSON", "(Ljava/lang/String;)Ljava/lang/String;"); + mid_Parsable_ToJSON = (*env)->GetMethodID(env, clazz, "toJSON", "()Ljava/lang/String;"); + +} + +JNIEXPORT jstring JNICALL +Java_issue12403_Issue12403_00024proxyParsable_fromJSON(JNIEnv* env, jobject __this__, jstring jstr) { + int32_t o = go_seq_to_refnum_go(env, __this__); + nstring _jstr = go_seq_from_java_string(env, jstr); + nstring r0 = proxyissue12403_Parsable_FromJSON(o, _jstr); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +nstring cproxyissue12403_Parsable_FromJSON(int32_t refnum, nstring jstr) { + JNIEnv *env = go_seq_push_local_frame(1); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue12403_Parsable, proxy_class_issue12403_Parsable_cons); + jstring _jstr = go_seq_to_java_string(env, jstr); + jstring res = (*env)->CallObjectMethod(env, o, mid_Parsable_FromJSON, _jstr); + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT jstring JNICALL +Java_issue12403_Issue12403_00024proxyParsable_toJSON(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + struct proxyissue12403_Parsable_ToJSON_return res = proxyissue12403_Parsable_ToJSON(o); + jstring _r0 = go_seq_to_java_string(env, res.r0); + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +struct cproxyissue12403_Parsable_ToJSON_return cproxyissue12403_Parsable_ToJSON(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue12403_Parsable, proxy_class_issue12403_Parsable_cons); + jstring res = (*env)->CallObjectMethod(env, o, mid_Parsable_ToJSON); + jobject exc = go_seq_get_exception(env); + int32_t _exc = go_seq_to_refnum(env, exc); + if (exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + cproxyissue12403_Parsable_ToJSON_return sres = { + _res, _exc + }; + go_seq_pop_local_frame(env); + return sres; +} + diff --git a/bind/testdata/issue12403.java.golden b/bind/testdata/issue12403.java.golden new file mode 100644 index 000000000..db0e5fb40 --- /dev/null +++ b/bind/testdata/issue12403.java.golden @@ -0,0 +1,53 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class issue12403.Parsable is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java issue12403 +package issue12403; + +import go.Seq; + +public interface Parsable { + public String fromJSON(String jstr); + public String toJSON() throws Exception; + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class issue12403.Issue12403 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java issue12403 +package issue12403; + +import go.Seq; + +public abstract class Issue12403 { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Issue12403() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyParsable implements Seq.Proxy, Parsable { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyParsable(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native String fromJSON(String jstr); + public native String toJSON() throws Exception; + } + + +} diff --git a/bind/testdata/issue12403.java.h.golden b/bind/testdata/issue12403.java.h.golden new file mode 100644 index 000000000..783436bb4 --- /dev/null +++ b/bind/testdata/issue12403.java.h.golden @@ -0,0 +1,23 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java issue12403 + +#ifndef __Issue12403_H__ +#define __Issue12403_H__ + +#include + +extern jclass proxy_class_issue12403_Parsable; +extern jmethodID proxy_class_issue12403_Parsable_cons; + +nstring cproxyissue12403_Parsable_FromJSON(int32_t refnum, nstring jstr); + +typedef struct cproxyissue12403_Parsable_ToJSON_return { + nstring r0; + int32_t r1; +} cproxyissue12403_Parsable_ToJSON_return; +struct cproxyissue12403_Parsable_ToJSON_return cproxyissue12403_Parsable_ToJSON(int32_t refnum); + +#endif diff --git a/bind/testdata/issue12403.objc.go.h.golden b/bind/testdata/issue12403.objc.go.h.golden new file mode 100644 index 000000000..9bcfb0110 --- /dev/null +++ b/bind/testdata/issue12403.objc.go.h.golden @@ -0,0 +1,19 @@ +// Objective-C API for talking to issue12403 Go package. +// gobind -lang=objc issue12403 +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_issue12403_H__ +#define __GO_issue12403_H__ + +#include +#include +nstring cproxyissue12403_Parsable_FromJSON(int32_t refnum, nstring jstr); + +typedef struct cproxyissue12403_Parsable_ToJSON_return { + nstring r0; + int32_t r1; +} cproxyissue12403_Parsable_ToJSON_return; +struct cproxyissue12403_Parsable_ToJSON_return cproxyissue12403_Parsable_ToJSON(int32_t refnum); + +#endif diff --git a/bind/testdata/issue12403.objc.h.golden b/bind/testdata/issue12403.objc.h.golden new file mode 100644 index 000000000..8710fb7a4 --- /dev/null +++ b/bind/testdata/issue12403.objc.h.golden @@ -0,0 +1,33 @@ +// Objective-C API for talking to issue12403 Go package. +// gobind -lang=objc issue12403 +// +// File is generated by gobind. Do not edit. + +#ifndef __Issue12403_H__ +#define __Issue12403_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@protocol Issue12403Parsable; +@class Issue12403Parsable; + +@protocol Issue12403Parsable +- (NSString* _Nonnull)fromJSON:(NSString* _Nullable)jstr; +- (NSString* _Nonnull)toJSON:(NSError* _Nullable* _Nullable)error; +@end + +@class Issue12403Parsable; + +@interface Issue12403Parsable : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (NSString* _Nonnull)fromJSON:(NSString* _Nullable)jstr; +- (NSString* _Nonnull)toJSON:(NSError* _Nullable* _Nullable)error; +@end + +#endif diff --git a/bind/testdata/issue12403.objc.m.golden b/bind/testdata/issue12403.objc.m.golden new file mode 100644 index 000000000..4e9b14c07 --- /dev/null +++ b/bind/testdata/issue12403.objc.m.golden @@ -0,0 +1,91 @@ +// Objective-C API for talking to issue12403 Go package. +// gobind -lang=objc issue12403 +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Issue12403.objc.h" + +@implementation Issue12403Parsable { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (NSString* _Nonnull)fromJSON:(NSString* _Nullable)jstr { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _jstr = go_seq_from_objc_string(jstr); + nstring r0 = proxyissue12403_Parsable_FromJSON(refnum, _jstr); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; +} + +- (NSString* _Nonnull)toJSON:(NSError* _Nullable* _Nullable)error { + int32_t refnum = go_seq_go_to_refnum(self._ref); + struct proxyissue12403_Parsable_ToJSON_return res = proxyissue12403_Parsable_ToJSON(refnum); + NSString *_ret0_ = go_seq_to_objc_string(res.r0); + Universeerror* _error = nil; + GoSeqRef* _error_ref = go_seq_from_refnum(res.r1); + if (_error_ref != NULL) { + _error = _error_ref.obj; + if (_error == nil) { + _error = [[Universeerror alloc] initWithRef:_error_ref]; + } + } + if (_error != nil && error != nil) { + *error = _error; + } + if (_error != nil) { + return nil; + } + return _ret0_; +} + +@end + + + +nstring cproxyissue12403_Parsable_FromJSON(int32_t refnum, nstring jstr) { + @autoreleasepool { + Issue12403Parsable* o = go_seq_objc_from_refnum(refnum); + NSString *_jstr = go_seq_to_objc_string(jstr); + NSString* _Nonnull ret0_; + ret0_ = [o fromJSON:_jstr]; + nstring _ret0_ = go_seq_from_objc_string(ret0_); + return _ret0_; + } +} + +struct cproxyissue12403_Parsable_ToJSON_return cproxyissue12403_Parsable_ToJSON(int32_t refnum) { + @autoreleasepool { + Issue12403Parsable* o = go_seq_objc_from_refnum(refnum); + NSString* _Nonnull ret0_; + NSError* error = nil; + ret0_ = [o toJSON:&error]; + nstring _ret0_ = go_seq_from_objc_string(ret0_); + NSError *_error = nil; + if (error != nil) { + _error = error; + } + int32_t __error; + if ([_error conformsToProtocol:@protocol(goSeqRefInterface)]) { + id _error_proxy = (id)(_error); + __error = go_seq_go_to_refnum(_error_proxy._ref); + } else { + __error = go_seq_to_refnum(_error); + } + cproxyissue12403_Parsable_ToJSON_return _sres = { + _ret0_, __error + }; + return _sres; + } +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/issue29559.go b/bind/testdata/issue29559.go new file mode 100644 index 000000000..597847def --- /dev/null +++ b/bind/testdata/issue29559.go @@ -0,0 +1,5 @@ +package issue29559 + +type AString = string + +func TakesAString(s AString) {} diff --git a/bind/testdata/issue29559.go.golden b/bind/testdata/issue29559.go.golden new file mode 100644 index 000000000..70f1790bb --- /dev/null +++ b/bind/testdata/issue29559.go.golden @@ -0,0 +1,29 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package issue29559. +// +// autogenerated by gobind -lang=go issue29559 +package main + +/* +#include +#include +#include "seq.h" +#include "issue29559.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "issue29559" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyissue29559__TakesAString +func proxyissue29559__TakesAString(param_s C.nstring) { + _param_s := decodeString(param_s) + issue29559.TakesAString(_param_s) +} diff --git a/bind/testdata/issue29559.java.c.golden b/bind/testdata/issue29559.java.c.golden new file mode 100644 index 000000000..92df86009 --- /dev/null +++ b/bind/testdata/issue29559.java.c.golden @@ -0,0 +1,24 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java issue29559 + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "issue29559.h" + + +JNIEXPORT void JNICALL +Java_issue29559_Issue29559__1init(JNIEnv *env, jclass _unused) { + jclass clazz; +} + +JNIEXPORT void JNICALL +Java_issue29559_Issue29559_takesAString(JNIEnv* env, jclass _clazz, jstring s) { + nstring _s = go_seq_from_java_string(env, s); + proxyissue29559__TakesAString(_s); +} + diff --git a/bind/testdata/issue29559.java.golden b/bind/testdata/issue29559.java.golden new file mode 100644 index 000000000..a821edfc4 --- /dev/null +++ b/bind/testdata/issue29559.java.golden @@ -0,0 +1,26 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class issue29559.Issue29559 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java issue29559 +package issue29559; + +import go.Seq; + +public abstract class Issue29559 { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Issue29559() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + + + public static native void takesAString(String s); +} diff --git a/bind/testdata/issue29559.java.h.golden b/bind/testdata/issue29559.java.h.golden new file mode 100644 index 000000000..9e4f85ea3 --- /dev/null +++ b/bind/testdata/issue29559.java.h.golden @@ -0,0 +1,12 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java issue29559 + +#ifndef __Issue29559_H__ +#define __Issue29559_H__ + +#include + +#endif diff --git a/bind/testdata/issue29559.objc.go.h.golden b/bind/testdata/issue29559.objc.go.h.golden new file mode 100644 index 000000000..93771b48d --- /dev/null +++ b/bind/testdata/issue29559.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to issue29559 Go package. +// gobind -lang=objc issue29559 +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_issue29559_H__ +#define __GO_issue29559_H__ + +#include +#include +#endif diff --git a/bind/testdata/issue29559.objc.h.golden b/bind/testdata/issue29559.objc.h.golden new file mode 100644 index 000000000..6638e14fc --- /dev/null +++ b/bind/testdata/issue29559.objc.h.golden @@ -0,0 +1,16 @@ +// Objective-C API for talking to issue29559 Go package. +// gobind -lang=objc issue29559 +// +// File is generated by gobind. Do not edit. + +#ifndef __Issue29559_H__ +#define __Issue29559_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +FOUNDATION_EXPORT void Issue29559TakesAString(NSString* _Nullable s); + +#endif diff --git a/bind/testdata/issue29559.objc.m.golden b/bind/testdata/issue29559.objc.m.golden new file mode 100644 index 000000000..83a9b8dc7 --- /dev/null +++ b/bind/testdata/issue29559.objc.m.golden @@ -0,0 +1,19 @@ +// Objective-C API for talking to issue29559 Go package. +// gobind -lang=objc issue29559 +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Issue29559.objc.h" + + +void Issue29559TakesAString(NSString* _Nullable s) { + nstring _s = go_seq_from_objc_string(s); + proxyissue29559__TakesAString(_s); +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/java.go b/bind/testdata/java.go new file mode 100644 index 000000000..8550582ff --- /dev/null +++ b/bind/testdata/java.go @@ -0,0 +1,16 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package java + +import ( + "Java/java/lang" +) + +type ( + F lang.Float + L lang.Long + O lang.Object + R lang.Runnable +) diff --git a/bind/testdata/java.go.golden b/bind/testdata/java.go.golden new file mode 100644 index 000000000..2a47a1eca --- /dev/null +++ b/bind/testdata/java.go.golden @@ -0,0 +1,407 @@ +// Code generated by gobind. DO NOT EDIT. + +package Float + +import "Java" + +const _ = Java.Dummy + +const ( + MAX_VALUE = 3.4028235E38 + MIN_NORMAL = 1.17549435E-38 + MIN_VALUE = 1.4E-45 + MAX_EXPONENT = 127 + MIN_EXPONENT = -126 + SIZE = 32 + BYTES = 4 +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.lang.Float proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.lang.Float. + Cast func(v interface{}) Java.Java_lang_Float +) +// Code generated by gobind. DO NOT EDIT. + +package lang + +import "Java" + +const _ = Java.Dummy + +type Float Java.Java_lang_Float +type Long Java.Java_lang_Long +type Object Java.Java_lang_Object +type Runnable Java.Java_lang_Runnable +// Code generated by gobind. DO NOT EDIT. + +package Long + +import "Java" + +const _ = Java.Dummy + +const ( + MIN_VALUE = -9223372036854775808 + MAX_VALUE = 9223372036854775807 + SIZE = 64 + BYTES = 8 +) + +var ( + // Cast takes a proxy for a Java object and converts it to a java.lang.Long proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.lang.Long. + Cast func(v interface{}) Java.Java_lang_Long +) +// Code generated by gobind. DO NOT EDIT. + +package Object + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.lang.Object proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.lang.Object. + Cast func(v interface{}) Java.Java_lang_Object +) +// Code generated by gobind. DO NOT EDIT. + +package Runnable + +import "Java" + +const _ = Java.Dummy + +const () + +var ( + // Cast takes a proxy for a Java object and converts it to a java.lang.Runnable proxy. + // Cast panics if the argument is not a proxy or if the underlying object does + // not extend or implement java.lang.Runnable. + Cast func(v interface{}) Java.Java_lang_Runnable +) +// Code generated by gobind. DO NOT EDIT. + +package Java + +// Used to silence this package not used errors +const Dummy = 0 + +type Java_lang_Float interface { + ToString() string +} + +type Java_lang_Long interface { + ToString() string +} + +type Java_lang_Object interface { + ToString() string +} + +type Java_lang_Runnable interface { +} +// Code generated by gobind. DO NOT EDIT. + +package main + +/* +#include // for free() +#include +#include "seq.h" +#include "classes.h" +*/ +import "C" + +import ( + "Java" + _seq "golang.org/x/mobile/bind/seq" +) + +import "Java/java/lang/Float" +import "Java/java/lang/Long" +import "Java/java/lang/Object" +import "Java/java/lang/Runnable" +import "unsafe" + +import "reflect" + +import "fmt" + +type proxy interface{ Bind_proxy_refnum__() int32 } + +// Suppress unused package error + +var _ = _seq.FromRefNum + +const _ = Java.Dummy + +//export initClasses +func initClasses() { + C.init_proxies() + init_java_lang_Float() + init_java_lang_Long() + init_java_lang_Object() + init_java_lang_Runnable() +} + +var class_java_lang_Float C.jclass + +func init_java_lang_Float() { + cls := C.CString("java/lang/Float") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_lang_Float = clazz + Float.Cast = func(v interface{}) Java.Java_lang_Float { + t := reflect.TypeOf((*proxy_class_java_lang_Float)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_lang_Float) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_lang_Float) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.lang.Float")) + } + return cv + } +} + +type proxy_class_java_lang_Float _seq.Ref + +func (p *proxy_class_java_lang_Float) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_lang_Float) ToString() string { + res := C.cproxy_java_lang_Float_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_lang_Long C.jclass + +func init_java_lang_Long() { + cls := C.CString("java/lang/Long") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_lang_Long = clazz + Long.Cast = func(v interface{}) Java.Java_lang_Long { + t := reflect.TypeOf((*proxy_class_java_lang_Long)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_lang_Long) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_lang_Long) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.lang.Long")) + } + return cv + } +} + +type proxy_class_java_lang_Long _seq.Ref + +func (p *proxy_class_java_lang_Long) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_lang_Long) ToString() string { + res := C.cproxy_java_lang_Long_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_lang_Object C.jclass + +func init_java_lang_Object() { + cls := C.CString("java/lang/Object") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_lang_Object = clazz + Object.Cast = func(v interface{}) Java.Java_lang_Object { + t := reflect.TypeOf((*proxy_class_java_lang_Object)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_lang_Object) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_lang_Object) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.lang.Object")) + } + return cv + } +} + +type proxy_class_java_lang_Object _seq.Ref + +func (p *proxy_class_java_lang_Object) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_class_java_lang_Object) ToString() string { + res := C.cproxy_java_lang_Object_toString(C.jint(p.Bind_proxy_refnum__())) + _res := decodeString(res.res) + var _exc error + _exc_ref := _seq.FromRefNum(int32(res.exc)) + if _exc_ref != nil { + if res.exc < 0 { // go object + _exc = _exc_ref.Get().(error) + } else { // foreign object + _exc = (*proxy_error)(_exc_ref) + } + } + if _exc != nil { + panic(_exc) + } + return _res +} + +var class_java_lang_Runnable C.jclass + +func init_java_lang_Runnable() { + cls := C.CString("java/lang/Runnable") + clazz := C.go_seq_find_class(cls) + C.free(unsafe.Pointer(cls)) + if uintptr(clazz) == 0 { + return + } + class_java_lang_Runnable = clazz + Runnable.Cast = func(v interface{}) Java.Java_lang_Runnable { + t := reflect.TypeOf((*proxy_class_java_lang_Runnable)(nil)) + cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_java_lang_Runnable) + ref := C.jint(_seq.ToRefNum(cv)) + if C.go_seq_isinstanceof(ref, class_java_lang_Runnable) != 1 { + panic(fmt.Errorf("%T is not an instance of %s", v, "java.lang.Runnable")) + } + return cv + } +} + +type proxy_class_java_lang_Runnable _seq.Ref + +func (p *proxy_class_java_lang_Runnable) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package java. +// +// autogenerated by gobind -lang=go java +package main + +/* +#include +#include +#include "seq.h" +#include "java.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "java" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyjava_F_ToString +func proxyjava_F_ToString(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(java.F) + res_0 := v.ToString() + _res_0 := encodeString(res_0) + return _res_0 +} + +type proxyjava_F _seq.Ref + +func (p *proxyjava_F) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyjava_F) ToString() string { + res := C.cproxyjava_F_ToString(C.int32_t(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +//export proxyjava_L_ToString +func proxyjava_L_ToString(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(java.L) + res_0 := v.ToString() + _res_0 := encodeString(res_0) + return _res_0 +} + +type proxyjava_L _seq.Ref + +func (p *proxyjava_L) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyjava_L) ToString() string { + res := C.cproxyjava_L_ToString(C.int32_t(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +//export proxyjava_O_ToString +func proxyjava_O_ToString(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(java.O) + res_0 := v.ToString() + _res_0 := encodeString(res_0) + return _res_0 +} + +type proxyjava_O _seq.Ref + +func (p *proxyjava_O) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxyjava_O) ToString() string { + res := C.cproxyjava_O_ToString(C.int32_t(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +type proxyjava_R _seq.Ref + +func (p *proxyjava_R) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} diff --git a/bind/testdata/java.java.c.golden b/bind/testdata/java.java.c.golden new file mode 100644 index 000000000..e9d060318 --- /dev/null +++ b/bind/testdata/java.java.c.golden @@ -0,0 +1,191 @@ +// Code generated by gobind. DO NOT EDIT. + + +#include +#include "seq.h" +#include "classes.h" + +static jclass class_java_lang_Float; +static jmethodID m_java_lang_Float_toString; +static jclass class_java_lang_Long; +static jmethodID m_java_lang_Long_toString; +static jclass class_java_lang_Object; +static jmethodID m_java_lang_Object_toString; +static jclass class_java_lang_Runnable; + +void init_proxies() { + JNIEnv *env = go_seq_push_local_frame(4); + jclass clazz; + clazz = go_seq_find_class("java/lang/Float"); + if (clazz != NULL) { + class_java_lang_Float = (*env)->NewGlobalRef(env, clazz); + m_java_lang_Float_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/lang/Long"); + if (clazz != NULL) { + class_java_lang_Long = (*env)->NewGlobalRef(env, clazz); + m_java_lang_Long_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/lang/Object"); + if (clazz != NULL) { + class_java_lang_Object = (*env)->NewGlobalRef(env, clazz); + m_java_lang_Object_toString = go_seq_get_method_id(clazz, "toString", "()Ljava/lang/String;"); + } + clazz = go_seq_find_class("java/lang/Runnable"); + if (clazz != NULL) { + class_java_lang_Runnable = (*env)->NewGlobalRef(env, clazz); + } + go_seq_pop_local_frame(env); +} + +ret_nstring cproxy_java_lang_Float_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_lang_Float_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_lang_Long_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_lang_Long_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +ret_nstring cproxy_java_lang_Object_toString(jint this) { + JNIEnv *env = go_seq_push_local_frame(1); + // Must be a Java object + jobject _this = go_seq_from_refnum(env, this, NULL, NULL); + jstring res = (*env)->CallObjectMethod(env, _this, m_java_lang_Object_toString); + jobject _exc = go_seq_get_exception(env); + int32_t _exc_ref = go_seq_to_refnum(env, _exc); + if (_exc != NULL) { + res = NULL; + } + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + ret_nstring __res = {_res, _exc_ref}; + return __res; +} + +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java java + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "java.h" + +jclass proxy_class_java_F; +jmethodID proxy_class_java_F_cons; +static jmethodID mid_F_ToString; +jclass proxy_class_java_L; +jmethodID proxy_class_java_L_cons; +static jmethodID mid_L_ToString; +jclass proxy_class_java_O; +jmethodID proxy_class_java_O_cons; +static jmethodID mid_O_ToString; +jclass proxy_class_java_R; +jmethodID proxy_class_java_R_cons; + +JNIEXPORT void JNICALL +Java_java_Java__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "java/Java$proxyF"); + proxy_class_java_F = (*env)->NewGlobalRef(env, clazz); + proxy_class_java_F_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "java/F"); + mid_F_ToString = (*env)->GetMethodID(env, clazz, "toString", "()Ljava/lang/String;"); + + clazz = (*env)->FindClass(env, "java/Java$proxyL"); + proxy_class_java_L = (*env)->NewGlobalRef(env, clazz); + proxy_class_java_L_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "java/L"); + mid_L_ToString = (*env)->GetMethodID(env, clazz, "toString", "()Ljava/lang/String;"); + + clazz = (*env)->FindClass(env, "java/Java$proxyO"); + proxy_class_java_O = (*env)->NewGlobalRef(env, clazz); + proxy_class_java_O_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "java/O"); + mid_O_ToString = (*env)->GetMethodID(env, clazz, "toString", "()Ljava/lang/String;"); + + clazz = (*env)->FindClass(env, "java/Java$proxyR"); + proxy_class_java_R = (*env)->NewGlobalRef(env, clazz); + proxy_class_java_R_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "java/R"); + +} + +JNIEXPORT jstring JNICALL +Java_java_Java_00024proxyF_toString(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + nstring r0 = proxyjava_F_ToString(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +nstring cproxyjava_F_ToString(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_java_F, proxy_class_java_F_cons); + jstring res = (*env)->CallObjectMethod(env, o, mid_F_ToString); + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT jstring JNICALL +Java_java_Java_00024proxyL_toString(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + nstring r0 = proxyjava_L_ToString(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +nstring cproxyjava_L_ToString(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_java_L, proxy_class_java_L_cons); + jstring res = (*env)->CallObjectMethod(env, o, mid_L_ToString); + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT jstring JNICALL +Java_java_Java_00024proxyO_toString(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + nstring r0 = proxyjava_O_ToString(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +nstring cproxyjava_O_ToString(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_java_O, proxy_class_java_O_cons); + jstring res = (*env)->CallObjectMethod(env, o, mid_O_ToString); + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + return _res; +} + diff --git a/bind/testdata/java.java.golden b/bind/testdata/java.java.golden new file mode 100644 index 000000000..bd060d83c --- /dev/null +++ b/bind/testdata/java.java.golden @@ -0,0 +1,127 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class java.F is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java java +package java; + +import go.Seq; + +public interface F extends R { + public String toString(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class java.L is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java java +package java; + +import go.Seq; + +public interface L extends R { + public String toString(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class java.O is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java java +package java; + +import go.Seq; + +public interface O extends R { + public String toString(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class java.R is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java java +package java; + +import go.Seq; + +public interface R { + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class java.Java is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java java +package java; + +import go.Seq; + +public abstract class Java { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Java() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyF implements Seq.Proxy, F { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyF(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native String toString(); + } + private static final class proxyL implements Seq.Proxy, L { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyL(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native String toString(); + } + private static final class proxyO implements Seq.Proxy, O { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyO(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native String toString(); + } + private static final class proxyR implements Seq.Proxy, R { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyR(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + } + + +} diff --git a/bind/testdata/java.java.h.golden b/bind/testdata/java.java.h.golden new file mode 100644 index 000000000..f0ccef393 --- /dev/null +++ b/bind/testdata/java.java.h.golden @@ -0,0 +1,82 @@ +// Code generated by gobind. DO NOT EDIT. + + +#include +#include "seq.h" + +extern void init_proxies(); + +typedef struct ret_jint { + jint res; + jint exc; +} ret_jint; +typedef struct ret_jboolean { + jboolean res; + jint exc; +} ret_jboolean; +typedef struct ret_jshort { + jshort res; + jint exc; +} ret_jshort; +typedef struct ret_jchar { + jchar res; + jint exc; +} ret_jchar; +typedef struct ret_jbyte { + jbyte res; + jint exc; +} ret_jbyte; +typedef struct ret_jlong { + jlong res; + jint exc; +} ret_jlong; +typedef struct ret_jfloat { + jfloat res; + jint exc; +} ret_jfloat; +typedef struct ret_jdouble { + jdouble res; + jint exc; +} ret_jdouble; +typedef struct ret_nstring { + nstring res; + jint exc; +} ret_nstring; +typedef struct ret_nbyteslice { + nbyteslice res; + jint exc; +} ret_nbyteslice; + +extern ret_nstring cproxy_java_lang_Float_toString(jint this); +extern ret_nstring cproxy_java_lang_Long_toString(jint this); +extern ret_nstring cproxy_java_lang_Object_toString(jint this); +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java java + +#ifndef __Java_H__ +#define __Java_H__ + +#include + +extern jclass proxy_class_java_F; +extern jmethodID proxy_class_java_F_cons; + +nstring cproxyjava_F_ToString(int32_t refnum); + +extern jclass proxy_class_java_L; +extern jmethodID proxy_class_java_L_cons; + +nstring cproxyjava_L_ToString(int32_t refnum); + +extern jclass proxy_class_java_O; +extern jmethodID proxy_class_java_O_cons; + +nstring cproxyjava_O_ToString(int32_t refnum); + +extern jclass proxy_class_java_R; +extern jmethodID proxy_class_java_R_cons; + +#endif diff --git a/bind/testdata/keywords.go b/bind/testdata/keywords.go new file mode 100644 index 000000000..6a04f0bdd --- /dev/null +++ b/bind/testdata/keywords.go @@ -0,0 +1,66 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package keywords + +type KeywordCaller interface { + Abstract() + Assert() + Boolean() + Break() + Byte() + Case() + Catch() + Char() + Class() + Const() + Continue() + Default() + Do() + Double() + Else() + Enum() + Extends() + Final() + Finally() + Float() + For() + Goto() + If() + Implements() + Import() + Instanceof() + Int() + Interface() + Long() + Native() + New() + Package() + Private() + Protected() + Public() + Return() + Short() + Static() + Strictfp() + Super() + Switch() + Synchronized() + This() + Throw() + Throws() + Transient() + Try() + Void() + Volatile() + While() + False() + Null() + True() + Bool() + Nil() +} + +func Const(id string) {} +func Static(strictfp string) {} diff --git a/bind/testdata/keywords.go.golden b/bind/testdata/keywords.go.golden new file mode 100644 index 000000000..01e0738d8 --- /dev/null +++ b/bind/testdata/keywords.go.golden @@ -0,0 +1,646 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package keywords. +// +// autogenerated by gobind -lang=go keywords +package main + +/* +#include +#include +#include "seq.h" +#include "keywords.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "keywords" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxykeywords_KeywordCaller_Abstract +func proxykeywords_KeywordCaller_Abstract(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Abstract() +} + +//export proxykeywords_KeywordCaller_Assert +func proxykeywords_KeywordCaller_Assert(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Assert() +} + +//export proxykeywords_KeywordCaller_Bool +func proxykeywords_KeywordCaller_Bool(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Bool() +} + +//export proxykeywords_KeywordCaller_Boolean +func proxykeywords_KeywordCaller_Boolean(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Boolean() +} + +//export proxykeywords_KeywordCaller_Break +func proxykeywords_KeywordCaller_Break(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Break() +} + +//export proxykeywords_KeywordCaller_Byte +func proxykeywords_KeywordCaller_Byte(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Byte() +} + +//export proxykeywords_KeywordCaller_Case +func proxykeywords_KeywordCaller_Case(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Case() +} + +//export proxykeywords_KeywordCaller_Catch +func proxykeywords_KeywordCaller_Catch(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Catch() +} + +//export proxykeywords_KeywordCaller_Char +func proxykeywords_KeywordCaller_Char(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Char() +} + +//export proxykeywords_KeywordCaller_Class +func proxykeywords_KeywordCaller_Class(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Class() +} + +//export proxykeywords_KeywordCaller_Const +func proxykeywords_KeywordCaller_Const(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Const() +} + +//export proxykeywords_KeywordCaller_Continue +func proxykeywords_KeywordCaller_Continue(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Continue() +} + +//export proxykeywords_KeywordCaller_Default +func proxykeywords_KeywordCaller_Default(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Default() +} + +//export proxykeywords_KeywordCaller_Do +func proxykeywords_KeywordCaller_Do(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Do() +} + +//export proxykeywords_KeywordCaller_Double +func proxykeywords_KeywordCaller_Double(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Double() +} + +//export proxykeywords_KeywordCaller_Else +func proxykeywords_KeywordCaller_Else(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Else() +} + +//export proxykeywords_KeywordCaller_Enum +func proxykeywords_KeywordCaller_Enum(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Enum() +} + +//export proxykeywords_KeywordCaller_Extends +func proxykeywords_KeywordCaller_Extends(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Extends() +} + +//export proxykeywords_KeywordCaller_False +func proxykeywords_KeywordCaller_False(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.False() +} + +//export proxykeywords_KeywordCaller_Final +func proxykeywords_KeywordCaller_Final(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Final() +} + +//export proxykeywords_KeywordCaller_Finally +func proxykeywords_KeywordCaller_Finally(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Finally() +} + +//export proxykeywords_KeywordCaller_Float +func proxykeywords_KeywordCaller_Float(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Float() +} + +//export proxykeywords_KeywordCaller_For +func proxykeywords_KeywordCaller_For(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.For() +} + +//export proxykeywords_KeywordCaller_Goto +func proxykeywords_KeywordCaller_Goto(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Goto() +} + +//export proxykeywords_KeywordCaller_If +func proxykeywords_KeywordCaller_If(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.If() +} + +//export proxykeywords_KeywordCaller_Implements +func proxykeywords_KeywordCaller_Implements(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Implements() +} + +//export proxykeywords_KeywordCaller_Import +func proxykeywords_KeywordCaller_Import(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Import() +} + +//export proxykeywords_KeywordCaller_Instanceof +func proxykeywords_KeywordCaller_Instanceof(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Instanceof() +} + +//export proxykeywords_KeywordCaller_Int +func proxykeywords_KeywordCaller_Int(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Int() +} + +//export proxykeywords_KeywordCaller_Interface +func proxykeywords_KeywordCaller_Interface(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Interface() +} + +//export proxykeywords_KeywordCaller_Long +func proxykeywords_KeywordCaller_Long(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Long() +} + +//export proxykeywords_KeywordCaller_Native +func proxykeywords_KeywordCaller_Native(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Native() +} + +//export proxykeywords_KeywordCaller_New +func proxykeywords_KeywordCaller_New(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.New() +} + +//export proxykeywords_KeywordCaller_Nil +func proxykeywords_KeywordCaller_Nil(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Nil() +} + +//export proxykeywords_KeywordCaller_Null +func proxykeywords_KeywordCaller_Null(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Null() +} + +//export proxykeywords_KeywordCaller_Package +func proxykeywords_KeywordCaller_Package(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Package() +} + +//export proxykeywords_KeywordCaller_Private +func proxykeywords_KeywordCaller_Private(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Private() +} + +//export proxykeywords_KeywordCaller_Protected +func proxykeywords_KeywordCaller_Protected(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Protected() +} + +//export proxykeywords_KeywordCaller_Public +func proxykeywords_KeywordCaller_Public(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Public() +} + +//export proxykeywords_KeywordCaller_Return +func proxykeywords_KeywordCaller_Return(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Return() +} + +//export proxykeywords_KeywordCaller_Short +func proxykeywords_KeywordCaller_Short(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Short() +} + +//export proxykeywords_KeywordCaller_Static +func proxykeywords_KeywordCaller_Static(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Static() +} + +//export proxykeywords_KeywordCaller_Strictfp +func proxykeywords_KeywordCaller_Strictfp(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Strictfp() +} + +//export proxykeywords_KeywordCaller_Super +func proxykeywords_KeywordCaller_Super(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Super() +} + +//export proxykeywords_KeywordCaller_Switch +func proxykeywords_KeywordCaller_Switch(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Switch() +} + +//export proxykeywords_KeywordCaller_Synchronized +func proxykeywords_KeywordCaller_Synchronized(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Synchronized() +} + +//export proxykeywords_KeywordCaller_This +func proxykeywords_KeywordCaller_This(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.This() +} + +//export proxykeywords_KeywordCaller_Throw +func proxykeywords_KeywordCaller_Throw(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Throw() +} + +//export proxykeywords_KeywordCaller_Throws +func proxykeywords_KeywordCaller_Throws(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Throws() +} + +//export proxykeywords_KeywordCaller_Transient +func proxykeywords_KeywordCaller_Transient(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Transient() +} + +//export proxykeywords_KeywordCaller_True +func proxykeywords_KeywordCaller_True(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.True() +} + +//export proxykeywords_KeywordCaller_Try +func proxykeywords_KeywordCaller_Try(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Try() +} + +//export proxykeywords_KeywordCaller_Void +func proxykeywords_KeywordCaller_Void(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Void() +} + +//export proxykeywords_KeywordCaller_Volatile +func proxykeywords_KeywordCaller_Volatile(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.Volatile() +} + +//export proxykeywords_KeywordCaller_While +func proxykeywords_KeywordCaller_While(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(keywords.KeywordCaller) + v.While() +} + +type proxykeywords_KeywordCaller _seq.Ref + +func (p *proxykeywords_KeywordCaller) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxykeywords_KeywordCaller) Abstract() { + C.cproxykeywords_KeywordCaller_Abstract(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Assert() { + C.cproxykeywords_KeywordCaller_Assert(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Bool() { + C.cproxykeywords_KeywordCaller_Bool(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Boolean() { + C.cproxykeywords_KeywordCaller_Boolean(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Break() { + C.cproxykeywords_KeywordCaller_Break(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Byte() { + C.cproxykeywords_KeywordCaller_Byte(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Case() { + C.cproxykeywords_KeywordCaller_Case(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Catch() { + C.cproxykeywords_KeywordCaller_Catch(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Char() { + C.cproxykeywords_KeywordCaller_Char(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Class() { + C.cproxykeywords_KeywordCaller_Class(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Const() { + C.cproxykeywords_KeywordCaller_Const(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Continue() { + C.cproxykeywords_KeywordCaller_Continue(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Default() { + C.cproxykeywords_KeywordCaller_Default(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Do() { + C.cproxykeywords_KeywordCaller_Do(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Double() { + C.cproxykeywords_KeywordCaller_Double(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Else() { + C.cproxykeywords_KeywordCaller_Else(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Enum() { + C.cproxykeywords_KeywordCaller_Enum(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Extends() { + C.cproxykeywords_KeywordCaller_Extends(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) False() { + C.cproxykeywords_KeywordCaller_False(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Final() { + C.cproxykeywords_KeywordCaller_Final(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Finally() { + C.cproxykeywords_KeywordCaller_Finally(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Float() { + C.cproxykeywords_KeywordCaller_Float(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) For() { + C.cproxykeywords_KeywordCaller_For(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Goto() { + C.cproxykeywords_KeywordCaller_Goto(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) If() { + C.cproxykeywords_KeywordCaller_If(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Implements() { + C.cproxykeywords_KeywordCaller_Implements(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Import() { + C.cproxykeywords_KeywordCaller_Import(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Instanceof() { + C.cproxykeywords_KeywordCaller_Instanceof(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Int() { + C.cproxykeywords_KeywordCaller_Int(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Interface() { + C.cproxykeywords_KeywordCaller_Interface(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Long() { + C.cproxykeywords_KeywordCaller_Long(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Native() { + C.cproxykeywords_KeywordCaller_Native(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) New() { + C.cproxykeywords_KeywordCaller_New(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Nil() { + C.cproxykeywords_KeywordCaller_Nil(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Null() { + C.cproxykeywords_KeywordCaller_Null(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Package() { + C.cproxykeywords_KeywordCaller_Package(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Private() { + C.cproxykeywords_KeywordCaller_Private(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Protected() { + C.cproxykeywords_KeywordCaller_Protected(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Public() { + C.cproxykeywords_KeywordCaller_Public(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Return() { + C.cproxykeywords_KeywordCaller_Return(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Short() { + C.cproxykeywords_KeywordCaller_Short(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Static() { + C.cproxykeywords_KeywordCaller_Static(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Strictfp() { + C.cproxykeywords_KeywordCaller_Strictfp(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Super() { + C.cproxykeywords_KeywordCaller_Super(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Switch() { + C.cproxykeywords_KeywordCaller_Switch(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Synchronized() { + C.cproxykeywords_KeywordCaller_Synchronized(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) This() { + C.cproxykeywords_KeywordCaller_This(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Throw() { + C.cproxykeywords_KeywordCaller_Throw(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Throws() { + C.cproxykeywords_KeywordCaller_Throws(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Transient() { + C.cproxykeywords_KeywordCaller_Transient(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) True() { + C.cproxykeywords_KeywordCaller_True(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Try() { + C.cproxykeywords_KeywordCaller_Try(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Void() { + C.cproxykeywords_KeywordCaller_Void(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) Volatile() { + C.cproxykeywords_KeywordCaller_Volatile(C.int32_t(p.Bind_proxy_refnum__())) +} + +func (p *proxykeywords_KeywordCaller) While() { + C.cproxykeywords_KeywordCaller_While(C.int32_t(p.Bind_proxy_refnum__())) +} + +//export proxykeywords__Const +func proxykeywords__Const(param_id C.nstring) { + _param_id := decodeString(param_id) + keywords.Const(_param_id) +} + +//export proxykeywords__Static +func proxykeywords__Static(param_strictfp C.nstring) { + _param_strictfp := decodeString(param_strictfp) + keywords.Static(_param_strictfp) +} diff --git a/bind/testdata/keywords.java.c.golden b/bind/testdata/keywords.java.c.golden new file mode 100644 index 000000000..82e103533 --- /dev/null +++ b/bind/testdata/keywords.java.c.golden @@ -0,0 +1,862 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java keywords + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "keywords.h" + +jclass proxy_class_keywords_KeywordCaller; +jmethodID proxy_class_keywords_KeywordCaller_cons; +static jmethodID mid_KeywordCaller_Abstract; +static jmethodID mid_KeywordCaller_Assert; +static jmethodID mid_KeywordCaller_Bool; +static jmethodID mid_KeywordCaller_Boolean; +static jmethodID mid_KeywordCaller_Break; +static jmethodID mid_KeywordCaller_Byte; +static jmethodID mid_KeywordCaller_Case; +static jmethodID mid_KeywordCaller_Catch; +static jmethodID mid_KeywordCaller_Char; +static jmethodID mid_KeywordCaller_Class; +static jmethodID mid_KeywordCaller_Const; +static jmethodID mid_KeywordCaller_Continue; +static jmethodID mid_KeywordCaller_Default; +static jmethodID mid_KeywordCaller_Do; +static jmethodID mid_KeywordCaller_Double; +static jmethodID mid_KeywordCaller_Else; +static jmethodID mid_KeywordCaller_Enum; +static jmethodID mid_KeywordCaller_Extends; +static jmethodID mid_KeywordCaller_False; +static jmethodID mid_KeywordCaller_Final; +static jmethodID mid_KeywordCaller_Finally; +static jmethodID mid_KeywordCaller_Float; +static jmethodID mid_KeywordCaller_For; +static jmethodID mid_KeywordCaller_Goto; +static jmethodID mid_KeywordCaller_If; +static jmethodID mid_KeywordCaller_Implements; +static jmethodID mid_KeywordCaller_Import; +static jmethodID mid_KeywordCaller_Instanceof; +static jmethodID mid_KeywordCaller_Int; +static jmethodID mid_KeywordCaller_Interface; +static jmethodID mid_KeywordCaller_Long; +static jmethodID mid_KeywordCaller_Native; +static jmethodID mid_KeywordCaller_New; +static jmethodID mid_KeywordCaller_Nil; +static jmethodID mid_KeywordCaller_Null; +static jmethodID mid_KeywordCaller_Package; +static jmethodID mid_KeywordCaller_Private; +static jmethodID mid_KeywordCaller_Protected; +static jmethodID mid_KeywordCaller_Public; +static jmethodID mid_KeywordCaller_Return; +static jmethodID mid_KeywordCaller_Short; +static jmethodID mid_KeywordCaller_Static; +static jmethodID mid_KeywordCaller_Strictfp; +static jmethodID mid_KeywordCaller_Super; +static jmethodID mid_KeywordCaller_Switch; +static jmethodID mid_KeywordCaller_Synchronized; +static jmethodID mid_KeywordCaller_This; +static jmethodID mid_KeywordCaller_Throw; +static jmethodID mid_KeywordCaller_Throws; +static jmethodID mid_KeywordCaller_Transient; +static jmethodID mid_KeywordCaller_True; +static jmethodID mid_KeywordCaller_Try; +static jmethodID mid_KeywordCaller_Void; +static jmethodID mid_KeywordCaller_Volatile; +static jmethodID mid_KeywordCaller_While; + +JNIEXPORT void JNICALL +Java_keywords_Keywords__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "keywords/Keywords$proxyKeywordCaller"); + proxy_class_keywords_KeywordCaller = (*env)->NewGlobalRef(env, clazz); + proxy_class_keywords_KeywordCaller_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "keywords/KeywordCaller"); + mid_KeywordCaller_Abstract = (*env)->GetMethodID(env, clazz, "abstract_", "()V"); + mid_KeywordCaller_Assert = (*env)->GetMethodID(env, clazz, "assert_", "()V"); + mid_KeywordCaller_Bool = (*env)->GetMethodID(env, clazz, "bool", "()V"); + mid_KeywordCaller_Boolean = (*env)->GetMethodID(env, clazz, "boolean_", "()V"); + mid_KeywordCaller_Break = (*env)->GetMethodID(env, clazz, "break_", "()V"); + mid_KeywordCaller_Byte = (*env)->GetMethodID(env, clazz, "byte_", "()V"); + mid_KeywordCaller_Case = (*env)->GetMethodID(env, clazz, "case_", "()V"); + mid_KeywordCaller_Catch = (*env)->GetMethodID(env, clazz, "catch_", "()V"); + mid_KeywordCaller_Char = (*env)->GetMethodID(env, clazz, "char_", "()V"); + mid_KeywordCaller_Class = (*env)->GetMethodID(env, clazz, "class_", "()V"); + mid_KeywordCaller_Const = (*env)->GetMethodID(env, clazz, "const_", "()V"); + mid_KeywordCaller_Continue = (*env)->GetMethodID(env, clazz, "continue_", "()V"); + mid_KeywordCaller_Default = (*env)->GetMethodID(env, clazz, "default_", "()V"); + mid_KeywordCaller_Do = (*env)->GetMethodID(env, clazz, "do_", "()V"); + mid_KeywordCaller_Double = (*env)->GetMethodID(env, clazz, "double_", "()V"); + mid_KeywordCaller_Else = (*env)->GetMethodID(env, clazz, "else_", "()V"); + mid_KeywordCaller_Enum = (*env)->GetMethodID(env, clazz, "enum_", "()V"); + mid_KeywordCaller_Extends = (*env)->GetMethodID(env, clazz, "extends_", "()V"); + mid_KeywordCaller_False = (*env)->GetMethodID(env, clazz, "false_", "()V"); + mid_KeywordCaller_Final = (*env)->GetMethodID(env, clazz, "final_", "()V"); + mid_KeywordCaller_Finally = (*env)->GetMethodID(env, clazz, "finally_", "()V"); + mid_KeywordCaller_Float = (*env)->GetMethodID(env, clazz, "float_", "()V"); + mid_KeywordCaller_For = (*env)->GetMethodID(env, clazz, "for_", "()V"); + mid_KeywordCaller_Goto = (*env)->GetMethodID(env, clazz, "goto_", "()V"); + mid_KeywordCaller_If = (*env)->GetMethodID(env, clazz, "if_", "()V"); + mid_KeywordCaller_Implements = (*env)->GetMethodID(env, clazz, "implements_", "()V"); + mid_KeywordCaller_Import = (*env)->GetMethodID(env, clazz, "import_", "()V"); + mid_KeywordCaller_Instanceof = (*env)->GetMethodID(env, clazz, "instanceof_", "()V"); + mid_KeywordCaller_Int = (*env)->GetMethodID(env, clazz, "int_", "()V"); + mid_KeywordCaller_Interface = (*env)->GetMethodID(env, clazz, "interface_", "()V"); + mid_KeywordCaller_Long = (*env)->GetMethodID(env, clazz, "long_", "()V"); + mid_KeywordCaller_Native = (*env)->GetMethodID(env, clazz, "native_", "()V"); + mid_KeywordCaller_New = (*env)->GetMethodID(env, clazz, "new_", "()V"); + mid_KeywordCaller_Nil = (*env)->GetMethodID(env, clazz, "nil", "()V"); + mid_KeywordCaller_Null = (*env)->GetMethodID(env, clazz, "null_", "()V"); + mid_KeywordCaller_Package = (*env)->GetMethodID(env, clazz, "package_", "()V"); + mid_KeywordCaller_Private = (*env)->GetMethodID(env, clazz, "private_", "()V"); + mid_KeywordCaller_Protected = (*env)->GetMethodID(env, clazz, "protected_", "()V"); + mid_KeywordCaller_Public = (*env)->GetMethodID(env, clazz, "public_", "()V"); + mid_KeywordCaller_Return = (*env)->GetMethodID(env, clazz, "return_", "()V"); + mid_KeywordCaller_Short = (*env)->GetMethodID(env, clazz, "short_", "()V"); + mid_KeywordCaller_Static = (*env)->GetMethodID(env, clazz, "static_", "()V"); + mid_KeywordCaller_Strictfp = (*env)->GetMethodID(env, clazz, "strictfp_", "()V"); + mid_KeywordCaller_Super = (*env)->GetMethodID(env, clazz, "super_", "()V"); + mid_KeywordCaller_Switch = (*env)->GetMethodID(env, clazz, "switch_", "()V"); + mid_KeywordCaller_Synchronized = (*env)->GetMethodID(env, clazz, "synchronized_", "()V"); + mid_KeywordCaller_This = (*env)->GetMethodID(env, clazz, "this_", "()V"); + mid_KeywordCaller_Throw = (*env)->GetMethodID(env, clazz, "throw_", "()V"); + mid_KeywordCaller_Throws = (*env)->GetMethodID(env, clazz, "throws_", "()V"); + mid_KeywordCaller_Transient = (*env)->GetMethodID(env, clazz, "transient_", "()V"); + mid_KeywordCaller_True = (*env)->GetMethodID(env, clazz, "true_", "()V"); + mid_KeywordCaller_Try = (*env)->GetMethodID(env, clazz, "try_", "()V"); + mid_KeywordCaller_Void = (*env)->GetMethodID(env, clazz, "void_", "()V"); + mid_KeywordCaller_Volatile = (*env)->GetMethodID(env, clazz, "volatile_", "()V"); + mid_KeywordCaller_While = (*env)->GetMethodID(env, clazz, "while_", "()V"); + +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_const_1(JNIEnv* env, jclass _clazz, jstring id) { + nstring _id = go_seq_from_java_string(env, id); + proxykeywords__Const(_id); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_static_1(JNIEnv* env, jclass _clazz, jstring strictfp_) { + nstring _strictfp_ = go_seq_from_java_string(env, strictfp_); + proxykeywords__Static(_strictfp_); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_abstract_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Abstract(o); +} + +void cproxykeywords_KeywordCaller_Abstract(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Abstract); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_assert_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Assert(o); +} + +void cproxykeywords_KeywordCaller_Assert(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Assert); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_bool(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Bool(o); +} + +void cproxykeywords_KeywordCaller_Bool(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Bool); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_boolean_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Boolean(o); +} + +void cproxykeywords_KeywordCaller_Boolean(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Boolean); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_break_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Break(o); +} + +void cproxykeywords_KeywordCaller_Break(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Break); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_byte_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Byte(o); +} + +void cproxykeywords_KeywordCaller_Byte(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Byte); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_case_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Case(o); +} + +void cproxykeywords_KeywordCaller_Case(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Case); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_catch_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Catch(o); +} + +void cproxykeywords_KeywordCaller_Catch(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Catch); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_char_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Char(o); +} + +void cproxykeywords_KeywordCaller_Char(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Char); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_class_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Class(o); +} + +void cproxykeywords_KeywordCaller_Class(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Class); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_const_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Const(o); +} + +void cproxykeywords_KeywordCaller_Const(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Const); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_continue_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Continue(o); +} + +void cproxykeywords_KeywordCaller_Continue(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Continue); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_default_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Default(o); +} + +void cproxykeywords_KeywordCaller_Default(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Default); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_do_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Do(o); +} + +void cproxykeywords_KeywordCaller_Do(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Do); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_double_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Double(o); +} + +void cproxykeywords_KeywordCaller_Double(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Double); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_else_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Else(o); +} + +void cproxykeywords_KeywordCaller_Else(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Else); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_enum_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Enum(o); +} + +void cproxykeywords_KeywordCaller_Enum(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Enum); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_extends_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Extends(o); +} + +void cproxykeywords_KeywordCaller_Extends(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Extends); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_false_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_False(o); +} + +void cproxykeywords_KeywordCaller_False(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_False); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_final_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Final(o); +} + +void cproxykeywords_KeywordCaller_Final(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Final); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_finally_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Finally(o); +} + +void cproxykeywords_KeywordCaller_Finally(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Finally); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_float_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Float(o); +} + +void cproxykeywords_KeywordCaller_Float(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Float); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_for_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_For(o); +} + +void cproxykeywords_KeywordCaller_For(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_For); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_goto_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Goto(o); +} + +void cproxykeywords_KeywordCaller_Goto(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Goto); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_if_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_If(o); +} + +void cproxykeywords_KeywordCaller_If(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_If); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_implements_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Implements(o); +} + +void cproxykeywords_KeywordCaller_Implements(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Implements); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_import_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Import(o); +} + +void cproxykeywords_KeywordCaller_Import(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Import); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_instanceof_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Instanceof(o); +} + +void cproxykeywords_KeywordCaller_Instanceof(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Instanceof); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_int_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Int(o); +} + +void cproxykeywords_KeywordCaller_Int(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Int); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_interface_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Interface(o); +} + +void cproxykeywords_KeywordCaller_Interface(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Interface); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_long_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Long(o); +} + +void cproxykeywords_KeywordCaller_Long(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Long); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_native_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Native(o); +} + +void cproxykeywords_KeywordCaller_Native(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Native); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_new_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_New(o); +} + +void cproxykeywords_KeywordCaller_New(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_New); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_nil(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Nil(o); +} + +void cproxykeywords_KeywordCaller_Nil(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Nil); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_null_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Null(o); +} + +void cproxykeywords_KeywordCaller_Null(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Null); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_package_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Package(o); +} + +void cproxykeywords_KeywordCaller_Package(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Package); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_private_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Private(o); +} + +void cproxykeywords_KeywordCaller_Private(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Private); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_protected_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Protected(o); +} + +void cproxykeywords_KeywordCaller_Protected(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Protected); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_public_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Public(o); +} + +void cproxykeywords_KeywordCaller_Public(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Public); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_return_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Return(o); +} + +void cproxykeywords_KeywordCaller_Return(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Return); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_short_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Short(o); +} + +void cproxykeywords_KeywordCaller_Short(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Short); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_static_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Static(o); +} + +void cproxykeywords_KeywordCaller_Static(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Static); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_strictfp_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Strictfp(o); +} + +void cproxykeywords_KeywordCaller_Strictfp(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Strictfp); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_super_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Super(o); +} + +void cproxykeywords_KeywordCaller_Super(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Super); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_switch_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Switch(o); +} + +void cproxykeywords_KeywordCaller_Switch(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Switch); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_synchronized_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Synchronized(o); +} + +void cproxykeywords_KeywordCaller_Synchronized(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Synchronized); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_this_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_This(o); +} + +void cproxykeywords_KeywordCaller_This(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_This); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_throw_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Throw(o); +} + +void cproxykeywords_KeywordCaller_Throw(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Throw); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_throws_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Throws(o); +} + +void cproxykeywords_KeywordCaller_Throws(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Throws); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_transient_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Transient(o); +} + +void cproxykeywords_KeywordCaller_Transient(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Transient); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_true_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_True(o); +} + +void cproxykeywords_KeywordCaller_True(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_True); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_try_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Try(o); +} + +void cproxykeywords_KeywordCaller_Try(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Try); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_void_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Void(o); +} + +void cproxykeywords_KeywordCaller_Void(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Void); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_volatile_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_Volatile(o); +} + +void cproxykeywords_KeywordCaller_Volatile(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_Volatile); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_keywords_Keywords_00024proxyKeywordCaller_while_1(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxykeywords_KeywordCaller_While(o); +} + +void cproxykeywords_KeywordCaller_While(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_keywords_KeywordCaller, proxy_class_keywords_KeywordCaller_cons); + (*env)->CallVoidMethod(env, o, mid_KeywordCaller_While); + go_seq_pop_local_frame(env); +} + diff --git a/bind/testdata/keywords.java.golden b/bind/testdata/keywords.java.golden new file mode 100644 index 000000000..3db5202f0 --- /dev/null +++ b/bind/testdata/keywords.java.golden @@ -0,0 +1,161 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class keywords.KeywordCaller is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java keywords +package keywords; + +import go.Seq; + +public interface KeywordCaller { + public void abstract_(); + public void assert_(); + public void bool(); + public void boolean_(); + public void break_(); + public void byte_(); + public void case_(); + public void catch_(); + public void char_(); + public void class_(); + public void const_(); + public void continue_(); + public void default_(); + public void do_(); + public void double_(); + public void else_(); + public void enum_(); + public void extends_(); + public void false_(); + public void final_(); + public void finally_(); + public void float_(); + public void for_(); + public void goto_(); + public void if_(); + public void implements_(); + public void import_(); + public void instanceof_(); + public void int_(); + public void interface_(); + public void long_(); + public void native_(); + public void new_(); + public void nil(); + public void null_(); + public void package_(); + public void private_(); + public void protected_(); + public void public_(); + public void return_(); + public void short_(); + public void static_(); + public void strictfp_(); + public void super_(); + public void switch_(); + public void synchronized_(); + public void this_(); + public void throw_(); + public void throws_(); + public void transient_(); + public void true_(); + public void try_(); + public void void_(); + public void volatile_(); + public void while_(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class keywords.Keywords is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java keywords +package keywords; + +import go.Seq; + +public abstract class Keywords { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Keywords() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyKeywordCaller implements Seq.Proxy, KeywordCaller { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyKeywordCaller(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void abstract_(); + public native void assert_(); + public native void bool(); + public native void boolean_(); + public native void break_(); + public native void byte_(); + public native void case_(); + public native void catch_(); + public native void char_(); + public native void class_(); + public native void const_(); + public native void continue_(); + public native void default_(); + public native void do_(); + public native void double_(); + public native void else_(); + public native void enum_(); + public native void extends_(); + public native void false_(); + public native void final_(); + public native void finally_(); + public native void float_(); + public native void for_(); + public native void goto_(); + public native void if_(); + public native void implements_(); + public native void import_(); + public native void instanceof_(); + public native void int_(); + public native void interface_(); + public native void long_(); + public native void native_(); + public native void new_(); + public native void nil(); + public native void null_(); + public native void package_(); + public native void private_(); + public native void protected_(); + public native void public_(); + public native void return_(); + public native void short_(); + public native void static_(); + public native void strictfp_(); + public native void super_(); + public native void switch_(); + public native void synchronized_(); + public native void this_(); + public native void throw_(); + public native void throws_(); + public native void transient_(); + public native void true_(); + public native void try_(); + public native void void_(); + public native void volatile_(); + public native void while_(); + } + + + public static native void const_(String id); + public static native void static_(String strictfp_); +} diff --git a/bind/testdata/keywords.java.h.golden b/bind/testdata/keywords.java.h.golden new file mode 100644 index 000000000..7eee7739f --- /dev/null +++ b/bind/testdata/keywords.java.h.golden @@ -0,0 +1,125 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java keywords + +#ifndef __Keywords_H__ +#define __Keywords_H__ + +#include + +extern jclass proxy_class_keywords_KeywordCaller; +extern jmethodID proxy_class_keywords_KeywordCaller_cons; + +void cproxykeywords_KeywordCaller_Abstract(int32_t refnum); + +void cproxykeywords_KeywordCaller_Assert(int32_t refnum); + +void cproxykeywords_KeywordCaller_Bool(int32_t refnum); + +void cproxykeywords_KeywordCaller_Boolean(int32_t refnum); + +void cproxykeywords_KeywordCaller_Break(int32_t refnum); + +void cproxykeywords_KeywordCaller_Byte(int32_t refnum); + +void cproxykeywords_KeywordCaller_Case(int32_t refnum); + +void cproxykeywords_KeywordCaller_Catch(int32_t refnum); + +void cproxykeywords_KeywordCaller_Char(int32_t refnum); + +void cproxykeywords_KeywordCaller_Class(int32_t refnum); + +void cproxykeywords_KeywordCaller_Const(int32_t refnum); + +void cproxykeywords_KeywordCaller_Continue(int32_t refnum); + +void cproxykeywords_KeywordCaller_Default(int32_t refnum); + +void cproxykeywords_KeywordCaller_Do(int32_t refnum); + +void cproxykeywords_KeywordCaller_Double(int32_t refnum); + +void cproxykeywords_KeywordCaller_Else(int32_t refnum); + +void cproxykeywords_KeywordCaller_Enum(int32_t refnum); + +void cproxykeywords_KeywordCaller_Extends(int32_t refnum); + +void cproxykeywords_KeywordCaller_False(int32_t refnum); + +void cproxykeywords_KeywordCaller_Final(int32_t refnum); + +void cproxykeywords_KeywordCaller_Finally(int32_t refnum); + +void cproxykeywords_KeywordCaller_Float(int32_t refnum); + +void cproxykeywords_KeywordCaller_For(int32_t refnum); + +void cproxykeywords_KeywordCaller_Goto(int32_t refnum); + +void cproxykeywords_KeywordCaller_If(int32_t refnum); + +void cproxykeywords_KeywordCaller_Implements(int32_t refnum); + +void cproxykeywords_KeywordCaller_Import(int32_t refnum); + +void cproxykeywords_KeywordCaller_Instanceof(int32_t refnum); + +void cproxykeywords_KeywordCaller_Int(int32_t refnum); + +void cproxykeywords_KeywordCaller_Interface(int32_t refnum); + +void cproxykeywords_KeywordCaller_Long(int32_t refnum); + +void cproxykeywords_KeywordCaller_Native(int32_t refnum); + +void cproxykeywords_KeywordCaller_New(int32_t refnum); + +void cproxykeywords_KeywordCaller_Nil(int32_t refnum); + +void cproxykeywords_KeywordCaller_Null(int32_t refnum); + +void cproxykeywords_KeywordCaller_Package(int32_t refnum); + +void cproxykeywords_KeywordCaller_Private(int32_t refnum); + +void cproxykeywords_KeywordCaller_Protected(int32_t refnum); + +void cproxykeywords_KeywordCaller_Public(int32_t refnum); + +void cproxykeywords_KeywordCaller_Return(int32_t refnum); + +void cproxykeywords_KeywordCaller_Short(int32_t refnum); + +void cproxykeywords_KeywordCaller_Static(int32_t refnum); + +void cproxykeywords_KeywordCaller_Strictfp(int32_t refnum); + +void cproxykeywords_KeywordCaller_Super(int32_t refnum); + +void cproxykeywords_KeywordCaller_Switch(int32_t refnum); + +void cproxykeywords_KeywordCaller_Synchronized(int32_t refnum); + +void cproxykeywords_KeywordCaller_This(int32_t refnum); + +void cproxykeywords_KeywordCaller_Throw(int32_t refnum); + +void cproxykeywords_KeywordCaller_Throws(int32_t refnum); + +void cproxykeywords_KeywordCaller_Transient(int32_t refnum); + +void cproxykeywords_KeywordCaller_True(int32_t refnum); + +void cproxykeywords_KeywordCaller_Try(int32_t refnum); + +void cproxykeywords_KeywordCaller_Void(int32_t refnum); + +void cproxykeywords_KeywordCaller_Volatile(int32_t refnum); + +void cproxykeywords_KeywordCaller_While(int32_t refnum); + +#endif diff --git a/bind/testdata/keywords.objc.go.h.golden b/bind/testdata/keywords.objc.go.h.golden new file mode 100644 index 000000000..c4a7d5d84 --- /dev/null +++ b/bind/testdata/keywords.objc.go.h.golden @@ -0,0 +1,121 @@ +// Objective-C API for talking to keywords Go package. +// gobind -lang=objc keywords +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_keywords_H__ +#define __GO_keywords_H__ + +#include +#include +void cproxykeywords_KeywordCaller_Abstract(int32_t refnum); + +void cproxykeywords_KeywordCaller_Assert(int32_t refnum); + +void cproxykeywords_KeywordCaller_Bool(int32_t refnum); + +void cproxykeywords_KeywordCaller_Boolean(int32_t refnum); + +void cproxykeywords_KeywordCaller_Break(int32_t refnum); + +void cproxykeywords_KeywordCaller_Byte(int32_t refnum); + +void cproxykeywords_KeywordCaller_Case(int32_t refnum); + +void cproxykeywords_KeywordCaller_Catch(int32_t refnum); + +void cproxykeywords_KeywordCaller_Char(int32_t refnum); + +void cproxykeywords_KeywordCaller_Class(int32_t refnum); + +void cproxykeywords_KeywordCaller_Const(int32_t refnum); + +void cproxykeywords_KeywordCaller_Continue(int32_t refnum); + +void cproxykeywords_KeywordCaller_Default(int32_t refnum); + +void cproxykeywords_KeywordCaller_Do(int32_t refnum); + +void cproxykeywords_KeywordCaller_Double(int32_t refnum); + +void cproxykeywords_KeywordCaller_Else(int32_t refnum); + +void cproxykeywords_KeywordCaller_Enum(int32_t refnum); + +void cproxykeywords_KeywordCaller_Extends(int32_t refnum); + +void cproxykeywords_KeywordCaller_False(int32_t refnum); + +void cproxykeywords_KeywordCaller_Final(int32_t refnum); + +void cproxykeywords_KeywordCaller_Finally(int32_t refnum); + +void cproxykeywords_KeywordCaller_Float(int32_t refnum); + +void cproxykeywords_KeywordCaller_For(int32_t refnum); + +void cproxykeywords_KeywordCaller_Goto(int32_t refnum); + +void cproxykeywords_KeywordCaller_If(int32_t refnum); + +void cproxykeywords_KeywordCaller_Implements(int32_t refnum); + +void cproxykeywords_KeywordCaller_Import(int32_t refnum); + +void cproxykeywords_KeywordCaller_Instanceof(int32_t refnum); + +void cproxykeywords_KeywordCaller_Int(int32_t refnum); + +void cproxykeywords_KeywordCaller_Interface(int32_t refnum); + +void cproxykeywords_KeywordCaller_Long(int32_t refnum); + +void cproxykeywords_KeywordCaller_Native(int32_t refnum); + +void cproxykeywords_KeywordCaller_New(int32_t refnum); + +void cproxykeywords_KeywordCaller_Nil(int32_t refnum); + +void cproxykeywords_KeywordCaller_Null(int32_t refnum); + +void cproxykeywords_KeywordCaller_Package(int32_t refnum); + +void cproxykeywords_KeywordCaller_Private(int32_t refnum); + +void cproxykeywords_KeywordCaller_Protected(int32_t refnum); + +void cproxykeywords_KeywordCaller_Public(int32_t refnum); + +void cproxykeywords_KeywordCaller_Return(int32_t refnum); + +void cproxykeywords_KeywordCaller_Short(int32_t refnum); + +void cproxykeywords_KeywordCaller_Static(int32_t refnum); + +void cproxykeywords_KeywordCaller_Strictfp(int32_t refnum); + +void cproxykeywords_KeywordCaller_Super(int32_t refnum); + +void cproxykeywords_KeywordCaller_Switch(int32_t refnum); + +void cproxykeywords_KeywordCaller_Synchronized(int32_t refnum); + +void cproxykeywords_KeywordCaller_This(int32_t refnum); + +void cproxykeywords_KeywordCaller_Throw(int32_t refnum); + +void cproxykeywords_KeywordCaller_Throws(int32_t refnum); + +void cproxykeywords_KeywordCaller_Transient(int32_t refnum); + +void cproxykeywords_KeywordCaller_True(int32_t refnum); + +void cproxykeywords_KeywordCaller_Try(int32_t refnum); + +void cproxykeywords_KeywordCaller_Void(int32_t refnum); + +void cproxykeywords_KeywordCaller_Volatile(int32_t refnum); + +void cproxykeywords_KeywordCaller_While(int32_t refnum); + +#endif diff --git a/bind/testdata/keywords.objc.h.golden b/bind/testdata/keywords.objc.h.golden new file mode 100644 index 000000000..67430b12f --- /dev/null +++ b/bind/testdata/keywords.objc.h.golden @@ -0,0 +1,143 @@ +// Objective-C API for talking to keywords Go package. +// gobind -lang=objc keywords +// +// File is generated by gobind. Do not edit. + +#ifndef __Keywords_H__ +#define __Keywords_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@protocol KeywordsKeywordCaller; +@class KeywordsKeywordCaller; + +@protocol KeywordsKeywordCaller +- (void)abstract; +- (void)assert; +- (void)bool_; +- (void)boolean; +- (void)break; +- (void)byte; +- (void)case; +- (void)catch; +- (void)char_; +- (void)class; +- (void)const_; +- (void)continue; +- (void)default; +- (void)do; +- (void)double_; +- (void)else; +- (void)enum; +- (void)extends; +- (void)false; +- (void)final; +- (void)finally; +- (void)float_; +- (void)for; +- (void)goto; +- (void)if; +- (void)implements; +- (void)import; +- (void)instanceof; +- (void)int_; +- (void)interface; +- (void)long_; +- (void)native; +- (void)new; +- (void)nil_; +- (void)null; +- (void)package; +- (void)private; +- (void)protected; +- (void)public; +- (void)return; +- (void)short_; +- (void)static; +- (void)strictfp; +- (void)super_; +- (void)switch; +- (void)synchronized; +- (void)this; +- (void)throw; +- (void)throws; +- (void)transient; +- (void)true; +- (void)try; +- (void)void_; +- (void)volatile_; +- (void)while; +@end + +FOUNDATION_EXPORT void KeywordsConst(NSString* _Nullable id_); + +FOUNDATION_EXPORT void KeywordsStatic(NSString* _Nullable strictfp); + +@class KeywordsKeywordCaller; + +@interface KeywordsKeywordCaller : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (void)abstract; +- (void)assert; +- (void)bool_; +- (void)boolean; +- (void)break; +- (void)byte; +- (void)case; +- (void)catch; +- (void)char_; +- (void)class; +- (void)const_; +- (void)continue; +- (void)default; +- (void)do; +- (void)double_; +- (void)else; +- (void)enum; +- (void)extends; +- (void)false; +- (void)final; +- (void)finally; +- (void)float_; +- (void)for; +- (void)goto; +- (void)if; +- (void)implements; +- (void)import; +- (void)instanceof; +- (void)int_; +- (void)interface; +- (void)long_; +- (void)native; +- (void)new; +- (void)nil_; +- (void)null; +- (void)package; +- (void)private; +- (void)protected; +- (void)public; +- (void)return; +- (void)short_; +- (void)static; +- (void)strictfp; +- (void)super_; +- (void)switch; +- (void)synchronized; +- (void)this; +- (void)throw; +- (void)throws; +- (void)transient; +- (void)true; +- (void)try; +- (void)void_; +- (void)volatile_; +- (void)while; +@end + +#endif diff --git a/bind/testdata/keywords.objc.m.golden b/bind/testdata/keywords.objc.m.golden new file mode 100644 index 000000000..881332b5c --- /dev/null +++ b/bind/testdata/keywords.objc.m.golden @@ -0,0 +1,696 @@ +// Objective-C API for talking to keywords Go package. +// gobind -lang=objc keywords +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Keywords.objc.h" + +@implementation KeywordsKeywordCaller { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)abstract { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Abstract(refnum); +} + +- (void)assert { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Assert(refnum); +} + +- (void)bool_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Bool(refnum); +} + +- (void)boolean { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Boolean(refnum); +} + +- (void)break { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Break(refnum); +} + +- (void)byte { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Byte(refnum); +} + +- (void)case { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Case(refnum); +} + +- (void)catch { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Catch(refnum); +} + +- (void)char_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Char(refnum); +} + +- (void)class { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Class(refnum); +} + +- (void)const_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Const(refnum); +} + +- (void)continue { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Continue(refnum); +} + +- (void)default { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Default(refnum); +} + +- (void)do { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Do(refnum); +} + +- (void)double_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Double(refnum); +} + +- (void)else { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Else(refnum); +} + +- (void)enum { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Enum(refnum); +} + +- (void)extends { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Extends(refnum); +} + +- (void)false { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_False(refnum); +} + +- (void)final { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Final(refnum); +} + +- (void)finally { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Finally(refnum); +} + +- (void)float_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Float(refnum); +} + +- (void)for { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_For(refnum); +} + +- (void)goto { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Goto(refnum); +} + +- (void)if { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_If(refnum); +} + +- (void)implements { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Implements(refnum); +} + +- (void)import { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Import(refnum); +} + +- (void)instanceof { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Instanceof(refnum); +} + +- (void)int_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Int(refnum); +} + +- (void)interface { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Interface(refnum); +} + +- (void)long_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Long(refnum); +} + +- (void)native { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Native(refnum); +} + +- (void)new { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_New(refnum); +} + +- (void)nil_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Nil(refnum); +} + +- (void)null { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Null(refnum); +} + +- (void)package { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Package(refnum); +} + +- (void)private { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Private(refnum); +} + +- (void)protected { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Protected(refnum); +} + +- (void)public { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Public(refnum); +} + +- (void)return { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Return(refnum); +} + +- (void)short_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Short(refnum); +} + +- (void)static { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Static(refnum); +} + +- (void)strictfp { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Strictfp(refnum); +} + +- (void)super_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Super(refnum); +} + +- (void)switch { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Switch(refnum); +} + +- (void)synchronized { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Synchronized(refnum); +} + +- (void)this { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_This(refnum); +} + +- (void)throw { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Throw(refnum); +} + +- (void)throws { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Throws(refnum); +} + +- (void)transient { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Transient(refnum); +} + +- (void)true { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_True(refnum); +} + +- (void)try { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Try(refnum); +} + +- (void)void_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Void(refnum); +} + +- (void)volatile_ { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_Volatile(refnum); +} + +- (void)while { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxykeywords_KeywordCaller_While(refnum); +} + +@end + + + +void KeywordsConst(NSString* _Nullable id_) { + nstring _id_ = go_seq_from_objc_string(id_); + proxykeywords__Const(_id_); +} + +void KeywordsStatic(NSString* _Nullable strictfp) { + nstring _strictfp = go_seq_from_objc_string(strictfp); + proxykeywords__Static(_strictfp); +} + +void cproxykeywords_KeywordCaller_Abstract(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o abstract]; + } +} + +void cproxykeywords_KeywordCaller_Assert(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o assert]; + } +} + +void cproxykeywords_KeywordCaller_Bool(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o bool_]; + } +} + +void cproxykeywords_KeywordCaller_Boolean(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o boolean]; + } +} + +void cproxykeywords_KeywordCaller_Break(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o break]; + } +} + +void cproxykeywords_KeywordCaller_Byte(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o byte]; + } +} + +void cproxykeywords_KeywordCaller_Case(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o case]; + } +} + +void cproxykeywords_KeywordCaller_Catch(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o catch]; + } +} + +void cproxykeywords_KeywordCaller_Char(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o char_]; + } +} + +void cproxykeywords_KeywordCaller_Class(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o class]; + } +} + +void cproxykeywords_KeywordCaller_Const(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o const_]; + } +} + +void cproxykeywords_KeywordCaller_Continue(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o continue]; + } +} + +void cproxykeywords_KeywordCaller_Default(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o default]; + } +} + +void cproxykeywords_KeywordCaller_Do(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o do]; + } +} + +void cproxykeywords_KeywordCaller_Double(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o double_]; + } +} + +void cproxykeywords_KeywordCaller_Else(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o else]; + } +} + +void cproxykeywords_KeywordCaller_Enum(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o enum]; + } +} + +void cproxykeywords_KeywordCaller_Extends(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o extends]; + } +} + +void cproxykeywords_KeywordCaller_False(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o false]; + } +} + +void cproxykeywords_KeywordCaller_Final(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o final]; + } +} + +void cproxykeywords_KeywordCaller_Finally(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o finally]; + } +} + +void cproxykeywords_KeywordCaller_Float(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o float_]; + } +} + +void cproxykeywords_KeywordCaller_For(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o for]; + } +} + +void cproxykeywords_KeywordCaller_Goto(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o goto]; + } +} + +void cproxykeywords_KeywordCaller_If(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o if]; + } +} + +void cproxykeywords_KeywordCaller_Implements(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o implements]; + } +} + +void cproxykeywords_KeywordCaller_Import(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o import]; + } +} + +void cproxykeywords_KeywordCaller_Instanceof(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o instanceof]; + } +} + +void cproxykeywords_KeywordCaller_Int(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o int_]; + } +} + +void cproxykeywords_KeywordCaller_Interface(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o interface]; + } +} + +void cproxykeywords_KeywordCaller_Long(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o long_]; + } +} + +void cproxykeywords_KeywordCaller_Native(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o native]; + } +} + +void cproxykeywords_KeywordCaller_New(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o new]; + } +} + +void cproxykeywords_KeywordCaller_Nil(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o nil_]; + } +} + +void cproxykeywords_KeywordCaller_Null(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o null]; + } +} + +void cproxykeywords_KeywordCaller_Package(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o package]; + } +} + +void cproxykeywords_KeywordCaller_Private(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o private]; + } +} + +void cproxykeywords_KeywordCaller_Protected(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o protected]; + } +} + +void cproxykeywords_KeywordCaller_Public(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o public]; + } +} + +void cproxykeywords_KeywordCaller_Return(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o return]; + } +} + +void cproxykeywords_KeywordCaller_Short(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o short_]; + } +} + +void cproxykeywords_KeywordCaller_Static(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o static]; + } +} + +void cproxykeywords_KeywordCaller_Strictfp(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o strictfp]; + } +} + +void cproxykeywords_KeywordCaller_Super(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o super_]; + } +} + +void cproxykeywords_KeywordCaller_Switch(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o switch]; + } +} + +void cproxykeywords_KeywordCaller_Synchronized(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o synchronized]; + } +} + +void cproxykeywords_KeywordCaller_This(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o this]; + } +} + +void cproxykeywords_KeywordCaller_Throw(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o throw]; + } +} + +void cproxykeywords_KeywordCaller_Throws(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o throws]; + } +} + +void cproxykeywords_KeywordCaller_Transient(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o transient]; + } +} + +void cproxykeywords_KeywordCaller_True(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o true]; + } +} + +void cproxykeywords_KeywordCaller_Try(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o try]; + } +} + +void cproxykeywords_KeywordCaller_Void(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o void_]; + } +} + +void cproxykeywords_KeywordCaller_Volatile(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o volatile_]; + } +} + +void cproxykeywords_KeywordCaller_While(int32_t refnum) { + @autoreleasepool { + KeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum); + [o while]; + } +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/objc.go b/bind/testdata/objc.go new file mode 100644 index 000000000..ca42fb95f --- /dev/null +++ b/bind/testdata/objc.go @@ -0,0 +1,15 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objc + +import ( + "ObjC/Foundation" +) + +type ( + S Foundation.NSString + D Foundation.NSDate + O Foundation.NSObjectC +) diff --git a/bind/testdata/objc.go.golden b/bind/testdata/objc.go.golden new file mode 100644 index 000000000..0f1ca864c --- /dev/null +++ b/bind/testdata/objc.go.golden @@ -0,0 +1,93 @@ +// Code generated by gobind. DO NOT EDIT. + +package ObjC + +// Used to silence this package not used errors +const Dummy = 0 + +type Foundation_NSString interface { +} + +type Foundation_NSDate interface { +} + +type Foundation_NSObjectC interface { +} +// Code generated by gobind. DO NOT EDIT. + +package main + +// #include "interfaces.h" +import "C" + +import "ObjC" +import _seq "golang.org/x/mobile/bind/seq" + +type proxy interface{ Bind_proxy_refnum__() int32 } + +// Suppress unused package error + +var _ = _seq.FromRefNum + +const _ = ObjC.Dummy + +func init() { +} + +type proxy_class_NSString _seq.Ref + +func (p *proxy_class_NSString) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func init() { +} + +type proxy_class_NSDate _seq.Ref + +func (p *proxy_class_NSDate) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func init() { +} + +type proxy_class_NSObjectC _seq.Ref + +func (p *proxy_class_NSObjectC) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package objc. +// +// autogenerated by gobind -lang=go objc +package main + +/* +#include +#include +#include "seq.h" +#include "objc.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +type proxyobjc_D _seq.Ref + +func (p *proxyobjc_D) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +type proxyobjc_O _seq.Ref + +func (p *proxyobjc_O) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +type proxyobjc_S _seq.Ref + +func (p *proxyobjc_S) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} diff --git a/bind/testdata/objcw.go b/bind/testdata/objcw.go new file mode 100644 index 000000000..dadfd93bc --- /dev/null +++ b/bind/testdata/objcw.go @@ -0,0 +1,60 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objc + +import ( + "ObjC/Foundation" + "ObjC/Foundation/NSMutableString" + "ObjC/NetworkExtension/NEPacket" + "ObjC/UIKit" +) + +type GoNSDate struct { + Foundation.NSDate + this Foundation.NSDate +} + +func (d *GoNSDate) Hash(this Foundation.NSDate) int { + return 0 +} + +type GoNSObject struct { + C Foundation.NSObjectC // The class + P Foundation.NSObjectP // The protocol +} + +func (o *GoNSObject) Description(this Foundation.NSObjectC) string { + return "" +} + +func DupNSDate(date Foundation.NSDate) Foundation.NSDate { + return date +} + +type GoUIResponder struct { + UIKit.UIResponder +} + +func (r *GoUIResponder) PressesBegan(_ Foundation.NSSet, _ UIKit.UIPressesEvent) { +} + +const NSUTF8StringEncoding = 8 + +func CreateReadNSMutableString() { + myData := []byte{'A', 'B'} + // Test byte slices. Use NSMutableString because NSString is + // represented as Go strings in bindings. + // Pass slice from Go to native. + mString := NSMutableString.NewWithData(myData, uint(NSUTF8StringEncoding)) + // Pass slice from native to Go. + _ = mString.DataUsingEncoding(uint(NSUTF8StringEncoding)) +} + +// From +const PF_INET = 2 + +func CallUcharFunction() { + _ = NEPacket.NewWithData(nil, uint8(PF_INET)) +} diff --git a/bind/testdata/objcw.go.golden b/bind/testdata/objcw.go.golden new file mode 100644 index 000000000..a9e80fa6d --- /dev/null +++ b/bind/testdata/objcw.go.golden @@ -0,0 +1,620 @@ +// Code generated by gobind. DO NOT EDIT. + +package ObjC + +// Used to silence this package not used errors +const Dummy = 0 + +type Foundation_NSDate interface { + Hash() uint + Description() string +} + +type Foundation_NSObjectC interface { + Hash() uint + Description() string +} + +type Foundation_NSObjectP interface { + Hash() uint + Description() string +} + +type Foundation_NSSet interface { + Hash() uint + Description() string +} + +type Foundation_NSMutableString interface { + Hash() uint + Description() string + DataUsingEncoding(encoding uint) []byte +} + +type UIKit_UIResponder interface { + Hash() uint + Description() string +} + +type UIKit_UIPressesEvent interface { + Hash() uint + Description() string +} + +type NetworkExtension_NEPacket interface { + Hash() uint + Description() string +} + +type Objc_GoNSDate interface { + Hash() uint + Description() string + Super() Objc_GoNSDate +} + +type Objc_GoNSObject interface { + Hash() uint + Description() string + Super() Objc_GoNSObject +} + +type Objc_GoUIResponder interface { + Hash() uint + Description() string + Super() Objc_GoUIResponder +} +// Code generated by gobind. DO NOT EDIT. + +package main + +// #include "interfaces.h" +import "C" + +import "ObjC" +import _seq "golang.org/x/mobile/bind/seq" +import "ObjC/Foundation/NSMutableString" +import "ObjC/NetworkExtension/NEPacket" + +type proxy interface{ Bind_proxy_refnum__() int32 } + +// Suppress unused package error + +var _ = _seq.FromRefNum + +const _ = ObjC.Dummy + +func init() { +} + +type proxy_class_NSDate _seq.Ref + +func (p *proxy_class_NSDate) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_NSDate) Hash() uint { + res := C.cproxy_NSDate_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_NSDate) Description() string { + res := C.cproxy_NSDate_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { +} + +type proxy_class_NSObjectC _seq.Ref + +func (p *proxy_class_NSObjectC) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_NSObjectC) Hash() uint { + res := C.cproxy_NSObjectC_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_NSObjectC) Description() string { + res := C.cproxy_NSObjectC_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { +} + +type proxy_class_NSObjectP _seq.Ref + +func (p *proxy_class_NSObjectP) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_NSObjectP) Hash() uint { + res := C.cproxy_NSObjectP_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_NSObjectP) Description() string { + res := C.cproxy_NSObjectP_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { +} + +type proxy_class_NSSet _seq.Ref + +func (p *proxy_class_NSSet) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_NSSet) Hash() uint { + res := C.cproxy_NSSet_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_NSSet) Description() string { + res := C.cproxy_NSSet_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { + NSMutableString.NewWithData = func(data []byte, encoding uint) ObjC.Foundation_NSMutableString { + _data := fromSlice(data, false) + _encoding := C.ulong(encoding) + res := C.cproxy_s_NSMutableString_NewWithData(_data, _encoding) + var _res ObjC.Foundation_NSMutableString + _res_ref := _seq.FromRefNum(int32(res)) + if _res_ref != nil { + if res < 0 { // go object + _res = _res_ref.Get().(ObjC.Foundation_NSMutableString) + } else { // foreign object + _res = (*proxy_class_NSMutableString)(_res_ref) + } + } + return _res + } + +} + +type proxy_class_NSMutableString _seq.Ref + +func (p *proxy_class_NSMutableString) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_NSMutableString) Hash() uint { + res := C.cproxy_NSMutableString_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_NSMutableString) Description() string { + res := C.cproxy_NSMutableString_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func (p *proxy_class_NSMutableString) DataUsingEncoding(encoding uint) []byte { + _encoding := C.ulong(encoding) + res := C.cproxy_NSMutableString_DataUsingEncoding(C.int(p.Bind_proxy_refnum__()), _encoding) + _res := toSlice(res, true) + return _res +} + +func init() { +} + +type proxy_class_UIResponder _seq.Ref + +func (p *proxy_class_UIResponder) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_UIResponder) Hash() uint { + res := C.cproxy_UIResponder_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_UIResponder) Description() string { + res := C.cproxy_UIResponder_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { +} + +type proxy_class_UIPressesEvent _seq.Ref + +func (p *proxy_class_UIPressesEvent) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_UIPressesEvent) Hash() uint { + res := C.cproxy_UIPressesEvent_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_UIPressesEvent) Description() string { + res := C.cproxy_UIPressesEvent_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { + NEPacket.NewWithData = func(data []byte, protocolFamily uint8) ObjC.NetworkExtension_NEPacket { + _data := fromSlice(data, false) + _protocolFamily := C.uchar(protocolFamily) + res := C.cproxy_s_NEPacket_NewWithData(_data, _protocolFamily) + var _res ObjC.NetworkExtension_NEPacket + _res_ref := _seq.FromRefNum(int32(res)) + if _res_ref != nil { + if res < 0 { // go object + _res = _res_ref.Get().(ObjC.NetworkExtension_NEPacket) + } else { // foreign object + _res = (*proxy_class_NEPacket)(_res_ref) + } + } + return _res + } + +} + +type proxy_class_NEPacket _seq.Ref + +func (p *proxy_class_NEPacket) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_NEPacket) Hash() uint { + res := C.cproxy_NEPacket_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_NEPacket) Description() string { + res := C.cproxy_NEPacket_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { +} + +type proxy_class_GoNSDate _seq.Ref + +func (p *proxy_class_GoNSDate) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_GoNSDate) Hash() uint { + res := C.cproxy_GoNSDate_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_GoNSDate) Description() string { + res := C.cproxy_GoNSDate_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func (p *proxy_class_GoNSDate) Super() ObjC.Objc_GoNSDate { + return &super_GoNSDate{p} +} + +type super_GoNSDate struct{ *proxy_class_GoNSDate } + +func (p *super_GoNSDate) Hash() uint { + res := C.csuper_GoNSDate_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *super_GoNSDate) Description() string { + res := C.csuper_GoNSDate_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { +} + +type proxy_class_GoNSObject _seq.Ref + +func (p *proxy_class_GoNSObject) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_GoNSObject) Hash() uint { + res := C.cproxy_GoNSObject_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_GoNSObject) Description() string { + res := C.cproxy_GoNSObject_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func (p *proxy_class_GoNSObject) Super() ObjC.Objc_GoNSObject { + return &super_GoNSObject{p} +} + +type super_GoNSObject struct{ *proxy_class_GoNSObject } + +func (p *super_GoNSObject) Hash() uint { + res := C.csuper_GoNSObject_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *super_GoNSObject) Description() string { + res := C.csuper_GoNSObject_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func init() { +} + +type proxy_class_GoUIResponder _seq.Ref + +func (p *proxy_class_GoUIResponder) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() } + +func (p *proxy_class_GoUIResponder) Hash() uint { + res := C.cproxy_GoUIResponder_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *proxy_class_GoUIResponder) Description() string { + res := C.cproxy_GoUIResponder_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} + +func (p *proxy_class_GoUIResponder) Super() ObjC.Objc_GoUIResponder { + return &super_GoUIResponder{p} +} + +type super_GoUIResponder struct{ *proxy_class_GoUIResponder } + +func (p *super_GoUIResponder) Hash() uint { + res := C.csuper_GoUIResponder_Hash(C.int(p.Bind_proxy_refnum__())) + _res := uint(res) + return _res +} + +func (p *super_GoUIResponder) Description() string { + res := C.csuper_GoUIResponder_Description(C.int(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package objc. +// +// autogenerated by gobind -lang=go objcw +package main + +/* +#include +#include +#include "seq.h" +#include "objc.h" + +*/ +import "C" + +import ( + "ObjC/Foundation" + "ObjC/UIKit" + _seq "golang.org/x/mobile/bind/seq" + "objcw" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyobjc_GoNSDate_NSDate_Set +func proxyobjc_GoNSDate_NSDate_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v Foundation.NSDate + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(Foundation.NSDate) + } else { // foreign object + _v = (*proxy_class_NSDate)(_v_ref) + } + } + ref.Get().(*objc.GoNSDate).NSDate = _v +} + +//export proxyobjc_GoNSDate_NSDate_Get +func proxyobjc_GoNSDate_NSDate_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*objc.GoNSDate).NSDate + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxyobjc_GoNSDate_Hash +func proxyobjc_GoNSDate_Hash(refnum C.int32_t, param_this C.int32_t) C.nint { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*objc.GoNSDate) + var _param_this Foundation.NSDate + _param_this_ref := _seq.FromRefNum(int32(param_this)) + if _param_this_ref != nil { + if param_this < 0 { // go object + _param_this = _param_this_ref.Get().(Foundation.NSDate) + } else { // foreign object + _param_this = (*proxy_class_NSDate)(_param_this_ref) + } + } + res_0 := v.Hash(_param_this) + _res_0 := C.nint(res_0) + return _res_0 +} + +//export new_objc_GoNSDate +func new_objc_GoNSDate() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(objc.GoNSDate))) +} + +//export proxyobjc_GoNSObject_C_Set +func proxyobjc_GoNSObject_C_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v Foundation.NSObjectC + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(Foundation.NSObjectC) + } else { // foreign object + _v = (*proxy_class_NSObjectC)(_v_ref) + } + } + ref.Get().(*objc.GoNSObject).C = _v +} + +//export proxyobjc_GoNSObject_C_Get +func proxyobjc_GoNSObject_C_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*objc.GoNSObject).C + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxyobjc_GoNSObject_P_Set +func proxyobjc_GoNSObject_P_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v Foundation.NSObjectP + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(Foundation.NSObjectP) + } else { // foreign object + _v = (*proxy_class_NSObjectP)(_v_ref) + } + } + ref.Get().(*objc.GoNSObject).P = _v +} + +//export proxyobjc_GoNSObject_P_Get +func proxyobjc_GoNSObject_P_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*objc.GoNSObject).P + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxyobjc_GoNSObject_Description +func proxyobjc_GoNSObject_Description(refnum C.int32_t, param_this C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*objc.GoNSObject) + var _param_this Foundation.NSObjectC + _param_this_ref := _seq.FromRefNum(int32(param_this)) + if _param_this_ref != nil { + if param_this < 0 { // go object + _param_this = _param_this_ref.Get().(Foundation.NSObjectC) + } else { // foreign object + _param_this = (*proxy_class_NSObjectC)(_param_this_ref) + } + } + res_0 := v.Description(_param_this) + _res_0 := encodeString(res_0) + return _res_0 +} + +//export new_objc_GoNSObject +func new_objc_GoNSObject() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(objc.GoNSObject))) +} + +//export proxyobjc_GoUIResponder_UIResponder_Set +func proxyobjc_GoUIResponder_UIResponder_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v UIKit.UIResponder + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(UIKit.UIResponder) + } else { // foreign object + _v = (*proxy_class_UIResponder)(_v_ref) + } + } + ref.Get().(*objc.GoUIResponder).UIResponder = _v +} + +//export proxyobjc_GoUIResponder_UIResponder_Get +func proxyobjc_GoUIResponder_UIResponder_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*objc.GoUIResponder).UIResponder + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxyobjc_GoUIResponder_PressesBegan +func proxyobjc_GoUIResponder_PressesBegan(refnum C.int32_t, param_p0 C.int32_t, param_p1 C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*objc.GoUIResponder) + var _param_p0 Foundation.NSSet + _param_p0_ref := _seq.FromRefNum(int32(param_p0)) + if _param_p0_ref != nil { + if param_p0 < 0 { // go object + _param_p0 = _param_p0_ref.Get().(Foundation.NSSet) + } else { // foreign object + _param_p0 = (*proxy_class_NSSet)(_param_p0_ref) + } + } + var _param_p1 UIKit.UIPressesEvent + _param_p1_ref := _seq.FromRefNum(int32(param_p1)) + if _param_p1_ref != nil { + if param_p1 < 0 { // go object + _param_p1 = _param_p1_ref.Get().(UIKit.UIPressesEvent) + } else { // foreign object + _param_p1 = (*proxy_class_UIPressesEvent)(_param_p1_ref) + } + } + v.PressesBegan(_param_p0, _param_p1) +} + +//export new_objc_GoUIResponder +func new_objc_GoUIResponder() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(objc.GoUIResponder))) +} + +//export proxyobjc__CallUcharFunction +func proxyobjc__CallUcharFunction() { + objc.CallUcharFunction() +} + +//export proxyobjc__CreateReadNSMutableString +func proxyobjc__CreateReadNSMutableString() { + objc.CreateReadNSMutableString() +} + +//export proxyobjc__DupNSDate +func proxyobjc__DupNSDate(param_date C.int32_t) C.int32_t { + var _param_date Foundation.NSDate + _param_date_ref := _seq.FromRefNum(int32(param_date)) + if _param_date_ref != nil { + if param_date < 0 { // go object + _param_date = _param_date_ref.Get().(Foundation.NSDate) + } else { // foreign object + _param_date = (*proxy_class_NSDate)(_param_date_ref) + } + } + res_0 := objc.DupNSDate(_param_date) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} diff --git a/bind/testdata/structs.go b/bind/testdata/structs.go new file mode 100644 index 000000000..5974bdc36 --- /dev/null +++ b/bind/testdata/structs.go @@ -0,0 +1,46 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package structs + +type S struct { + X, Y float64 + unexported bool +} + +func (s *S) Sum() float64 { + return s.X + s.Y +} + +func (s *S) Identity() (*S, error) { + return s, nil +} + +func Identity(s *S) *S { + return s +} + +func IdentityWithError(s *S) (*S, error) { + return s, nil +} + +type ( + S2 struct{} + I interface { + M() + } +) + +func (s *S2) M() { +} + +func (_ *S2) String() string { + return "" +} + +// Structs is a struct with the same name as its package. +type Structs struct{} + +func (_ *Structs) M() { +} diff --git a/bind/testdata/structs.go.golden b/bind/testdata/structs.go.golden new file mode 100644 index 000000000..fb50778ae --- /dev/null +++ b/bind/testdata/structs.go.golden @@ -0,0 +1,167 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package structs. +// +// autogenerated by gobind -lang=go structs +package main + +/* +#include +#include +#include "seq.h" +#include "structs.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "structs" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxystructs_S_X_Set +func proxystructs_S_X_Set(refnum C.int32_t, v C.double) { + ref := _seq.FromRefNum(int32(refnum)) + _v := float64(v) + ref.Get().(*structs.S).X = _v +} + +//export proxystructs_S_X_Get +func proxystructs_S_X_Get(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*structs.S).X + _v := C.double(v) + return _v +} + +//export proxystructs_S_Y_Set +func proxystructs_S_Y_Set(refnum C.int32_t, v C.double) { + ref := _seq.FromRefNum(int32(refnum)) + _v := float64(v) + ref.Get().(*structs.S).Y = _v +} + +//export proxystructs_S_Y_Get +func proxystructs_S_Y_Get(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*structs.S).Y + _v := C.double(v) + return _v +} + +//export proxystructs_S_Identity +func proxystructs_S_Identity(refnum C.int32_t) (C.int32_t, C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*structs.S) + res_0, res_1 := v.Identity() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 +} + +//export proxystructs_S_Sum +func proxystructs_S_Sum(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*structs.S) + res_0 := v.Sum() + _res_0 := C.double(res_0) + return _res_0 +} + +//export new_structs_S +func new_structs_S() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(structs.S))) +} + +//export proxystructs_S2_M +func proxystructs_S2_M(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*structs.S2) + v.M() +} + +//export proxystructs_S2_String +func proxystructs_S2_String(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*structs.S2) + res_0 := v.String() + _res_0 := encodeString(res_0) + return _res_0 +} + +//export new_structs_S2 +func new_structs_S2() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(structs.S2))) +} + +//export proxystructs_Structs_M +func proxystructs_Structs_M(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*structs.Structs) + v.M() +} + +//export new_structs_Structs +func new_structs_Structs() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(structs.Structs))) +} + +//export proxystructs_I_M +func proxystructs_I_M(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(structs.I) + v.M() +} + +type proxystructs_I _seq.Ref + +func (p *proxystructs_I) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxystructs_I) M() { + C.cproxystructs_I_M(C.int32_t(p.Bind_proxy_refnum__())) +} + +//export proxystructs__Identity +func proxystructs__Identity(param_s C.int32_t) C.int32_t { + // Must be a Go object + var _param_s *structs.S + if _param_s_ref := _seq.FromRefNum(int32(param_s)); _param_s_ref != nil { + _param_s = _param_s_ref.Get().(*structs.S) + } + res_0 := structs.Identity(_param_s) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxystructs__IdentityWithError +func proxystructs__IdentityWithError(param_s C.int32_t) (C.int32_t, C.int32_t) { + // Must be a Go object + var _param_s *structs.S + if _param_s_ref := _seq.FromRefNum(int32(param_s)); _param_s_ref != nil { + _param_s = _param_s_ref.Get().(*structs.S) + } + res_0, res_1 := structs.IdentityWithError(_param_s) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + var _res_1 C.int32_t = _seq.NullRefNum + if res_1 != nil { + _res_1 = C.int32_t(_seq.ToRefNum(res_1)) + } + return _res_0, _res_1 +} diff --git a/bind/testdata/structs.java.c.golden b/bind/testdata/structs.java.c.golden new file mode 100644 index 000000000..62b8f5af8 --- /dev/null +++ b/bind/testdata/structs.java.c.golden @@ -0,0 +1,156 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java structs + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "structs.h" + +jclass proxy_class_structs_I; +jmethodID proxy_class_structs_I_cons; +static jmethodID mid_I_M; +jclass proxy_class_structs_S; +jmethodID proxy_class_structs_S_cons; +jclass proxy_class_structs_S2; +jmethodID proxy_class_structs_S2_cons; +jclass proxy_class_structs_Structs; +jmethodID proxy_class_structs_Structs_cons; + +JNIEXPORT void JNICALL +Java_structs_Structs__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "structs/S"); + proxy_class_structs_S = (*env)->NewGlobalRef(env, clazz); + proxy_class_structs_S_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "structs/S2"); + proxy_class_structs_S2 = (*env)->NewGlobalRef(env, clazz); + proxy_class_structs_S2_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "structs/Structs_"); + proxy_class_structs_Structs = (*env)->NewGlobalRef(env, clazz); + proxy_class_structs_Structs_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "structs/Structs$proxyI"); + proxy_class_structs_I = (*env)->NewGlobalRef(env, clazz); + proxy_class_structs_I_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "structs/I"); + mid_I_M = (*env)->GetMethodID(env, clazz, "m", "()V"); + +} + +JNIEXPORT jobject JNICALL +Java_structs_Structs_identity(JNIEnv* env, jclass _clazz, jobject s) { + int32_t _s = go_seq_to_refnum(env, s); + int32_t r0 = proxystructs__Identity(_s); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_structs_S, proxy_class_structs_S_cons); + return _r0; +} + +JNIEXPORT jobject JNICALL +Java_structs_Structs_identityWithError(JNIEnv* env, jclass _clazz, jobject s) { + int32_t _s = go_seq_to_refnum(env, s); + struct proxystructs__IdentityWithError_return res = proxystructs__IdentityWithError(_s); + jobject _r0 = go_seq_from_refnum(env, res.r0, proxy_class_structs_S, proxy_class_structs_S_cons); + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT jint JNICALL +Java_structs_S__1_1New(JNIEnv *env, jclass clazz) { + return new_structs_S(); +} + +JNIEXPORT jobject JNICALL +Java_structs_S_identity(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + struct proxystructs_S_Identity_return res = proxystructs_S_Identity(o); + jobject _r0 = go_seq_from_refnum(env, res.r0, proxy_class_structs_S, proxy_class_structs_S_cons); + jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT jdouble JNICALL +Java_structs_S_sum(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + double r0 = proxystructs_S_Sum(o); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_structs_S_setX(JNIEnv *env, jobject this, jdouble v) { + int32_t o = go_seq_to_refnum_go(env, this); + double _v = (double)v; + proxystructs_S_X_Set(o, _v); +} + +JNIEXPORT jdouble JNICALL +Java_structs_S_getX(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + double r0 = proxystructs_S_X_Get(o); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_structs_S_setY(JNIEnv *env, jobject this, jdouble v) { + int32_t o = go_seq_to_refnum_go(env, this); + double _v = (double)v; + proxystructs_S_Y_Set(o, _v); +} + +JNIEXPORT jdouble JNICALL +Java_structs_S_getY(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + double r0 = proxystructs_S_Y_Get(o); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT jint JNICALL +Java_structs_S2__1_1New(JNIEnv *env, jclass clazz) { + return new_structs_S2(); +} + +JNIEXPORT void JNICALL +Java_structs_S2_m(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxystructs_S2_M(o); +} + +JNIEXPORT jstring JNICALL +Java_structs_S2_string(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + nstring r0 = proxystructs_S2_String(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT jint JNICALL +Java_structs_Structs_1__1_1New(JNIEnv *env, jclass clazz) { + return new_structs_Structs(); +} + +JNIEXPORT void JNICALL +Java_structs_Structs_1_m(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxystructs_Structs_M(o); +} + +JNIEXPORT void JNICALL +Java_structs_Structs_00024proxyI_m(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + proxystructs_I_M(o); +} + +void cproxystructs_I_M(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_structs_I, proxy_class_structs_I_cons); + (*env)->CallVoidMethod(env, o, mid_I_M); + go_seq_pop_local_frame(env); +} + diff --git a/bind/testdata/structs.java.golden b/bind/testdata/structs.java.golden new file mode 100644 index 000000000..5a140fe00 --- /dev/null +++ b/bind/testdata/structs.java.golden @@ -0,0 +1,206 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class structs.S is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java structs +package structs; + +import go.Seq; + +public final class S implements Seq.Proxy { + static { Structs.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + S(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public S() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public final native double getX(); + public final native void setX(double v); + + public final native double getY(); + public final native void setY(double v); + + public native S identity() throws Exception; + public native double sum(); + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof S)) { + return false; + } + S that = (S)o; + double thisX = getX(); + double thatX = that.getX(); + if (thisX != thatX) { + return false; + } + double thisY = getY(); + double thatY = that.getY(); + if (thisY != thatY) { + return false; + } + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {getX(), getY()}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("S").append("{"); + b.append("X:").append(getX()).append(","); + b.append("Y:").append(getY()).append(","); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class structs.S2 is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java structs +package structs; + +import go.Seq; + +public final class S2 implements Seq.Proxy, I { + static { Structs.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + S2(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public S2() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public native void m(); + public native String string(); + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof S2)) { + return false; + } + S2 that = (S2)o; + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {}); + } + + @Override public String toString() { + return string(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class structs.Structs_ is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java structs +package structs; + +import go.Seq; + +public final class Structs_ implements Seq.Proxy, I { + static { Structs.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + Structs_(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public Structs_() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public native void m(); + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof Structs_)) { + return false; + } + Structs_ that = (Structs_)o; + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("Structs_").append("{"); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class structs.I is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java structs +package structs; + +import go.Seq; + +public interface I { + public void m(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class structs.Structs is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java structs +package structs; + +import go.Seq; + +public abstract class Structs { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Structs() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyI implements Seq.Proxy, I { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyI(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public native void m(); + } + + + public static native S identity(S s); + public static native S identityWithError(S s) throws Exception; +} diff --git a/bind/testdata/structs.java.h.golden b/bind/testdata/structs.java.h.golden new file mode 100644 index 000000000..85dc84bb0 --- /dev/null +++ b/bind/testdata/structs.java.h.golden @@ -0,0 +1,23 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java structs + +#ifndef __Structs_H__ +#define __Structs_H__ + +#include + +extern jclass proxy_class_structs_I; +extern jmethodID proxy_class_structs_I_cons; + +void cproxystructs_I_M(int32_t refnum); + +extern jclass proxy_class_structs_S; +extern jmethodID proxy_class_structs_S_cons; +extern jclass proxy_class_structs_S2; +extern jmethodID proxy_class_structs_S2_cons; +extern jclass proxy_class_structs_Structs; +extern jmethodID proxy_class_structs_Structs_cons; +#endif diff --git a/bind/testdata/structs.objc.go.h.golden b/bind/testdata/structs.objc.go.h.golden new file mode 100644 index 000000000..41f67cb90 --- /dev/null +++ b/bind/testdata/structs.objc.go.h.golden @@ -0,0 +1,13 @@ +// Objective-C API for talking to structs Go package. +// gobind -lang=objc structs +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_structs_H__ +#define __GO_structs_H__ + +#include +#include +void cproxystructs_I_M(int32_t refnum); + +#endif diff --git a/bind/testdata/structs.objc.h.golden b/bind/testdata/structs.objc.h.golden new file mode 100644 index 000000000..87ccbc052 --- /dev/null +++ b/bind/testdata/structs.objc.h.golden @@ -0,0 +1,72 @@ +// Objective-C API for talking to structs Go package. +// gobind -lang=objc structs +// +// File is generated by gobind. Do not edit. + +#ifndef __Structs_H__ +#define __Structs_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class StructsS; +@class StructsS2; +@class StructsStructs; +@protocol StructsI; +@class StructsI; + +@protocol StructsI +- (void)m; +@end + +@interface StructsS : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +@property (nonatomic) double x; +@property (nonatomic) double y; +- (StructsS* _Nullable)identity:(NSError* _Nullable* _Nullable)error; +- (double)sum; +@end + +@interface StructsS2 : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +- (void)m; +- (NSString* _Nonnull)string; +@end + +/** + * Structs is a struct with the same name as its package. + */ +@interface StructsStructs : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +- (void)m; +@end + +FOUNDATION_EXPORT StructsS* _Nullable StructsIdentity(StructsS* _Nullable s); + +FOUNDATION_EXPORT StructsS* _Nullable StructsIdentityWithError(StructsS* _Nullable s, NSError* _Nullable* _Nullable error); + +@class StructsI; + +@interface StructsI : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (void)m; +@end + +#endif diff --git a/bind/testdata/structs.objc.m.golden b/bind/testdata/structs.objc.m.golden new file mode 100644 index 000000000..c86517413 --- /dev/null +++ b/bind/testdata/structs.objc.m.golden @@ -0,0 +1,233 @@ +// Objective-C API for talking to structs Go package. +// gobind -lang=objc structs +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Structs.objc.h" + + +@implementation StructsS { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_structs_S()); + } + return self; +} + +- (double)x { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxystructs_S_X_Get(refnum); + double _r0 = (double)r0; + return _r0; +} + +- (void)setX:(double)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double _v = (double)v; + proxystructs_S_X_Set(refnum, _v); +} + +- (double)y { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxystructs_S_Y_Get(refnum); + double _r0 = (double)r0; + return _r0; +} + +- (void)setY:(double)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double _v = (double)v; + proxystructs_S_Y_Set(refnum, _v); +} + +- (StructsS* _Nullable)identity:(NSError* _Nullable* _Nullable)error { + int32_t refnum = go_seq_go_to_refnum(self._ref); + struct proxystructs_S_Identity_return res = proxystructs_S_Identity(refnum); + StructsS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(res.r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[StructsS alloc] initWithRef:_ret0__ref]; + } + } + Universeerror* _error = nil; + GoSeqRef* _error_ref = go_seq_from_refnum(res.r1); + if (_error_ref != NULL) { + _error = _error_ref.obj; + if (_error == nil) { + _error = [[Universeerror alloc] initWithRef:_error_ref]; + } + } + if (_error != nil && error != nil) { + *error = _error; + } + if (_error != nil) { + return nil; + } + return _ret0_; +} + +- (double)sum { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxystructs_S_Sum(refnum); + double _ret0_ = (double)r0; + return _ret0_; +} + +@end + + + +@implementation StructsS2 { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_structs_S2()); + } + return self; +} + +- (void)m { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxystructs_S2_M(refnum); +} + +- (NSString* _Nonnull)string { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxystructs_S2_String(refnum); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; +} + +@end + + + +@implementation StructsStructs { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_structs_Structs()); + } + return self; +} + +- (void)m { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxystructs_Structs_M(refnum); +} + +@end + + +@implementation StructsI { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (void)m { + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxystructs_I_M(refnum); +} + +@end + + + +StructsS* _Nullable StructsIdentity(StructsS* _Nullable s) { + int32_t _s; + if ([s conformsToProtocol:@protocol(goSeqRefInterface)]) { + id s_proxy = (id)(s); + _s = go_seq_go_to_refnum(s_proxy._ref); + } else { + _s = go_seq_to_refnum(s); + } + int32_t r0 = proxystructs__Identity(_s); + StructsS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[StructsS alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +StructsS* _Nullable StructsIdentityWithError(StructsS* _Nullable s, NSError* _Nullable* _Nullable error) { + int32_t _s; + if ([s conformsToProtocol:@protocol(goSeqRefInterface)]) { + id s_proxy = (id)(s); + _s = go_seq_go_to_refnum(s_proxy._ref); + } else { + _s = go_seq_to_refnum(s); + } + struct proxystructs__IdentityWithError_return res = proxystructs__IdentityWithError(_s); + StructsS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(res.r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[StructsS alloc] initWithRef:_ret0__ref]; + } + } + Universeerror* _error = nil; + GoSeqRef* _error_ref = go_seq_from_refnum(res.r1); + if (_error_ref != NULL) { + _error = _error_ref.obj; + if (_error == nil) { + _error = [[Universeerror alloc] initWithRef:_error_ref]; + } + } + if (_error != nil && error != nil) { + *error = _error; + } + if (_error != nil) { + return nil; + } + return _ret0_; +} + +void cproxystructs_I_M(int32_t refnum) { + @autoreleasepool { + StructsI* o = go_seq_objc_from_refnum(refnum); + [o m]; + } +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/testpkg/assets/hello.txt b/bind/testdata/testpkg/assets/hello.txt new file mode 100644 index 000000000..0c4408308 --- /dev/null +++ b/bind/testdata/testpkg/assets/hello.txt @@ -0,0 +1 @@ +Hello, Assets. diff --git a/bind/testdata/testpkg/javapkg/classes.go b/bind/testdata/testpkg/javapkg/classes.go new file mode 100644 index 000000000..3f95c4874 --- /dev/null +++ b/bind/testdata/testpkg/javapkg/classes.go @@ -0,0 +1,202 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package javapkg + +import ( + "Java/java/beans" + "Java/java/io" + "Java/java/io/IOException" + "Java/java/lang" + "Java/java/lang/Character" + "Java/java/lang/Integer" + "Java/java/lang/Object" + "Java/java/lang/Runnable" + "Java/java/net" + "Java/java/nio" + "Java/java/util" + "Java/java/util/concurrent" + gopkg "Java/javapkg" + xnet "Java/javax/net" +) + +const ( + ToStringPrefix = "Go toString: " + IOExceptionMessage = "GoInputStream IOException" +) + +type GoRunnable struct { + lang.Object + lang.Runnable + this lang.Runnable + + Field string +} + +func (r *GoRunnable) ToString(this gopkg.GoRunnable) string { + return ToStringPrefix +} + +func (r *GoRunnable) Run(this gopkg.GoRunnable) { +} + +func (r *GoRunnable) GetThis(this gopkg.GoRunnable) lang.Runnable { + return this +} + +type GoInputStream struct { + io.InputStream +} + +func (_ *GoInputStream) Read() (int32, error) { + return 0, IOException.New(IOExceptionMessage) +} + +func NewGoInputStream() *GoInputStream { + return new(GoInputStream) +} + +type GoFuture struct { + concurrent.Future +} + +func (_ *GoFuture) Cancel(_ bool) bool { + return false +} + +func (_ *GoFuture) Get() (lang.Object, error) { + return nil, nil +} + +// Use a trailing underscore to override multiple overloaded methods. +func (_ *GoFuture) Get_(_ int64, _ concurrent.TimeUnit) (lang.Object, error) { + return nil, nil +} + +func (_ *GoFuture) IsCancelled() bool { + return false +} + +func (_ *GoFuture) IsDone() bool { + return false +} + +type GoObject struct { + lang.Object + this lang.Object +} + +func (o *GoObject) ToString(this gopkg.GoObject) string { + o.this = this + return ToStringPrefix + this.Super().ToString() +} + +func (_ *GoObject) HashCode() int32 { + return 42 +} + +func RunRunnable(r lang.Runnable) { + r.Run() +} + +func RunnableRoundtrip(r lang.Runnable) lang.Runnable { + return r +} + +// Test constructing and returning Go instances of GoObject and GoRunnable +// outside a constructor +func ConstructGoRunnable() *GoRunnable { + return new(GoRunnable) +} + +func ConstructGoObject() *GoObject { + return new(GoObject) +} + +// java.beans.PropertyChangeEvent is a class a with no default constructors. +type GoPCE struct { + beans.PropertyChangeEvent +} + +func NewGoPCE(_ lang.Object, _ string, _ lang.Object, _ lang.Object) *GoPCE { + return new(GoPCE) +} + +// java.util.ArrayList is a class with multiple constructors +type GoArrayList struct { + util.ArrayList +} + +func NewGoArrayList() *GoArrayList { + return new(GoArrayList) +} + +func NewGoArrayListWithCap(_ int32) *GoArrayList { + return new(GoArrayList) +} + +func UnwrapGoArrayList(l gopkg.GoArrayList) { + _ = l.Unwrap().(*GoArrayList) +} + +func CallSubset(s Character.Subset) { + s.ToString() +} + +type GoSubset struct { + Character.Subset +} + +func NewGoSubset(_ string) *GoSubset { + return new(GoSubset) +} + +func NewJavaObject() lang.Object { + return Object.New() +} + +func NewJavaInteger() lang.Integer { + i, _ := Integer.New(int32(42)) + return i +} + +type NoargConstructor struct { + util.BitSet // An otherwise unused class with a no-arg constructor +} + +type GoRand struct { + util.Random +} + +func (_ *GoRand) Next(this gopkg.GoRand, i int32) int32 { + return this.Super().Next(i) +} + +type I interface{} + +func CastInterface(intf I) lang.Runnable { + var r lang.Runnable = Runnable.Cast(intf) + r.Run() + return r +} + +func CastRunnable(o lang.Object) lang.Runnable { + defer func() { + recover() // swallow the panic + }() + var r lang.Runnable = Runnable.Cast(o) + r.Run() + return r +} + +// Test that extending classes from Java packages +// with the same last component (in this case "net") +// works. +func NameClashingPackages(_ net.Socket, _ xnet.SocketFactory) { +} + +func testReferenceToUnsupportedParameters() { + var ib nio.IntBuffer + ib.Put(nil) +} diff --git a/bind/testdata/testpkg/javapkg/java.go b/bind/testdata/testpkg/javapkg/java.go new file mode 100644 index 000000000..948f13a43 --- /dev/null +++ b/bind/testdata/testpkg/javapkg/java.go @@ -0,0 +1,57 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package javapkg + +import ( + "Java/java/lang/Float" + "Java/java/lang/Integer" + "Java/java/lang/System" + "Java/java/util/Collections" + "Java/java/util/jar/JarFile" + "fmt" +) + +func SystemCurrentTimeMillis() int64 { + return System.CurrentTimeMillis() +} + +func FloatMin() float32 { + return Float.MIN_VALUE +} + +func ManifestName() string { + return JarFile.MANIFEST_NAME +} + +func IntegerBytes() int { + return Integer.SIZE +} + +func IntegerValueOf(v int32) int32 { + i, _ := Integer.ValueOf(v) + return i.IntValue() +} + +func IntegerDecode(v string) (int32, error) { + i, err := Integer.Decode(v) + if err != nil { + return 0, fmt.Errorf("wrapped error: %v", err) + } + // Call methods from super class + i.HashCode() + return i.IntValue(), nil +} + +func IntegerParseInt(v string, radix int32) (int32, error) { + return Integer.ParseInt(v, radix) +} + +func ProvokeRuntimeException() (err error) { + defer func() { + err = recover().(error) + }() + Collections.Copy(nil, nil) + return +} diff --git a/bind/testdata/testpkg/objcpkg/classes.go b/bind/testdata/testpkg/objcpkg/classes.go new file mode 100644 index 000000000..608dd97dc --- /dev/null +++ b/bind/testdata/testpkg/objcpkg/classes.go @@ -0,0 +1,72 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objcpkg + +import ( + "ObjC/Foundation" + gopkg "ObjC/Objcpkg" + "ObjC/UIKit" +) + +const ( + DescriptionStr = "Descriptrion from Go" + Hash = 42 +) + +type GoNSDate struct { + Foundation.NSDate +} + +func (d *GoNSDate) Hash(self gopkg.GoNSDate) int { + return Hash +} + +func (d *GoNSDate) Description(self gopkg.GoNSDate) string { + // Test self call + if h := self.Hash(); h != Hash { + panic("hash mismatch") + } + return DescriptionStr +} + +func (d *GoNSDate) GetSelf(self gopkg.GoNSDate) Foundation.NSDate { + return self +} + +func NewGoNSDate() *GoNSDate { + return new(GoNSDate) +} + +type GoNSObject struct { + C Foundation.NSObjectC // The class + P Foundation.NSObjectP // The protocol + UseSelf bool +} + +func (o *GoNSObject) Description(self gopkg.GoNSObject) string { + if o.UseSelf { + return DescriptionStr + } else { + return self.Super().Description() + } +} + +func DupNSDate(date Foundation.NSDate) Foundation.NSDate { + return date +} + +type GoUIResponder struct { + UIKit.UIResponder + Called bool +} + +func (r *GoUIResponder) PressesBegan(_ Foundation.NSSet, _ UIKit.UIPressesEvent) { + r.Called = true +} + +// Check that implicitly referenced types are wrapped. +func implicitType(r UIKit.UIResponder) { + r.MotionBegan(0, nil) +} diff --git a/bind/testdata/testpkg/objcpkg/objc.go b/bind/testdata/testpkg/objcpkg/objc.go new file mode 100644 index 000000000..4c1b07ffd --- /dev/null +++ b/bind/testdata/testpkg/objcpkg/objc.go @@ -0,0 +1,47 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objcpkg + +import ( + "ObjC/Foundation/NSDate" + "ObjC/Foundation/NSString" + "ObjC/QuartzCore/CAMediaTimingFunction" +) + +func Func() { + NSDate.Date() + CAMediaTimingFunction.FunctionWithControlPoints(0, 0, 0, 0) +} + +func Method() string { + d := NSDate.Date() + return d.Description() +} + +func New() { + NSDate.New() + CAMediaTimingFunction.NewWithControlPoints(0, 0, 0, 0) +} + +func Error() { + str, err := NSString.StringWithContentsOfFileEncodingError("", 0) + if err == nil { + panic("no error from stringWithContentsOfFile") + } + // Assert err is an error + err = err.(error) + if str != "" { + panic("non-empty string from stringWithContentsOfFile") + } + str, err = NSString.NewWithContentsOfFileEncodingError("", 0) + if err == nil { + panic("no error from stringWithContentsOfFile") + } + // Assert err is an error + err = err.(error) + if str != "" { + panic("non-empty string from initWithContentsOfFile") + } +} diff --git a/bind/testdata/testpkg/secondpkg/secondpkg.go b/bind/testdata/testpkg/secondpkg/secondpkg.go new file mode 100644 index 000000000..b7e7cd5a1 --- /dev/null +++ b/bind/testdata/testpkg/secondpkg/secondpkg.go @@ -0,0 +1,44 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package secondpkg is imported by bind tests that verify +// that a bound package can reference another bound package. +package secondpkg + +type ( + Ser interface { + S(_ *S) + } + + IF interface { + F() + } + + I interface { + F(i int) int + } + + S struct{} +) + +func (_ *S) F(i int) int { + return i +} + +const HelloString = "secondpkg string" + +func Hello() string { + return HelloString +} + +type Secondpkg struct { + V string +} + +func (_ *Secondpkg) M() { +} + +func NewSecondpkg() *Secondpkg { + return new(Secondpkg) +} diff --git a/bind/testdata/testpkg/simplepkg/simplepkg.go b/bind/testdata/testpkg/simplepkg/simplepkg.go new file mode 100644 index 000000000..730c1bede --- /dev/null +++ b/bind/testdata/testpkg/simplepkg/simplepkg.go @@ -0,0 +1,16 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package simplepkg is imported from testpkg and tests two +// corner cases. +// First: simplepkg itself contains no (exported) functions +// or methods and so its generated Go package must not import +// it. +// +// Second: even though testpkg imports simplepkg, testpkg's +// generated Go package ends up not referencing simplepkg and +// must not import it. +package simplepkg + +type S struct{} diff --git a/bind/testdata/testpkg/tagged.go b/bind/testdata/testpkg/tagged.go new file mode 100644 index 000000000..b5fe898e5 --- /dev/null +++ b/bind/testdata/testpkg/tagged.go @@ -0,0 +1,11 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aaa && bbb +// +build aaa,bbb + +// This file tests that tags work with gomobile. +package testpkg + +const TaggedConst = 42 diff --git a/bind/testdata/testpkg/testpkg.go b/bind/testdata/testpkg/testpkg.go new file mode 100644 index 000000000..cd7a2ea04 --- /dev/null +++ b/bind/testdata/testpkg/testpkg.go @@ -0,0 +1,628 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package testpkg contains bound functions for testing the cgo-JNI interface. +// This is used in tests of golang.org/x/mobile/bind/java. +package testpkg + +//go:generate gobind -lang=go -outdir=go_testpkg . +//go:generate gobind -lang=java -outdir=. . +import ( + "context" + "errors" + "fmt" + "io/ioutil" + "log" + "math" + "os" + "runtime" + "syscall" + "time" + + "golang.org/x/mobile/asset" + + "golang.org/x/mobile/bind/testdata/testpkg/secondpkg" + "golang.org/x/mobile/bind/testdata/testpkg/simplepkg" + "golang.org/x/mobile/bind/testdata/testpkg/unboundpkg" +) + +const ( + AString = "a string" + AnInt = 7 + ABool = true + AFloat = 0.12345 + + MinInt32 int32 = math.MinInt32 + MaxInt32 int32 = math.MaxInt32 + MinInt64 = math.MinInt64 + MaxInt64 = math.MaxInt64 + SmallestNonzeroFloat64 = math.SmallestNonzeroFloat64 + MaxFloat64 = math.MaxFloat64 + SmallestNonzeroFloat32 float32 = math.SmallestNonzeroFloat64 + MaxFloat32 float32 = math.MaxFloat32 + Log2E = math.Log2E +) + +var ( + StringVar = "a string var" + IntVar = 77 + StructVar = &S{name: "a struct var"} + InterfaceVar I + InterfaceVar2 I2 + NodeVar = &Node{V: "a struct var"} +) + +type Nummer interface { + Num() +} + +type I interface { + F() + + E() error + V() int + VE() (int, error) + I() I + S() *S + StoString(seq *S) string + + String() string +} + +func CallF(i I) { + i.F() +} + +func CallE(i I) error { + return i.E() +} + +func CallV(i I) int { + return i.V() +} + +func CallVE(i I) (int, error) { + return i.VE() +} + +func CallI(i I) I { + return i +} + +func CallS(i I) *S { + return &S{} +} + +var keep []I + +func Keep(i I) { + keep = append(keep, i) +} + +var numSCollected int + +type S struct { + // *S already has a finalizer, so we need another object + // to count successful collections. + innerObj *int + + name string +} + +func (s *S) F() { + fmt.Printf("called F on *S{%s}\n", s.name) +} + +func (s *S) String() string { + return s.name +} + +func finalizeInner(a *int) { + numSCollected++ +} + +var seq = 0 + +func New() *S { + s := &S{innerObj: new(int), name: fmt.Sprintf("new%d", seq)} + runtime.SetFinalizer(s.innerObj, finalizeInner) + return s +} + +func GC() { + runtime.GC() + time.Sleep(10 * time.Millisecond) + runtime.GC() +} + +func Add(x, y int) int { + return x + y +} + +func NumSCollected() int { + return numSCollected +} + +func I2Dup(i I2) I2 { + return i +} + +func IDup(i I) I { + return i +} + +func StrDup(s string) string { + return s +} + +func Negate(x bool) bool { + return !x +} + +func Err(s string) error { + if s != "" { + return errors.New(s) + } + return nil +} + +func BytesAppend(a []byte, b []byte) []byte { + return append(a, b...) +} + +func AppendToString(str string, someBytes []byte) []byte { + a := []byte(str) + fmt.Printf("str=%q (len=%d), someBytes=%v (len=%d)\n", str, len(str), someBytes, len(someBytes)) + return append(a, someBytes...) +} + +func UnnamedParams(_, _ int, p0 string) int { + return len(p0) +} + +type Node struct { + V string + Next *Node + Err error +} + +func NewNode(name string) *Node { + return &Node{V: name} +} + +func (a *Node) String() string { + if a == nil { + return "" + } + return a.V + ":" + a.Next.String() +} + +type Receiver interface { + Hello(message string) +} + +func Hello(r Receiver, name string) { + r.Hello(fmt.Sprintf("Hello, %s!\n", name)) +} + +func GarbageCollect() { + runtime.GC() +} + +type ( + Concrete struct{} + + Interface interface { + F() + } +) + +func (_ *Concrete) F() { +} + +func NewConcrete() *Concrete { + return new(Concrete) +} + +func ReadAsset() string { + rc, err := asset.Open("hello.txt") + if err != nil { + log.Fatal(err) + } + defer rc.Close() + + b, err := ioutil.ReadAll(rc) + if err != nil { + log.Fatal(err) + } + return string(b) +} + +type GoCallback interface { + VarUpdate() +} + +func CallWithCallback(gcb GoCallback) { + for i := 0; i < 1000; i++ { + gcb.VarUpdate() + } +} + +type NullTest interface { + Null() NullTest +} + +func NewNullInterface() I { + return nil +} + +func NewNullStruct() *S { + return nil +} + +func CallWithNull(_null NullTest, nuller NullTest) bool { + return _null == nil && nuller.Null() == nil +} + +type Issue20330 struct{} + +func NewIssue20330() *Issue20330 { + return new(Issue20330) +} + +func (i *Issue20330) CallWithNull(_null *Issue20330) bool { + return _null == nil +} + +type Issue14168 interface { + F(seq int32) +} + +func ReadIntoByteArray(s []byte) (int, error) { + if len(s) != cap(s) { + return 0, fmt.Errorf("cap %d != len %d", cap(s), len(s)) + } + for i := 0; i < len(s); i++ { + s[i] = byte(i) + } + return len(s), nil +} + +type B interface { + B(b []byte) +} + +func PassByteArray(b B) { + b.B([]byte{1, 2, 3, 4}) +} + +func GoroutineCallback(r Receiver) { + done := make(chan struct{}) + go func() { + // Run it multiple times to increase the chance that the goroutine + // will use different threads for the call. Use a long argument string to + // make sure the JNI calls take more time. + for i := 0; i < 100000; i++ { + r.Hello("HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello") + } + close(done) + }() + <-done +} + +func Hi() { + fmt.Println("Hi") +} + +func Int(x int32) { + fmt.Println("Received int32", x) +} + +type I2 interface { + Times(v int32) int64 + Error(triggerError bool) error + + StringError(s string) (string, error) +} + +type myI2 struct{} + +func (_ *myI2) Times(v int32) int64 { + return int64(v) * 10 +} + +func (_ *myI2) Error(e bool) error { + if e { + return errors.New("some error") + } + return nil +} + +func (_ *myI2) StringError(s string) (string, error) { + return s, nil +} + +func CallIError(i I2, triggerError bool) error { + return i.Error(triggerError) +} + +func CallIStringError(i I2, s string) (string, error) { + return i.StringError(s) +} + +func NewI() I2 { + return &myI2{} +} + +var pinnedI = make(map[int32]I2) + +func RegisterI(idx int32, i I2) { + pinnedI[idx] = i +} + +func UnregisterI(idx int32) { + delete(pinnedI, idx) +} + +func Multiply(idx int32, val int32) int64 { + i, ok := pinnedI[idx] + if !ok { + panic(fmt.Sprintf("unknown I2 with index %d", idx)) + } + return i.Times(val) +} + +func AppendHello(s string) string { + return fmt.Sprintf("Hello, %s!", s) +} + +func ReturnsError(b bool) (string, error) { + if b { + return "", errors.New("Error") + } + return "OK", nil +} + +var collectS2 = make(chan struct{}, 100) + +func finalizeS(a *S2) { + collectS2 <- struct{}{} +} + +func CollectS2(want, timeoutSec int) int { + runtime.GC() + + tick := time.NewTicker(time.Duration(timeoutSec) * time.Second) + defer tick.Stop() + + for i := 0; i < want; i++ { + select { + case <-collectS2: + case <-tick.C: + fmt.Println("CollectS: timed out") + return i + } + } + return want +} + +type S2 struct { + X, Y float64 + unexported bool +} + +func NewS2(x, y float64) *S2 { + s := &S2{X: x, Y: y} + runtime.SetFinalizer(s, finalizeS) + return s +} + +func (_ *S2) TryTwoStrings(first, second string) string { + return first + second +} + +func (s *S2) Sum() float64 { + return s.X + s.Y +} + +func CallSSum(s *S2) float64 { + return s.Sum() +} + +// Issue #13033 +type NullFieldStruct struct { + F *S +} + +func NewNullFieldStruct() *NullFieldStruct { + return &NullFieldStruct{} +} + +var ( + ImportedVarI secondpkg.I = NewImportedI() + ImportedVarS *secondpkg.S = NewImportedS() +) + +type ( + ImportedFields struct { + I secondpkg.I + S *secondpkg.S + } + + ImportedI interface { + F(_ secondpkg.I) + } + + AnSer struct{} +) + +func (_ *AnSer) S(_ *secondpkg.S) { +} + +func NewImportedFields() *ImportedFields { + return &ImportedFields{ + I: NewImportedI(), + S: NewImportedS(), + } +} + +func NewImportedI() secondpkg.I { + return NewImportedS() +} + +func NewImportedS() *secondpkg.S { + return new(secondpkg.S) +} + +func WithImportedI(i secondpkg.I) secondpkg.I { + return i +} + +func WithImportedS(s *secondpkg.S) *secondpkg.S { + return s +} + +func CallImportedI(i secondpkg.I) { + i.F(0) +} + +func NewSer() *AnSer { + return nil +} + +func NewSimpleS() *simplepkg.S { + return nil +} + +func UnboundS(_ *unboundpkg.S) { +} + +func UnboundI(_ unboundpkg.I) { +} + +type ( + InterfaceDupper interface { + IDup(i Interface) Interface + } + + ConcreteDupper interface { + CDup(c *Concrete) *Concrete + } +) + +func CallIDupper(d InterfaceDupper) bool { + var want Interface = new(Concrete) + got := d.IDup(want) + return got == want +} + +func CallCDupper(d ConcreteDupper) bool { + want := new(Concrete) + got := d.CDup(want) + return got == want +} + +type EmptyErrorer interface { + EmptyError() error +} + +func EmptyError() error { + return errors.New("") +} + +func CallEmptyError(c EmptyErrorer) error { + return c.EmptyError() +} + +func Init() {} + +type InitCaller struct{} + +func NewInitCaller() *InitCaller { + return new(InitCaller) +} + +func (ic *InitCaller) Init() {} + +type Issue17073 interface { + OnError(err error) +} + +func ErrorMessage(err error) string { + return err.Error() +} + +var GlobalErr error = errors.New("global err") + +func IsGlobalErr(err error) bool { + return GlobalErr == err +} + +type S3 struct { +} + +type S4 struct { + I int +} + +func NewS4WithInt(i int) *S4 { + return &S4{i} +} + +func NewS4WithFloat(f float64) *S4 { + return &S4{int(f)} +} + +func NewS4WithBoolAndError(b bool) (*S4, error) { + if b { + return nil, errors.New("some error") + } + return new(S4), nil +} + +// Lifted from TestEPIPE in package os. +func TestSIGPIPE() { + r, w, err := os.Pipe() + if err != nil { + panic(err) + } + if err := r.Close(); err != nil { + panic(err) + } + + _, err = w.Write([]byte("hi")) + if err == nil { + panic("unexpected success of Write to broken pipe") + } + if pe, ok := err.(*os.PathError); ok { + err = pe.Err + } + if se, ok := err.(*os.SyscallError); ok { + err = se.Err + } + if err != syscall.EPIPE { + panic(fmt.Errorf("got %v, expected EPIPE", err)) + } +} + +// Testpkg is an empty interface with the same name as its package. +type Testpkg interface{} + +func ClashingParameterFromOtherPackage(_ *secondpkg.Secondpkg) {} + +type MyStruct struct { +} + +// Test that constructors with incompatible signatures are ignored. +func NewMyStruct(ctx context.Context) *MyStruct { + return nil +} + +type Int32Constructed struct{} + +// Test that constuctors that clash with the internal proxy constructor +// are skipped. +func NewInt32Constructed(i int32) *Int32Constructed { + return nil +} diff --git a/bind/testdata/testpkg/unboundpkg/unboundpkg.go b/bind/testdata/testpkg/unboundpkg/unboundpkg.go new file mode 100644 index 000000000..985b2cb14 --- /dev/null +++ b/bind/testdata/testpkg/unboundpkg/unboundpkg.go @@ -0,0 +1,12 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package simplepkg is imported from testpkg and tests +// that references to other, unbound packages, are ignored. +package unboundpkg + +type ( + S struct{} + I interface{} +) diff --git a/bind/testdata/try.go b/bind/testdata/try.go new file mode 100644 index 000000000..5d3d21787 --- /dev/null +++ b/bind/testdata/try.go @@ -0,0 +1,9 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package try has a name that is a Java keyword. +// Gobind has to translate it usefully. See Issue #12273. +package try + +func This() string { return "This" } diff --git a/bind/testdata/try.go.golden b/bind/testdata/try.go.golden new file mode 100644 index 000000000..9d0322c61 --- /dev/null +++ b/bind/testdata/try.go.golden @@ -0,0 +1,30 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package try. +// +// autogenerated by gobind -lang=go try +package main + +/* +#include +#include +#include "seq.h" +#include "try.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "try" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxytry__This +func proxytry__This() C.nstring { + res_0 := try.This() + _res_0 := encodeString(res_0) + return _res_0 +} diff --git a/bind/testdata/try.java.c.golden b/bind/testdata/try.java.c.golden new file mode 100644 index 000000000..0099fa07c --- /dev/null +++ b/bind/testdata/try.java.c.golden @@ -0,0 +1,25 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java try + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "try.h" + + +JNIEXPORT void JNICALL +Java_try_1_Try__1init(JNIEnv *env, jclass _unused) { + jclass clazz; +} + +JNIEXPORT jstring JNICALL +Java_try_1_Try_this_1(JNIEnv* env, jclass _clazz) { + nstring r0 = proxytry__This(); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + diff --git a/bind/testdata/try.java.golden b/bind/testdata/try.java.golden new file mode 100644 index 000000000..e7c7adb4c --- /dev/null +++ b/bind/testdata/try.java.golden @@ -0,0 +1,26 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class try_.Try is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java try +package try_; + +import go.Seq; + +public abstract class Try { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Try() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + + + public static native String this_(); +} diff --git a/bind/testdata/try.java.h.golden b/bind/testdata/try.java.h.golden new file mode 100644 index 000000000..ffa4ed96b --- /dev/null +++ b/bind/testdata/try.java.h.golden @@ -0,0 +1,12 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java try + +#ifndef __Try_H__ +#define __Try_H__ + +#include + +#endif diff --git a/bind/testdata/try.objc.go.h.golden b/bind/testdata/try.objc.go.h.golden new file mode 100644 index 000000000..2b0531674 --- /dev/null +++ b/bind/testdata/try.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to try Go package. +// gobind -lang=objc try +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_try_H__ +#define __GO_try_H__ + +#include +#include +#endif diff --git a/bind/testdata/try.objc.h.golden b/bind/testdata/try.objc.h.golden new file mode 100644 index 000000000..f72f7cc38 --- /dev/null +++ b/bind/testdata/try.objc.h.golden @@ -0,0 +1,16 @@ +// Objective-C API for talking to try Go package. +// gobind -lang=objc try +// +// File is generated by gobind. Do not edit. + +#ifndef __Try_H__ +#define __Try_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +FOUNDATION_EXPORT NSString* _Nonnull TryThis(void); + +#endif diff --git a/bind/testdata/try.objc.m.golden b/bind/testdata/try.objc.m.golden new file mode 100644 index 000000000..a8d639209 --- /dev/null +++ b/bind/testdata/try.objc.m.golden @@ -0,0 +1,20 @@ +// Objective-C API for talking to try Go package. +// gobind -lang=objc try +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Try.objc.h" + + +NSString* _Nonnull TryThis(void) { + nstring r0 = proxytry__This(); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/underscores.go b/bind/testdata/underscores.go new file mode 100644 index 000000000..e13f25d71 --- /dev/null +++ b/bind/testdata/underscores.go @@ -0,0 +1,13 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package underscore_pkg + +type Underscore_struct struct { + Underscore_field string +} + +var Underscore_var int + +func Underscore_func() {} diff --git a/bind/testdata/underscores.go.golden b/bind/testdata/underscores.go.golden new file mode 100644 index 000000000..040bf36a4 --- /dev/null +++ b/bind/testdata/underscores.go.golden @@ -0,0 +1,61 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package underscore_pkg. +// +// autogenerated by gobind -lang=go underscores +package main + +/* +#include +#include +#include "seq.h" +#include "underscore_pkg.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "underscores" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxyunderscore_pkg_Underscore_struct_Underscore_field_Set +func proxyunderscore_pkg_Underscore_struct_Underscore_field_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v := decodeString(v) + ref.Get().(*underscore_pkg.Underscore_struct).Underscore_field = _v +} + +//export proxyunderscore_pkg_Underscore_struct_Underscore_field_Get +func proxyunderscore_pkg_Underscore_struct_Underscore_field_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*underscore_pkg.Underscore_struct).Underscore_field + _v := encodeString(v) + return _v +} + +//export new_underscore_pkg_Underscore_struct +func new_underscore_pkg_Underscore_struct() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(underscore_pkg.Underscore_struct))) +} + +//export var_setunderscore_pkg_Underscore_var +func var_setunderscore_pkg_Underscore_var(v C.nint) { + _v := int(v) + underscore_pkg.Underscore_var = _v +} + +//export var_getunderscore_pkg_Underscore_var +func var_getunderscore_pkg_Underscore_var() C.nint { + v := underscore_pkg.Underscore_var + _v := C.nint(v) + return _v +} + +//export proxyunderscore_pkg__Underscore_func +func proxyunderscore_pkg__Underscore_func() { + underscore_pkg.Underscore_func() +} diff --git a/bind/testdata/underscores.java.c.golden b/bind/testdata/underscores.java.c.golden new file mode 100644 index 000000000..b791d426c --- /dev/null +++ b/bind/testdata/underscores.java.c.golden @@ -0,0 +1,61 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java underscores + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "underscore_pkg.h" + +jclass proxy_class_underscore_pkg_Underscore_struct; +jmethodID proxy_class_underscore_pkg_Underscore_struct_cons; + +JNIEXPORT void JNICALL +Java_underscore_1pkg_Underscore_1pkg__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "underscore_pkg/Underscore_struct"); + proxy_class_underscore_pkg_Underscore_struct = (*env)->NewGlobalRef(env, clazz); + proxy_class_underscore_pkg_Underscore_struct_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); +} + +JNIEXPORT void JNICALL +Java_underscore_1pkg_Underscore_1pkg_underscore_1func(JNIEnv* env, jclass _clazz) { + proxyunderscore_pkg__Underscore_func(); +} + +JNIEXPORT jint JNICALL +Java_underscore_1pkg_Underscore_1struct__1_1New(JNIEnv *env, jclass clazz) { + return new_underscore_pkg_Underscore_struct(); +} + +JNIEXPORT void JNICALL +Java_underscore_1pkg_Underscore_1struct_setUnderscore_1field(JNIEnv *env, jobject this, jstring v) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring _v = go_seq_from_java_string(env, v); + proxyunderscore_pkg_Underscore_struct_Underscore_field_Set(o, _v); +} + +JNIEXPORT jstring JNICALL +Java_underscore_1pkg_Underscore_1struct_getUnderscore_1field(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum_go(env, this); + nstring r0 = proxyunderscore_pkg_Underscore_struct_Underscore_field_Get(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT void JNICALL +Java_underscore_1pkg_Underscore_1pkg_setUnderscore_1var(JNIEnv *env, jclass clazz, jlong v) { + nint _v = (nint)v; + var_setunderscore_pkg_Underscore_var(_v); +} + +JNIEXPORT jlong JNICALL +Java_underscore_1pkg_Underscore_1pkg_getUnderscore_1var(JNIEnv *env, jclass clazz) { + nint r0 = var_getunderscore_pkg_Underscore_var(); + jlong _r0 = (jlong)r0; + return _r0; +} + diff --git a/bind/testdata/underscores.java.golden b/bind/testdata/underscores.java.golden new file mode 100644 index 000000000..3624f9d0d --- /dev/null +++ b/bind/testdata/underscores.java.golden @@ -0,0 +1,86 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class underscore_pkg.Underscore_struct is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java underscores +package underscore_pkg; + +import go.Seq; + +public final class Underscore_struct implements Seq.Proxy { + static { Underscore_pkg.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + Underscore_struct(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public Underscore_struct() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + public final native String getUnderscore_field(); + public final native void setUnderscore_field(String v); + + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof Underscore_struct)) { + return false; + } + Underscore_struct that = (Underscore_struct)o; + String thisUnderscore_field = getUnderscore_field(); + String thatUnderscore_field = that.getUnderscore_field(); + if (thisUnderscore_field == null) { + if (thatUnderscore_field != null) { + return false; + } + } else if (!thisUnderscore_field.equals(thatUnderscore_field)) { + return false; + } + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {getUnderscore_field()}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("Underscore_struct").append("{"); + b.append("Underscore_field:").append(getUnderscore_field()).append(","); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class underscore_pkg.Underscore_pkg is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java underscores +package underscore_pkg; + +import go.Seq; + +public abstract class Underscore_pkg { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Underscore_pkg() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + + + public static native void setUnderscore_var(long v); + public static native long getUnderscore_var(); + + public static native void underscore_func(); +} diff --git a/bind/testdata/underscores.java.h.golden b/bind/testdata/underscores.java.h.golden new file mode 100644 index 000000000..1545890ba --- /dev/null +++ b/bind/testdata/underscores.java.h.golden @@ -0,0 +1,14 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java underscores + +#ifndef __Underscore_pkg_H__ +#define __Underscore_pkg_H__ + +#include + +extern jclass proxy_class_underscore_pkg_Underscore_struct; +extern jmethodID proxy_class_underscore_pkg_Underscore_struct_cons; +#endif diff --git a/bind/testdata/underscores.objc.go.h.golden b/bind/testdata/underscores.objc.go.h.golden new file mode 100644 index 000000000..d7c8dfe88 --- /dev/null +++ b/bind/testdata/underscores.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to underscores Go package. +// gobind -lang=objc underscores +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_underscore_pkg_H__ +#define __GO_underscore_pkg_H__ + +#include +#include +#endif diff --git a/bind/testdata/underscores.objc.h.golden b/bind/testdata/underscores.objc.h.golden new file mode 100644 index 000000000..3daaec06c --- /dev/null +++ b/bind/testdata/underscores.objc.h.golden @@ -0,0 +1,33 @@ +// Objective-C API for talking to underscores Go package. +// gobind -lang=objc underscores +// +// File is generated by gobind. Do not edit. + +#ifndef __Underscore_pkg_H__ +#define __Underscore_pkg_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class Underscore_pkgUnderscore_struct; + +@interface Underscore_pkgUnderscore_struct : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +@property (nonatomic) NSString* _Nonnull underscore_field; +@end + +@interface Underscore_pkg : NSObject ++ (long) underscore_var; ++ (void) setUnderscore_var:(long)v; + +@end + +FOUNDATION_EXPORT void Underscore_pkgUnderscore_func(void); + +#endif diff --git a/bind/testdata/underscores.objc.m.golden b/bind/testdata/underscores.objc.m.golden new file mode 100644 index 000000000..a985755e7 --- /dev/null +++ b/bind/testdata/underscores.objc.m.golden @@ -0,0 +1,66 @@ +// Objective-C API for talking to underscores Go package. +// gobind -lang=objc underscores +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Underscore_pkg.objc.h" + + +@implementation Underscore_pkgUnderscore_struct { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_underscore_pkg_Underscore_struct()); + } + return self; +} + +- (NSString* _Nonnull)underscore_field { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxyunderscore_pkg_Underscore_struct_Underscore_field_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + +- (void)setUnderscore_field:(NSString* _Nonnull)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxyunderscore_pkg_Underscore_struct_Underscore_field_Set(refnum, _v); +} + +@end + + +@implementation Underscore_pkg ++ (void) setUnderscore_var:(long)v { + nint _v = (nint)v; + var_setunderscore_pkg_Underscore_var(_v); +} + ++ (long) underscore_var { + nint r0 = var_getunderscore_pkg_Underscore_var(); + long _r0 = (long)r0; + return _r0; +} + +@end + + +void Underscore_pkgUnderscore_func(void) { + proxyunderscore_pkg__Underscore_func(); +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/universe.golden b/bind/testdata/universe.golden new file mode 100644 index 000000000..1bb2a7395 --- /dev/null +++ b/bind/testdata/universe.golden @@ -0,0 +1,43 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package universe. +// +// autogenerated by gobind -lang=go +package main + +/* +#include +#include +#include "seq.h" +#include "universe.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export proxy_error_Error +func proxy_error_Error(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(error) + res_0 := v.Error() + _res_0 := encodeString(res_0) + return _res_0 +} + +type proxy_error _seq.Ref + +func (p *proxy_error) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +func (p *proxy_error) Error() string { + res := C.cproxy_error_Error(C.int32_t(p.Bind_proxy_refnum__())) + _res := decodeString(res) + return _res +} diff --git a/bind/testdata/universe.java.c.golden b/bind/testdata/universe.java.c.golden new file mode 100644 index 000000000..1b4a2c8e9 --- /dev/null +++ b/bind/testdata/universe.java.c.golden @@ -0,0 +1,43 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "universe.h" + +jclass proxy_class__error; +jmethodID proxy_class__error_cons; +static jmethodID mid_error_Error; + +JNIEXPORT void JNICALL +Java_go_Universe__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "go/Universe$proxyerror"); + proxy_class__error = (*env)->NewGlobalRef(env, clazz); + proxy_class__error_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "java/lang/Throwable"); + mid_error_Error = (*env)->GetMethodID(env, clazz, "getMessage", "()Ljava/lang/String;"); +} + +JNIEXPORT jstring JNICALL +Java_go_Universe_00024proxyerror_error(JNIEnv* env, jobject __this__) { + int32_t o = go_seq_to_refnum_go(env, __this__); + nstring r0 = proxy_error_Error(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +nstring cproxy_error_Error(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(0); + jobject o = go_seq_from_refnum(env, refnum, proxy_class__error, proxy_class__error_cons); + jstring res = (*env)->CallObjectMethod(env, o, mid_error_Error); + nstring _res = go_seq_from_java_string(env, res); + go_seq_pop_local_frame(env); + return _res; +} + diff --git a/bind/testdata/universe.java.golden b/bind/testdata/universe.java.golden new file mode 100644 index 000000000..6e49eaf98 --- /dev/null +++ b/bind/testdata/universe.java.golden @@ -0,0 +1,53 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class go.error is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java +package go; + +import go.Seq; + +public interface error { + public String error(); + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class go.Universe is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java +package go; + +import go.Seq; + +public abstract class Universe { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Universe() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyerror extends Exception implements Seq.Proxy, error { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyerror(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + @Override public String getMessage() { return error(); } + + public native String error(); + } + + +} diff --git a/bind/testdata/universe.java.h.golden b/bind/testdata/universe.java.h.golden new file mode 100644 index 000000000..cd0b1e790 --- /dev/null +++ b/bind/testdata/universe.java.h.golden @@ -0,0 +1,17 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java + +#ifndef __Universe_H__ +#define __Universe_H__ + +#include + +extern jclass proxy_class__error; +extern jmethodID proxy_class__error_cons; + +nstring cproxy_error_Error(int32_t refnum); + +#endif diff --git a/bind/testdata/universe.objc.go.h.golden b/bind/testdata/universe.objc.go.h.golden new file mode 100644 index 000000000..dec178551 --- /dev/null +++ b/bind/testdata/universe.objc.go.h.golden @@ -0,0 +1,13 @@ +// Objective-C API for talking to Go package. +// gobind -lang=objc +// +// File is generated by gobind. Do not edit. + +#ifndef __GO__H__ +#define __GO__H__ + +#include +#include +nstring cproxy_error_Error(int32_t refnum); + +#endif diff --git a/bind/testdata/universe.objc.h.golden b/bind/testdata/universe.objc.h.golden new file mode 100644 index 000000000..019e7502d --- /dev/null +++ b/bind/testdata/universe.objc.h.golden @@ -0,0 +1,29 @@ +// Objective-C API for talking to Go package. +// gobind -lang=objc +// +// File is generated by gobind. Do not edit. + +#ifndef __Universe_H__ +#define __Universe_H__ + +@import Foundation; +#include "ref.h" + +@protocol Universeerror; +@class Universeerror; + +@protocol Universeerror +- (NSString* _Nonnull)error; +@end + +@class Universeerror; + +@interface Universeerror : NSError { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (NSString* _Nonnull)error; +@end + +#endif diff --git a/bind/testdata/universe.objc.m.golden b/bind/testdata/universe.objc.m.golden new file mode 100644 index 000000000..369f238d5 --- /dev/null +++ b/bind/testdata/universe.objc.m.golden @@ -0,0 +1,45 @@ +// Objective-C API for talking to Go package. +// gobind -lang=objc +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Universe.objc.h" + +@implementation Universeerror { +} + +- (nonnull instancetype)initWithRef:(id)ref { + if (self) { + __ref = ref; + self = [super initWithDomain:@"go" code:1 userInfo:@{NSLocalizedDescriptionKey: [self error]}]; + } + return self; +} + +- (NSString* _Nonnull)error { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxy_error_Error(refnum); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; +} + +@end + + + +nstring cproxy_error_Error(int32_t refnum) { + @autoreleasepool { + Universeerror* o = go_seq_objc_from_refnum(refnum); + NSString* _Nonnull ret0_; + ret0_ = [o localizedDescription]; + nstring _ret0_ = go_seq_from_objc_string(ret0_); + return _ret0_; + } +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/vars.go b/bind/testdata/vars.go new file mode 100644 index 000000000..a86397098 --- /dev/null +++ b/bind/testdata/vars.go @@ -0,0 +1,24 @@ +package vars + +var ( + AString = "String" + + AnInt = -1 + AnInt8 int8 = 8 + AnInt16 int16 = 16 + AnInt32 int32 = 32 + AnInt64 int64 = 64 + + AFloat = -2.0 + AFloat32 float32 = 32.0 + AFloat64 float64 = 64.0 + + ABool = true + + AStructPtr *S + AnInterface I +) + +type S struct{} + +type I interface{} diff --git a/bind/testdata/vars.go.golden b/bind/testdata/vars.go.golden new file mode 100644 index 000000000..f86d44650 --- /dev/null +++ b/bind/testdata/vars.go.golden @@ -0,0 +1,211 @@ +// Code generated by gobind. DO NOT EDIT. + +// Package main is an autogenerated binder stub for package vars. +// +// autogenerated by gobind -lang=go vars +package main + +/* +#include +#include +#include "seq.h" +#include "vars.h" + +*/ +import "C" + +import ( + _seq "golang.org/x/mobile/bind/seq" + "vars" +) + +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +//export new_vars_S +func new_vars_S() C.int32_t { + return C.int32_t(_seq.ToRefNum(new(vars.S))) +} + +type proxyvars_I _seq.Ref + +func (p *proxyvars_I) Bind_proxy_refnum__() int32 { + return (*_seq.Ref)(p).Bind_IncNum() +} + +//export var_setvars_ABool +func var_setvars_ABool(v C.char) { + _v := v != 0 + vars.ABool = _v +} + +//export var_getvars_ABool +func var_getvars_ABool() C.char { + v := vars.ABool + var _v C.char = 0 + if v { + _v = 1 + } + return _v +} + +//export var_setvars_AFloat +func var_setvars_AFloat(v C.double) { + _v := float64(v) + vars.AFloat = _v +} + +//export var_getvars_AFloat +func var_getvars_AFloat() C.double { + v := vars.AFloat + _v := C.double(v) + return _v +} + +//export var_setvars_AFloat32 +func var_setvars_AFloat32(v C.float) { + _v := float32(v) + vars.AFloat32 = _v +} + +//export var_getvars_AFloat32 +func var_getvars_AFloat32() C.float { + v := vars.AFloat32 + _v := C.float(v) + return _v +} + +//export var_setvars_AFloat64 +func var_setvars_AFloat64(v C.double) { + _v := float64(v) + vars.AFloat64 = _v +} + +//export var_getvars_AFloat64 +func var_getvars_AFloat64() C.double { + v := vars.AFloat64 + _v := C.double(v) + return _v +} + +//export var_setvars_AString +func var_setvars_AString(v C.nstring) { + _v := decodeString(v) + vars.AString = _v +} + +//export var_getvars_AString +func var_getvars_AString() C.nstring { + v := vars.AString + _v := encodeString(v) + return _v +} + +//export var_setvars_AStructPtr +func var_setvars_AStructPtr(v C.int32_t) { + // Must be a Go object + var _v *vars.S + if _v_ref := _seq.FromRefNum(int32(v)); _v_ref != nil { + _v = _v_ref.Get().(*vars.S) + } + vars.AStructPtr = _v +} + +//export var_getvars_AStructPtr +func var_getvars_AStructPtr() C.int32_t { + v := vars.AStructPtr + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export var_setvars_AnInt +func var_setvars_AnInt(v C.nint) { + _v := int(v) + vars.AnInt = _v +} + +//export var_getvars_AnInt +func var_getvars_AnInt() C.nint { + v := vars.AnInt + _v := C.nint(v) + return _v +} + +//export var_setvars_AnInt16 +func var_setvars_AnInt16(v C.int16_t) { + _v := int16(v) + vars.AnInt16 = _v +} + +//export var_getvars_AnInt16 +func var_getvars_AnInt16() C.int16_t { + v := vars.AnInt16 + _v := C.int16_t(v) + return _v +} + +//export var_setvars_AnInt32 +func var_setvars_AnInt32(v C.int32_t) { + _v := int32(v) + vars.AnInt32 = _v +} + +//export var_getvars_AnInt32 +func var_getvars_AnInt32() C.int32_t { + v := vars.AnInt32 + _v := C.int32_t(v) + return _v +} + +//export var_setvars_AnInt64 +func var_setvars_AnInt64(v C.int64_t) { + _v := int64(v) + vars.AnInt64 = _v +} + +//export var_getvars_AnInt64 +func var_getvars_AnInt64() C.int64_t { + v := vars.AnInt64 + _v := C.int64_t(v) + return _v +} + +//export var_setvars_AnInt8 +func var_setvars_AnInt8(v C.int8_t) { + _v := int8(v) + vars.AnInt8 = _v +} + +//export var_getvars_AnInt8 +func var_getvars_AnInt8() C.int8_t { + v := vars.AnInt8 + _v := C.int8_t(v) + return _v +} + +//export var_setvars_AnInterface +func var_setvars_AnInterface(v C.int32_t) { + var _v vars.I + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if v < 0 { // go object + _v = _v_ref.Get().(vars.I) + } else { // foreign object + _v = (*proxyvars_I)(_v_ref) + } + } + vars.AnInterface = _v +} + +//export var_getvars_AnInterface +func var_getvars_AnInterface() C.int32_t { + v := vars.AnInterface + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} diff --git a/bind/testdata/vars.java.c.golden b/bind/testdata/vars.java.c.golden new file mode 100644 index 000000000..014fce6a1 --- /dev/null +++ b/bind/testdata/vars.java.c.golden @@ -0,0 +1,191 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI functions for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java vars + +#include +#include +#include "seq.h" +#include "_cgo_export.h" +#include "vars.h" + +jclass proxy_class_vars_I; +jmethodID proxy_class_vars_I_cons; +jclass proxy_class_vars_S; +jmethodID proxy_class_vars_S_cons; + +JNIEXPORT void JNICALL +Java_vars_Vars__1init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "vars/S"); + proxy_class_vars_S = (*env)->NewGlobalRef(env, clazz); + proxy_class_vars_S_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "vars/Vars$proxyI"); + proxy_class_vars_I = (*env)->NewGlobalRef(env, clazz); + proxy_class_vars_I_cons = (*env)->GetMethodID(env, clazz, "", "(I)V"); + clazz = (*env)->FindClass(env, "vars/I"); + +} + +JNIEXPORT jint JNICALL +Java_vars_S__1_1New(JNIEnv *env, jclass clazz) { + return new_vars_S(); +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setABool(JNIEnv *env, jclass clazz, jboolean v) { + char _v = (char)v; + var_setvars_ABool(_v); +} + +JNIEXPORT jboolean JNICALL +Java_vars_Vars_getABool(JNIEnv *env, jclass clazz) { + char r0 = var_getvars_ABool(); + jboolean _r0 = r0 ? JNI_TRUE : JNI_FALSE; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAFloat(JNIEnv *env, jclass clazz, jdouble v) { + double _v = (double)v; + var_setvars_AFloat(_v); +} + +JNIEXPORT jdouble JNICALL +Java_vars_Vars_getAFloat(JNIEnv *env, jclass clazz) { + double r0 = var_getvars_AFloat(); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAFloat32(JNIEnv *env, jclass clazz, jfloat v) { + float _v = (float)v; + var_setvars_AFloat32(_v); +} + +JNIEXPORT jfloat JNICALL +Java_vars_Vars_getAFloat32(JNIEnv *env, jclass clazz) { + float r0 = var_getvars_AFloat32(); + jfloat _r0 = (jfloat)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAFloat64(JNIEnv *env, jclass clazz, jdouble v) { + double _v = (double)v; + var_setvars_AFloat64(_v); +} + +JNIEXPORT jdouble JNICALL +Java_vars_Vars_getAFloat64(JNIEnv *env, jclass clazz) { + double r0 = var_getvars_AFloat64(); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAString(JNIEnv *env, jclass clazz, jstring v) { + nstring _v = go_seq_from_java_string(env, v); + var_setvars_AString(_v); +} + +JNIEXPORT jstring JNICALL +Java_vars_Vars_getAString(JNIEnv *env, jclass clazz) { + nstring r0 = var_getvars_AString(); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAStructPtr(JNIEnv *env, jclass clazz, jobject v) { + int32_t _v = go_seq_to_refnum(env, v); + var_setvars_AStructPtr(_v); +} + +JNIEXPORT jobject JNICALL +Java_vars_Vars_getAStructPtr(JNIEnv *env, jclass clazz) { + int32_t r0 = var_getvars_AStructPtr(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_vars_S, proxy_class_vars_S_cons); + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAnInt(JNIEnv *env, jclass clazz, jlong v) { + nint _v = (nint)v; + var_setvars_AnInt(_v); +} + +JNIEXPORT jlong JNICALL +Java_vars_Vars_getAnInt(JNIEnv *env, jclass clazz) { + nint r0 = var_getvars_AnInt(); + jlong _r0 = (jlong)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAnInt16(JNIEnv *env, jclass clazz, jshort v) { + int16_t _v = (int16_t)v; + var_setvars_AnInt16(_v); +} + +JNIEXPORT jshort JNICALL +Java_vars_Vars_getAnInt16(JNIEnv *env, jclass clazz) { + int16_t r0 = var_getvars_AnInt16(); + jshort _r0 = (jshort)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAnInt32(JNIEnv *env, jclass clazz, jint v) { + int32_t _v = (int32_t)v; + var_setvars_AnInt32(_v); +} + +JNIEXPORT jint JNICALL +Java_vars_Vars_getAnInt32(JNIEnv *env, jclass clazz) { + int32_t r0 = var_getvars_AnInt32(); + jint _r0 = (jint)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAnInt64(JNIEnv *env, jclass clazz, jlong v) { + int64_t _v = (int64_t)v; + var_setvars_AnInt64(_v); +} + +JNIEXPORT jlong JNICALL +Java_vars_Vars_getAnInt64(JNIEnv *env, jclass clazz) { + int64_t r0 = var_getvars_AnInt64(); + jlong _r0 = (jlong)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAnInt8(JNIEnv *env, jclass clazz, jbyte v) { + int8_t _v = (int8_t)v; + var_setvars_AnInt8(_v); +} + +JNIEXPORT jbyte JNICALL +Java_vars_Vars_getAnInt8(JNIEnv *env, jclass clazz) { + int8_t r0 = var_getvars_AnInt8(); + jbyte _r0 = (jbyte)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_vars_Vars_setAnInterface(JNIEnv *env, jclass clazz, jobject v) { + int32_t _v = go_seq_to_refnum(env, v); + var_setvars_AnInterface(_v); +} + +JNIEXPORT jobject JNICALL +Java_vars_Vars_getAnInterface(JNIEnv *env, jclass clazz) { + int32_t r0 = var_getvars_AnInterface(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_vars_I, proxy_class_vars_I_cons); + return _r0; +} + diff --git a/bind/testdata/vars.java.golden b/bind/testdata/vars.java.golden new file mode 100644 index 000000000..09cd5d044 --- /dev/null +++ b/bind/testdata/vars.java.golden @@ -0,0 +1,129 @@ +// Code generated by gobind. DO NOT EDIT. + +// Java class vars.S is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java vars +package vars; + +import go.Seq; + +public final class S implements Seq.Proxy, I { + static { Vars.touch(); } + + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + S(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + public S() { this.refnum = __New(); Seq.trackGoRef(refnum, this); } + + private static native int __New(); + + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof S)) { + return false; + } + S that = (S)o; + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("S").append("{"); + return b.append("}").toString(); + } +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class vars.I is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java vars +package vars; + +import go.Seq; + +public interface I { + +} + +// Code generated by gobind. DO NOT EDIT. + +// Java class vars.Vars is a proxy for talking to a Go program. +// +// autogenerated by gobind -lang=java vars +package vars; + +import go.Seq; + +public abstract class Vars { + static { + Seq.touch(); // for loading the native library + _init(); + } + + private Vars() {} // uninstantiable + + // touch is called from other bound packages to initialize this package + public static void touch() {} + + private static native void _init(); + + private static final class proxyI implements Seq.Proxy, I { + private final int refnum; + + @Override public final int incRefnum() { + Seq.incGoRef(refnum, this); + return refnum; + } + + proxyI(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); } + + } + + + public static native void setABool(boolean v); + public static native boolean getABool(); + + public static native void setAFloat(double v); + public static native double getAFloat(); + + public static native void setAFloat32(float v); + public static native float getAFloat32(); + + public static native void setAFloat64(double v); + public static native double getAFloat64(); + + public static native void setAString(String v); + public static native String getAString(); + + public static native void setAStructPtr(S v); + public static native S getAStructPtr(); + + public static native void setAnInt(long v); + public static native long getAnInt(); + + public static native void setAnInt16(short v); + public static native short getAnInt16(); + + public static native void setAnInt32(int v); + public static native int getAnInt32(); + + public static native void setAnInt64(long v); + public static native long getAnInt64(); + + public static native void setAnInt8(byte v); + public static native byte getAnInt8(); + + public static native void setAnInterface(I v); + public static native I getAnInterface(); + +} diff --git a/bind/testdata/vars.java.h.golden b/bind/testdata/vars.java.h.golden new file mode 100644 index 000000000..3b99414e3 --- /dev/null +++ b/bind/testdata/vars.java.h.golden @@ -0,0 +1,17 @@ +// Code generated by gobind. DO NOT EDIT. + +// JNI function headers for the Go <=> Java bridge. +// +// autogenerated by gobind -lang=java vars + +#ifndef __Vars_H__ +#define __Vars_H__ + +#include + +extern jclass proxy_class_vars_I; +extern jmethodID proxy_class_vars_I_cons; + +extern jclass proxy_class_vars_S; +extern jmethodID proxy_class_vars_S_cons; +#endif diff --git a/bind/testdata/vars.objc.go.h.golden b/bind/testdata/vars.objc.go.h.golden new file mode 100644 index 000000000..3e0bcf831 --- /dev/null +++ b/bind/testdata/vars.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to vars Go package. +// gobind -lang=objc vars +// +// File is generated by gobind. Do not edit. + +#ifndef __GO_vars_H__ +#define __GO_vars_H__ + +#include +#include +#endif diff --git a/bind/testdata/vars.objc.h.golden b/bind/testdata/vars.objc.h.golden new file mode 100644 index 000000000..569b375ef --- /dev/null +++ b/bind/testdata/vars.objc.h.golden @@ -0,0 +1,77 @@ +// Objective-C API for talking to vars Go package. +// gobind -lang=objc vars +// +// File is generated by gobind. Do not edit. + +#ifndef __Vars_H__ +#define __Vars_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class VarsS; +@protocol VarsI; +@class VarsI; + +@protocol VarsI +@end + +@interface VarsS : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +@end + +@interface Vars : NSObject ++ (BOOL) aBool; ++ (void) setABool:(BOOL)v; + ++ (double) aFloat; ++ (void) setAFloat:(double)v; + ++ (float) aFloat32; ++ (void) setAFloat32:(float)v; + ++ (double) aFloat64; ++ (void) setAFloat64:(double)v; + ++ (NSString* _Nonnull) aString; ++ (void) setAString:(NSString* _Nonnull)v; + ++ (VarsS* _Nullable) aStructPtr; ++ (void) setAStructPtr:(VarsS* _Nullable)v; + ++ (long) anInt; ++ (void) setAnInt:(long)v; + ++ (int16_t) anInt16; ++ (void) setAnInt16:(int16_t)v; + ++ (int32_t) anInt32; ++ (void) setAnInt32:(int32_t)v; + ++ (int64_t) anInt64; ++ (void) setAnInt64:(int64_t)v; + ++ (int8_t) anInt8; ++ (void) setAnInt8:(int8_t)v; + ++ (id _Nullable) anInterface; ++ (void) setAnInterface:(id _Nullable)v; + +@end + +@class VarsI; + +@interface VarsI : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +@end + +#endif diff --git a/bind/testdata/vars.objc.m.golden b/bind/testdata/vars.objc.m.golden new file mode 100644 index 000000000..c390a8488 --- /dev/null +++ b/bind/testdata/vars.objc.m.golden @@ -0,0 +1,208 @@ +// Objective-C API for talking to vars Go package. +// gobind -lang=objc vars +// +// File is generated by gobind. Do not edit. + +#include +#include "seq.h" +#include "_cgo_export.h" +#include "Vars.objc.h" + + +@implementation VarsS { +} + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + __ref = go_seq_from_refnum(new_vars_S()); + } + return self; +} + +@end + + +@implementation VarsI { +} + +- (nonnull instancetype)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +@end + + +@implementation Vars ++ (void) setABool:(BOOL)v { + char _v = (char)v; + var_setvars_ABool(_v); +} + ++ (BOOL) aBool { + char r0 = var_getvars_ABool(); + BOOL _r0 = r0 ? YES : NO; + return _r0; +} + ++ (void) setAFloat:(double)v { + double _v = (double)v; + var_setvars_AFloat(_v); +} + ++ (double) aFloat { + double r0 = var_getvars_AFloat(); + double _r0 = (double)r0; + return _r0; +} + ++ (void) setAFloat32:(float)v { + float _v = (float)v; + var_setvars_AFloat32(_v); +} + ++ (float) aFloat32 { + float r0 = var_getvars_AFloat32(); + float _r0 = (float)r0; + return _r0; +} + ++ (void) setAFloat64:(double)v { + double _v = (double)v; + var_setvars_AFloat64(_v); +} + ++ (double) aFloat64 { + double r0 = var_getvars_AFloat64(); + double _r0 = (double)r0; + return _r0; +} + ++ (void) setAString:(NSString* _Nonnull)v { + nstring _v = go_seq_from_objc_string(v); + var_setvars_AString(_v); +} + ++ (NSString* _Nonnull) aString { + nstring r0 = var_getvars_AString(); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + ++ (void) setAStructPtr:(VarsS* _Nullable)v { + int32_t _v; + if ([v conformsToProtocol:@protocol(goSeqRefInterface)]) { + id v_proxy = (id)(v); + _v = go_seq_go_to_refnum(v_proxy._ref); + } else { + _v = go_seq_to_refnum(v); + } + var_setvars_AStructPtr(_v); +} + ++ (VarsS* _Nullable) aStructPtr { + int32_t r0 = var_getvars_AStructPtr(); + VarsS* _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[VarsS alloc] initWithRef:_r0_ref]; + } + } + return _r0; +} + ++ (void) setAnInt:(long)v { + nint _v = (nint)v; + var_setvars_AnInt(_v); +} + ++ (long) anInt { + nint r0 = var_getvars_AnInt(); + long _r0 = (long)r0; + return _r0; +} + ++ (void) setAnInt16:(int16_t)v { + int16_t _v = (int16_t)v; + var_setvars_AnInt16(_v); +} + ++ (int16_t) anInt16 { + int16_t r0 = var_getvars_AnInt16(); + int16_t _r0 = (int16_t)r0; + return _r0; +} + ++ (void) setAnInt32:(int32_t)v { + int32_t _v = (int32_t)v; + var_setvars_AnInt32(_v); +} + ++ (int32_t) anInt32 { + int32_t r0 = var_getvars_AnInt32(); + int32_t _r0 = (int32_t)r0; + return _r0; +} + ++ (void) setAnInt64:(int64_t)v { + int64_t _v = (int64_t)v; + var_setvars_AnInt64(_v); +} + ++ (int64_t) anInt64 { + int64_t r0 = var_getvars_AnInt64(); + int64_t _r0 = (int64_t)r0; + return _r0; +} + ++ (void) setAnInt8:(int8_t)v { + int8_t _v = (int8_t)v; + var_setvars_AnInt8(_v); +} + ++ (int8_t) anInt8 { + int8_t r0 = var_getvars_AnInt8(); + int8_t _r0 = (int8_t)r0; + return _r0; +} + ++ (void) setAnInterface:(id _Nullable)v { + int32_t _v; + if ([v conformsToProtocol:@protocol(goSeqRefInterface)]) { + id v_proxy = (id)(v); + _v = go_seq_go_to_refnum(v_proxy._ref); + } else { + _v = go_seq_to_refnum(v); + } + var_setvars_AnInterface(_v); +} + ++ (id _Nullable) anInterface { + int32_t r0 = var_getvars_AnInterface(); + VarsI* _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[VarsI alloc] initWithRef:_r0_ref]; + } + } + return _r0; +} + +@end + + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/types.go b/bind/types.go new file mode 100644 index 000000000..e7a7fcec9 --- /dev/null +++ b/bind/types.go @@ -0,0 +1,172 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bind + +import ( + "fmt" + "go/types" + "log" + "strings" +) + +type ifaceSummary struct { + iface *types.Interface + callable []*types.Func + implementable bool +} + +func makeIfaceSummary(iface *types.Interface) ifaceSummary { + summary := ifaceSummary{ + iface: iface, + implementable: true, + } + methodset := types.NewMethodSet(iface) + for i := 0; i < methodset.Len(); i++ { + obj := methodset.At(i).Obj() + if !obj.Exported() { + summary.implementable = false + continue + } + m, ok := obj.(*types.Func) + if !ok { + log.Panicf("unexpected methodset obj: %s (%T)", obj, obj) + } + if !isImplementable(m.Type().(*types.Signature)) { + summary.implementable = false + } + if isCallable(m) { + summary.callable = append(summary.callable, m) + } + } + return summary +} + +func isCallable(t *types.Func) bool { + // TODO(crawshaw): functions that are not implementable from + // another language may still be callable (for example, a + // returned value with an unexported type can be treated as + // an opaque value by the caller). This restriction could be + // lifted. + return isImplementable(t.Type().(*types.Signature)) +} + +func isImplementable(sig *types.Signature) bool { + params := sig.Params() + for i := 0; i < params.Len(); i++ { + if !isExported(params.At(i).Type()) { + return false + } + } + res := sig.Results() + for i := 0; i < res.Len(); i++ { + if !isExported(res.At(i).Type()) { + return false + } + } + return true +} + +func exportedMethodSet(T types.Type) []*types.Func { + var methods []*types.Func + methodset := types.NewMethodSet(T) + for i := 0; i < methodset.Len(); i++ { + obj := methodset.At(i).Obj() + if !obj.Exported() { + continue + } + // Skip methods from the embedded classes, so that + // only methods that are implemented in Go are included. + if pref := pkgFirstElem(obj.Pkg()); pref == "Java" || pref == "ObjC" { + continue + } + switch obj := obj.(type) { + case *types.Func: + methods = append(methods, obj) + default: + log.Panicf("unexpected methodset obj: %s", obj) + } + } + return methods +} + +func exportedFields(T *types.Struct) []*types.Var { + var fields []*types.Var + for i := 0; i < T.NumFields(); i++ { + f := T.Field(i) + if !f.Exported() { + continue + } + fields = append(fields, f) + } + return fields +} + +func isErrorType(t types.Type) bool { + return types.Identical(t, types.Universe.Lookup("error").Type()) +} + +func isExported(t types.Type) bool { + if isErrorType(t) { + return true + } + switch t := t.(type) { + case *types.Basic: + return true + case *types.Named: + return t.Obj().Exported() + case *types.Pointer: + return isExported(t.Elem()) + default: + return true + } +} + +func isRefType(t types.Type) bool { + if isErrorType(t) { + return false + } + switch t := t.(type) { + case *types.Named: + switch u := t.Underlying().(type) { + case *types.Interface: + return true + default: + panic(fmt.Sprintf("unsupported named type: %s / %T", u, u)) + } + case *types.Pointer: + return isRefType(t.Elem()) + default: + return false + } +} + +func isNullableType(t types.Type) bool { + return types.AssignableTo(types.Typ[types.UntypedNil].Underlying(), t) || t.String() == "string" // string is mapped to NSString*, which is nullable +} + +func typePkgFirstElem(t types.Type) string { + nt, ok := t.(*types.Named) + if !ok { + return "" + } + return pkgFirstElem(nt.Obj().Pkg()) +} + +func pkgFirstElem(p *types.Package) string { + if p == nil { + return "" + } + path := p.Path() + idx := strings.Index(path, "/") + if idx == -1 { + return path + } + return path[:idx] +} + +func isWrapperType(t types.Type) bool { + e := typePkgFirstElem(t) + return e == "Java" || e == "ObjC" +} diff --git a/cmd/gobind/doc.go b/cmd/gobind/doc.go new file mode 100644 index 000000000..31155c639 --- /dev/null +++ b/cmd/gobind/doc.go @@ -0,0 +1,252 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Gobind generates language bindings that make it possible to call Go +functions from Java and Objective-C. + +Typically gobind is not used directly. Instead, a binding is +generated and automatically packaged for Android or iOS by +`gomobile bind`. For more details on installing and using the gomobile +tool, see https://golang.org/x/mobile/cmd/gomobile. + +# Binding Go + +Gobind generates target language (Java or Objective-C) bindings for +each exported symbol in a Go package. The Go package you choose to +bind defines a cross-language interface. + +Bindings require additional Go code be generated, so using gobind +manually requires calling it twice, first with -lang=, where +target is either java or objc, and again with -lang=go. The generated +package can then be _ imported into a Go program, typically built +with -buildmode=c-archive for iOS or -buildmode=c-shared for Android. +These details are handled by the `gomobile bind` command. + +# Passing Go objects to target languages + +Consider a type for counting: + + package mypkg + + type Counter struct { + Value int + } + + func (c *Counter) Inc() { c.Value++ } + + func NewCounter() *Counter { return &Counter{ 5 } } + +In Java, the generated bindings are, + + public abstract class Mypkg { + public static native Counter newCounter(); + } + +and + + public final class Counter { + public Counter() { ... } + + public final long getValue(); + public final void setValue(long v); + public void inc(); + + } + +The package-level function newCounter can be called like so: + + Counter c = Mypkg.newCounter() + +For convenience, functions on the form NewT(...) *T are converted to constructors for T: + + Counter c = new Counter() + +Both forms returns a Java Counter, which is a proxy for a Go *Counter. Calling the inc, getValue and +setValue methods will call the Go implementations of these methods. + +Similarly, the same Go package will generate the Objective-C interface + + @class GoMypkgCounter; + + @interface GoMypkgCounter : NSObject { + } + + @property(strong, readonly) id ref; + - (void)inc; + - (int64_t)value; + - (void)setValue:(int64_t)v; + @end + + FOUNDATION_EXPORT GoMypkgCounter* GoMypkgNewCounter(void); + +The equivalent of calling newCounter in Go is GoMypkgNewCounter in Objective-C. +The returned GoMypkgCounter* holds a reference to an underlying Go +*Counter. + +# Passing target language objects to Go + +For a Go interface: + + package myfmt + + type Printer interface { + Print(s string) + } + + func PrintHello(p Printer) { + p.Print("Hello, World!") + } + +gobind generates a Java interface that can be used to implement a Printer: + + public abstract class Myfmt { + public static void printHello(Printer p0); + } + +and + + public interface Printer { + public void print(String s); + } + +You can implement Printer, and pass it to Go using the printHello +package function: + + public class SysPrint implements Printer { + public void print(String s) { + System.out.println(s); + } + } + +The Java implementation can be used like so: + + Printer printer = new SysPrint(); + Myfmt.printHello(printer); + +For Objective-C binding, gobind generates a protocol that declares +methods corresponding to Go interface's methods. + + @protocol GoMyfmtPrinter + - (void)Print:(NSString*)s; + @end + + FOUNDATION_EXPORT void GoMyfmtPrintHello(id p0); + +Any Objective-C classes conforming to the GoMyfmtPrinter protocol can be +passed to Go using the GoMyfmtPrintHello function: + + @interface SysPrint : NSObject { + } + @end + + @implementation SysPrint { + } + - (void)Print:(NSString*)s { + NSLog("%@", s); + } + @end + +The Objective-C implementation can be used like so: + + SysPrint* printer = [[SysPrint alloc] init]; + GoMyfmtPrintHello(printer); + +# Type restrictions + +At present, only a subset of Go types are supported. + +All exported symbols in the package must have types that are supported. +Supported types include: + + - Signed integer and floating point types. + + - String and boolean types. + + - Byte slice types. Note that byte slices are passed by reference, + and support mutation. + + - Any function type all of whose parameters and results have + supported types. Functions must return either no results, + one result, or two results where the type of the second is + the built-in 'error' type. + + - Any interface type, all of whose exported methods have + supported function types. + + - Any struct type, all of whose exported methods have + supported function types and all of whose exported fields + have supported types. + +Unexported symbols have no effect on the cross-language interface, and +as such are not restricted. + +The set of supported types will eventually be expanded to cover more +Go types, but this is a work in progress. + +Exceptions and panics are not yet supported. If either pass a language +boundary, the program will exit. + +# Reverse bindings + +Gobind also supports accessing API from Java or Objective C from Go. +Similar to how Cgo supports the magic "C" import, gobind recognizes +import statements that start with "Java/" or "ObjC/". For example, +to import java.lang.System and call the static method currentTimeMillis: + + import "Java/java/lang/System" + + t := System.CurrentTimeMillis() + +Similarly, to import NSDate and call the static method [NSDate date]: + + import "ObjC/Foundation/NSDate" + + d := NSDate.Date() + +Gobind also supports specifying particular classes, interfaces or +protocols a particular Go struct should extend or implement. For example, +to create an Android Activity subclass MainActivity: + + import "Java/android/app/Activity" + + type MainActivity struct { + app.Activity + } + +Gobind also recognizes Java interfaces as well as Objective C classes and +protocols the same way. + +For more details on binding the the native API, see the design proposals, +https://golang.org/issues/16876 (Java) and https://golang.org/issues/17102 +(Objective C). + +# Avoid reference cycles + +The language bindings maintain a reference to each object that has been +proxied. When a proxy object becomes unreachable, its finalizer reports +this fact to the object's native side, so that the reference can be +removed, potentially allowing the object to be reclaimed by its native +garbage collector. The mechanism is symmetric. + +However, it is possible to create a reference cycle between Go and +objects in target languages, via proxies, meaning objects cannot be +collected. This causes a memory leak. + +For example, in Java: if a Go object G holds a reference to the Go +proxy of a Java object J, and J holds a reference to the Java proxy +of G, then the language bindings on each side must keep G and J live +even if they are otherwise unreachable. + +We recommend that implementations of foreign interfaces do not hold +references to proxies of objects. That is: if you implement a Go +interface in Java, do not store an instance of Seq.Object inside it. + +# Further reading + +Examples can be found in http://golang.org/x/mobile/example. + +Design doc: http://golang.org/s/gobind +*/ +package main // import "golang.org/x/mobile/cmd/gobind" diff --git a/cmd/gobind/gen.go b/cmd/gobind/gen.go new file mode 100644 index 000000000..fedbc2705 --- /dev/null +++ b/cmd/gobind/gen.go @@ -0,0 +1,392 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "go/types" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "unicode" + "unicode/utf8" + + "golang.org/x/mobile/bind" + "golang.org/x/mobile/internal/importers" + "golang.org/x/mobile/internal/importers/java" + "golang.org/x/mobile/internal/importers/objc" + "golang.org/x/tools/go/packages" +) + +func genPkg(lang string, p *types.Package, astFiles []*ast.File, allPkg []*types.Package, classes []*java.Class, otypes []*objc.Named) { + fname := defaultFileName(lang, p) + conf := &bind.GeneratorConfig{ + Fset: fset, + Pkg: p, + AllPkg: allPkg, + } + var pname string + if p != nil { + pname = p.Name() + } else { + pname = "universe" + } + var buf bytes.Buffer + generator := &bind.Generator{ + Printer: &bind.Printer{Buf: &buf, IndentEach: []byte("\t")}, + Fset: conf.Fset, + AllPkg: conf.AllPkg, + Pkg: conf.Pkg, + Files: astFiles, + } + switch lang { + case "java": + g := &bind.JavaGen{ + JavaPkg: *javaPkg, + Generator: generator, + } + g.Init(classes) + + pkgname := bind.JavaPkgName(*javaPkg, p) + pkgDir := strings.Replace(pkgname, ".", "/", -1) + buf.Reset() + w, closer := writer(filepath.Join("java", pkgDir, fname)) + processErr(g.GenJava()) + io.Copy(w, &buf) + closer() + for i, name := range g.ClassNames() { + buf.Reset() + w, closer := writer(filepath.Join("java", pkgDir, name+".java")) + processErr(g.GenClass(i)) + io.Copy(w, &buf) + closer() + } + buf.Reset() + w, closer = writer(filepath.Join("src", "gobind", pname+"_android.c")) + processErr(g.GenC()) + io.Copy(w, &buf) + closer() + buf.Reset() + w, closer = writer(filepath.Join("src", "gobind", pname+"_android.h")) + processErr(g.GenH()) + io.Copy(w, &buf) + closer() + // Generate support files along with the universe package + if p == nil { + dir, err := packageDir("golang.org/x/mobile/bind") + if err != nil { + errorf(`"golang.org/x/mobile/bind" is not found; run go get golang.org/x/mobile/bind: %v`, err) + return + } + repo := filepath.Clean(filepath.Join(dir, "..")) // golang.org/x/mobile directory. + for _, javaFile := range []string{"Seq.java"} { + src := filepath.Join(repo, "bind/java/"+javaFile) + in, err := os.Open(src) + if err != nil { + errorf("failed to open Java support file: %v", err) + } + defer in.Close() + w, closer := writer(filepath.Join("java", "go", javaFile)) + defer closer() + if _, err := io.Copy(w, in); err != nil { + errorf("failed to copy Java support file: %v", err) + return + } + } + // Copy support files + if err != nil { + errorf("unable to import bind/java: %v", err) + return + } + javaDir, err := packageDir("golang.org/x/mobile/bind/java") + if err != nil { + errorf("unable to import bind/java: %v", err) + return + } + copyFile(filepath.Join("src", "gobind", "seq_android.c"), filepath.Join(javaDir, "seq_android.c.support")) + copyFile(filepath.Join("src", "gobind", "seq_android.go"), filepath.Join(javaDir, "seq_android.go.support")) + copyFile(filepath.Join("src", "gobind", "seq_android.h"), filepath.Join(javaDir, "seq_android.h")) + } + case "go": + w, closer := writer(filepath.Join("src", "gobind", fname)) + conf.Writer = w + processErr(bind.GenGo(conf)) + closer() + w, closer = writer(filepath.Join("src", "gobind", pname+".h")) + genPkgH(w, pname) + io.Copy(w, &buf) + closer() + w, closer = writer(filepath.Join("src", "gobind", "seq.h")) + genPkgH(w, "seq") + io.Copy(w, &buf) + closer() + dir, err := packageDir("golang.org/x/mobile/bind") + if err != nil { + errorf("unable to import bind: %v", err) + return + } + copyFile(filepath.Join("src", "gobind", "seq.go"), filepath.Join(dir, "seq.go.support")) + case "objc": + g := &bind.ObjcGen{ + Generator: generator, + Prefix: *prefix, + } + g.Init(otypes) + w, closer := writer(filepath.Join("src", "gobind", pname+"_darwin.h")) + processErr(g.GenGoH()) + io.Copy(w, &buf) + closer() + hname := strings.Title(fname[:len(fname)-2]) + ".objc.h" + w, closer = writer(filepath.Join("src", "gobind", hname)) + processErr(g.GenH()) + io.Copy(w, &buf) + closer() + mname := strings.Title(fname[:len(fname)-2]) + "_darwin.m" + w, closer = writer(filepath.Join("src", "gobind", mname)) + conf.Writer = w + processErr(g.GenM()) + io.Copy(w, &buf) + closer() + if p == nil { + // Copy support files + dir, err := packageDir("golang.org/x/mobile/bind/objc") + if err != nil { + errorf("unable to import bind/objc: %v", err) + return + } + copyFile(filepath.Join("src", "gobind", "seq_darwin.m"), filepath.Join(dir, "seq_darwin.m.support")) + copyFile(filepath.Join("src", "gobind", "seq_darwin.go"), filepath.Join(dir, "seq_darwin.go.support")) + copyFile(filepath.Join("src", "gobind", "ref.h"), filepath.Join(dir, "ref.h")) + copyFile(filepath.Join("src", "gobind", "seq_darwin.h"), filepath.Join(dir, "seq_darwin.h")) + } + default: + errorf("unknown target language: %q", lang) + } +} + +func genPkgH(w io.Writer, pname string) { + fmt.Fprintf(w, `// Code generated by gobind. DO NOT EDIT. + +#ifdef __GOBIND_ANDROID__ +#include "%[1]s_android.h" +#endif +#ifdef __GOBIND_DARWIN__ +#include "%[1]s_darwin.h" +#endif`, pname) +} + +func genObjcPackages(dir string, types []*objc.Named, embedders []importers.Struct) error { + var buf bytes.Buffer + cg := &bind.ObjcWrapper{ + Printer: &bind.Printer{ + IndentEach: []byte("\t"), + Buf: &buf, + }, + } + var genNames []string + for _, emb := range embedders { + genNames = append(genNames, emb.Name) + } + cg.Init(types, genNames) + for i, opkg := range cg.Packages() { + pkgDir := filepath.Join(dir, "src", "ObjC", opkg) + if err := os.MkdirAll(pkgDir, 0700); err != nil { + return err + } + pkgFile := filepath.Join(pkgDir, "package.go") + buf.Reset() + cg.GenPackage(i) + if err := ioutil.WriteFile(pkgFile, buf.Bytes(), 0600); err != nil { + return err + } + } + buf.Reset() + cg.GenInterfaces() + objcBase := filepath.Join(dir, "src", "ObjC") + if err := os.MkdirAll(objcBase, 0700); err != nil { + return err + } + if err := ioutil.WriteFile(filepath.Join(objcBase, "interfaces.go"), buf.Bytes(), 0600); err != nil { + return err + } + goBase := filepath.Join(dir, "src", "gobind") + if err := os.MkdirAll(goBase, 0700); err != nil { + return err + } + buf.Reset() + cg.GenGo() + if err := ioutil.WriteFile(filepath.Join(goBase, "interfaces_darwin.go"), buf.Bytes(), 0600); err != nil { + return err + } + buf.Reset() + cg.GenH() + if err := ioutil.WriteFile(filepath.Join(goBase, "interfaces.h"), buf.Bytes(), 0600); err != nil { + return err + } + buf.Reset() + cg.GenM() + if err := ioutil.WriteFile(filepath.Join(goBase, "interfaces_darwin.m"), buf.Bytes(), 0600); err != nil { + return err + } + return nil +} + +func genJavaPackages(dir string, classes []*java.Class, embedders []importers.Struct) error { + var buf bytes.Buffer + cg := &bind.ClassGen{ + JavaPkg: *javaPkg, + Printer: &bind.Printer{ + IndentEach: []byte("\t"), + Buf: &buf, + }, + } + cg.Init(classes, embedders) + for i, jpkg := range cg.Packages() { + pkgDir := filepath.Join(dir, "src", "Java", jpkg) + if err := os.MkdirAll(pkgDir, 0700); err != nil { + return err + } + pkgFile := filepath.Join(pkgDir, "package.go") + buf.Reset() + cg.GenPackage(i) + if err := ioutil.WriteFile(pkgFile, buf.Bytes(), 0600); err != nil { + return err + } + } + buf.Reset() + cg.GenInterfaces() + javaBase := filepath.Join(dir, "src", "Java") + if err := os.MkdirAll(javaBase, 0700); err != nil { + return err + } + if err := ioutil.WriteFile(filepath.Join(javaBase, "interfaces.go"), buf.Bytes(), 0600); err != nil { + return err + } + goBase := filepath.Join(dir, "src", "gobind") + if err := os.MkdirAll(goBase, 0700); err != nil { + return err + } + buf.Reset() + cg.GenGo() + if err := ioutil.WriteFile(filepath.Join(goBase, "classes_android.go"), buf.Bytes(), 0600); err != nil { + return err + } + buf.Reset() + cg.GenH() + if err := ioutil.WriteFile(filepath.Join(goBase, "classes.h"), buf.Bytes(), 0600); err != nil { + return err + } + buf.Reset() + cg.GenC() + if err := ioutil.WriteFile(filepath.Join(goBase, "classes_android.c"), buf.Bytes(), 0600); err != nil { + return err + } + return nil +} + +func processErr(err error) { + if err != nil { + if list, _ := err.(bind.ErrorList); len(list) > 0 { + for _, err := range list { + errorf("%v", err) + } + } else { + errorf("%v", err) + } + } +} + +var fset = token.NewFileSet() + +func writer(fname string) (w io.Writer, closer func()) { + if *outdir == "" { + return os.Stdout, func() { return } + } + + name := filepath.Join(*outdir, fname) + dir := filepath.Dir(name) + if err := os.MkdirAll(dir, 0755); err != nil { + errorf("invalid output dir: %v", err) + os.Exit(exitStatus) + } + + f, err := os.Create(name) + if err != nil { + errorf("invalid output dir: %v", err) + os.Exit(exitStatus) + } + closer = func() { + if err := f.Close(); err != nil { + errorf("error in closing output file: %v", err) + } + } + return f, closer +} + +func copyFile(dst, src string) { + w, closer := writer(dst) + f, err := os.Open(src) + if err != nil { + errorf("unable to open file: %v", err) + closer() + os.Exit(exitStatus) + } + if _, err := io.Copy(w, f); err != nil { + errorf("unable to copy file: %v", err) + f.Close() + closer() + os.Exit(exitStatus) + } + f.Close() + closer() +} + +func defaultFileName(lang string, pkg *types.Package) string { + switch lang { + case "java": + if pkg == nil { + return "Universe.java" + } + firstRune, size := utf8.DecodeRuneInString(pkg.Name()) + className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:] + return className + ".java" + case "go": + if pkg == nil { + return "go_main.go" + } + return "go_" + pkg.Name() + "main.go" + case "objc": + if pkg == nil { + return "Universe.m" + } + firstRune, size := utf8.DecodeRuneInString(pkg.Name()) + className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:] + return *prefix + className + ".m" + } + errorf("unknown target language: %q", lang) + os.Exit(exitStatus) + return "" +} + +func packageDir(path string) (string, error) { + mode := packages.NeedFiles + pkgs, err := packages.Load(&packages.Config{Mode: mode}, path) + if err != nil { + return "", err + } + if len(pkgs) == 0 || len(pkgs[0].GoFiles) == 0 { + return "", fmt.Errorf("no Go package in %v", path) + } + pkg := pkgs[0] + if len(pkg.Errors) > 0 { + return "", fmt.Errorf("%v", pkg.Errors) + } + return filepath.Dir(pkg.GoFiles[0]), nil +} diff --git a/cmd/gobind/gobind_test.go b/cmd/gobind/gobind_test.go new file mode 100644 index 000000000..302103c9e --- /dev/null +++ b/cmd/gobind/gobind_test.go @@ -0,0 +1,218 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "runtime" + "strings" + "testing" + + "golang.org/x/tools/go/packages/packagestest" +) + +func TestMain(m *testing.M) { + // To avoid recompiling the gobind command (and to support compiler options + // like -race and -coverage), allow the test binary itself to re-exec itself + // as the gobind command by setting an environment variable. + if os.Getenv("GOBIND_TEST_IS_GOBIND") != "" { + main() + os.Exit(0) + } + os.Setenv("GOBIND_TEST_IS_GOBIND", "1") + + os.Exit(m.Run()) +} + +var tests = []struct { + name string + lang string + pkg string + goos string + // reverse is true if the test needs to generate reverse bindings using + // external tools such as javap. + reverse bool +}{ + { + name: "ObjC-Testpkg", + lang: "objc", + pkg: "golang.org/x/mobile/bind/testdata/testpkg", + }, + { + name: "Java-Testpkg", + lang: "java", + pkg: "golang.org/x/mobile/bind/testdata/testpkg", + }, + { + name: "Go-Testpkg", + lang: "go", + pkg: "golang.org/x/mobile/bind/testdata/testpkg", + }, + { + name: "Java-Javapkg", + lang: "java", + pkg: "golang.org/x/mobile/bind/testdata/testpkg/javapkg", + goos: "android", + reverse: true, + }, + { + name: "Go-Javapkg", + lang: "go", + pkg: "golang.org/x/mobile/bind/testdata/testpkg/javapkg", + goos: "android", + reverse: true, + }, + { + name: "Go-Cgopkg", + lang: "go,java,objc", + pkg: "golang.org/x/mobile/bind/testdata/cgopkg", + goos: "android", + }, +} + +func mustHaveBindTestdata(t testing.TB) { + switch runtime.GOOS { + case "android", "ios": + t.Skipf("skipping: test cannot access ../../bind/testdata on %s/%s", runtime.GOOS, runtime.GOARCH) + } +} + +func gobindBin(t testing.TB) string { + switch runtime.GOOS { + case "js", "ios": + t.Skipf("skipping: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH) + } + + p, err := os.Executable() + if err != nil { + t.Fatal(err) + } + return p +} + +func runGobind(t testing.TB, lang, pkg, goos string, exported *packagestest.Exported) error { + cmd := exec.Command(gobindBin(t), "-lang", lang, pkg) + cmd.Dir = exported.Config.Dir + cmd.Env = exported.Config.Env + if goos != "" { + // Add CGO_ENABLED=1 explicitly since Cgo is disabled when GOOS is different from host OS. + cmd.Env = append(cmd.Env, "GOOS="+goos, "CGO_ENABLED=1") + } + stderr := new(strings.Builder) + cmd.Stderr = stderr + stdout := new(strings.Builder) + cmd.Stdout = stdout + err := cmd.Run() + if testing.Verbose() && stdout.Len() > 0 { + t.Logf("stdout (%v):\n%s", cmd, stderr) + } + if stderr.Len() > 0 { + t.Logf("stderr (%v):\n%s", cmd, stderr) + } + if err != nil { + return fmt.Errorf("%v: %w", cmd, err) + } + return nil +} + +func TestGobind(t *testing.T) { packagestest.TestAll(t, testGobind) } +func testGobind(t *testing.T, exporter packagestest.Exporter) { + mustHaveBindTestdata(t) + + _, javapErr := exec.LookPath("javap") + exported := packagestest.Export(t, exporter, []packagestest.Module{{ + Name: "golang.org/x/mobile", + Files: packagestest.MustCopyFileTree("../.."), + }}) + defer exported.Cleanup() + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if exporter == packagestest.Modules && test.reverse { + t.Skip("reverse binding does't work with Go modules") + } + if test.reverse && javapErr != nil { + t.Skip("reverse bind test requires javap which is not available") + } + if err := runGobind(t, test.lang, test.pkg, test.goos, exported); err != nil { + t.Error(err) + } + }) + } +} + +func TestDocs(t *testing.T) { packagestest.TestAll(t, testDocs) } +func testDocs(t *testing.T, exporter packagestest.Exporter) { + mustHaveBindTestdata(t) + + const docsrc = ` +package doctest + +// This is a comment. +type Struct struct{ +}` + + exported := packagestest.Export(t, exporter, []packagestest.Module{ + { + Name: "example.com/doctest", + Files: map[string]interface{}{ + "doc.go": docsrc, + }, + }, + { + // gobind requires golang.org/x/mobile to generate code for reverse bindings. + Name: "golang.org/x/mobile", + Files: packagestest.MustCopyFileTree("../.."), + }, + }) + defer exported.Cleanup() + + const comment = "This is a comment." + for _, lang := range []string{"java", "objc"} { + cmd := exec.Command(gobindBin(t), "-lang", lang, "example.com/doctest") + cmd.Dir = exported.Config.Dir + cmd.Env = exported.Config.Env + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("gobind -lang %s failed: %v: %s", lang, err, out) + continue + } + if bytes.Index(out, []byte(comment)) == -1 { + t.Errorf("gobind output for language %s did not contain the comment %q", lang, comment) + } + } +} + +func BenchmarkGobind(b *testing.B) { + packagestest.BenchmarkAll(b, benchmarkGobind) +} + +func benchmarkGobind(b *testing.B, exporter packagestest.Exporter) { + _, javapErr := exec.LookPath("javap") + exported := packagestest.Export(b, exporter, []packagestest.Module{{ + Name: "golang.org/x/mobile", + Files: packagestest.MustCopyFileTree("../.."), + }}) + defer exported.Cleanup() + + for _, test := range tests { + b.Run(test.name, func(b *testing.B) { + if exporter == packagestest.Modules && test.reverse { + b.Skip("reverse binding does't work with Go modules") + } + if test.reverse && javapErr != nil { + b.Skip("reverse bind test requires javap which is not available") + } + for i := 0; i < b.N; i++ { + if err := runGobind(b, test.lang, test.pkg, test.goos, exported); err != nil { + b.Error(err) + } + } + }) + } +} diff --git a/cmd/gobind/implicit.go b/cmd/gobind/implicit.go new file mode 100644 index 000000000..4289d4b36 --- /dev/null +++ b/cmd/gobind/implicit.go @@ -0,0 +1,12 @@ +// This file imports implicit dependencies required by generated code. + +//go:build mobile_implicit +// +build mobile_implicit + +package main + +import ( + _ "golang.org/x/mobile/bind" + _ "golang.org/x/mobile/bind/java" + _ "golang.org/x/mobile/bind/objc" +) diff --git a/cmd/gobind/main.go b/cmd/gobind/main.go new file mode 100644 index 000000000..8ccb9951e --- /dev/null +++ b/cmd/gobind/main.go @@ -0,0 +1,169 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "flag" + "fmt" + "go/ast" + "go/types" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + + "golang.org/x/mobile/internal/importers" + "golang.org/x/mobile/internal/importers/java" + "golang.org/x/mobile/internal/importers/objc" + "golang.org/x/tools/go/packages" +) + +var ( + lang = flag.String("lang", "", "target languages for bindings, either java, go, or objc. If empty, all languages are generated.") + outdir = flag.String("outdir", "", "result will be written to the directory instead of stdout.") + javaPkg = flag.String("javapkg", "", "custom Java package path prefix. Valid only with -lang=java.") + prefix = flag.String("prefix", "", "custom Objective-C name prefix. Valid only with -lang=objc.") + bootclasspath = flag.String("bootclasspath", "", "Java bootstrap classpath.") + classpath = flag.String("classpath", "", "Java classpath.") + tags = flag.String("tags", "", "build tags.") +) + +var usage = `The Gobind tool generates Java language bindings for Go. + +For usage details, see doc.go.` + +func main() { + flag.Parse() + + run() + os.Exit(exitStatus) +} + +func run() { + var langs []string + if *lang != "" { + langs = strings.Split(*lang, ",") + } else { + langs = []string{"go", "java", "objc"} + } + + // We need to give appropriate environment variables like CC or CXX so that the returned packages no longer have errors. + // However, getting such environment variables is difficult or impossible so far. + // Gomobile can obtain such environment variables in env.go, but this logic assumes some condiitons gobind doesn't assume. + cfg := &packages.Config{ + Mode: packages.NeedName | packages.NeedFiles | + packages.NeedImports | packages.NeedDeps | + packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo, + BuildFlags: []string{"-tags", strings.Join(strings.Split(*tags, ","), " ")}, + } + + // Call Load twice to warm the cache. There is a known issue that the result of Load + // depends on build cache state. See golang/go#33687. + packages.Load(cfg, flag.Args()...) + + allPkg, err := packages.Load(cfg, flag.Args()...) + if err != nil { + log.Fatal(err) + } + + jrefs, err := importers.AnalyzePackages(allPkg, "Java/") + if err != nil { + log.Fatal(err) + } + orefs, err := importers.AnalyzePackages(allPkg, "ObjC/") + if err != nil { + log.Fatal(err) + } + var classes []*java.Class + if len(jrefs.Refs) > 0 { + jimp := &java.Importer{ + Bootclasspath: *bootclasspath, + Classpath: *classpath, + JavaPkg: *javaPkg, + } + classes, err = jimp.Import(jrefs) + if err != nil { + log.Fatal(err) + } + } + var otypes []*objc.Named + if len(orefs.Refs) > 0 { + otypes, err = objc.Import(orefs) + if err != nil { + log.Fatal(err) + } + } + + if len(classes) > 0 || len(otypes) > 0 { + srcDir := *outdir + if srcDir == "" { + srcDir, err = ioutil.TempDir(os.TempDir(), "gobind-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(srcDir) + } else { + srcDir, err = filepath.Abs(srcDir) + if err != nil { + log.Fatal(err) + } + } + if len(classes) > 0 { + if err := genJavaPackages(srcDir, classes, jrefs.Embedders); err != nil { + log.Fatal(err) + } + } + if len(otypes) > 0 { + if err := genObjcPackages(srcDir, otypes, orefs.Embedders); err != nil { + log.Fatal(err) + } + } + + // Add a new directory to GOPATH where the file for reverse bindings exist, and recreate allPkg. + // It is because the current allPkg did not solve imports for reverse bindings. + var gopath string + if out, err := exec.Command("go", "env", "GOPATH").Output(); err != nil { + log.Fatal(err) + } else { + gopath = string(bytes.TrimSpace(out)) + } + if gopath != "" { + gopath = string(filepath.ListSeparator) + gopath + } + gopath = srcDir + gopath + cfg.Env = append(os.Environ(), "GOPATH="+gopath) + allPkg, err = packages.Load(cfg, flag.Args()...) + if err != nil { + log.Fatal(err) + } + } + + typePkgs := make([]*types.Package, len(allPkg)) + astPkgs := make([][]*ast.File, len(allPkg)) + for i, pkg := range allPkg { + // Ignore pkg.Errors. pkg.Errors can exist when Cgo is used, but this should not affect the result. + // See the discussion at golang/go#36547. + typePkgs[i] = pkg.Types + astPkgs[i] = pkg.Syntax + } + for _, l := range langs { + for i, pkg := range typePkgs { + genPkg(l, pkg, astPkgs[i], typePkgs, classes, otypes) + } + // Generate the error package and support files + genPkg(l, nil, nil, typePkgs, classes, otypes) + } +} + +var exitStatus = 0 + +func errorf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, format, args...) + fmt.Fprintln(os.Stderr) + exitStatus = 1 +} diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go new file mode 100644 index 000000000..54eaa4bcf --- /dev/null +++ b/cmd/gomobile/bind.go @@ -0,0 +1,335 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + + "golang.org/x/mobile/internal/sdkpath" + "golang.org/x/mod/modfile" + "golang.org/x/tools/go/packages" +) + +var cmdBind = &command{ + run: runBind, + Name: "bind", + Usage: "[-target android|" + strings.Join(applePlatforms, "|") + "] [-bootclasspath ] [-classpath ] [-o output] [build flags] [package]", + Short: "build a library for Android and iOS", + Long: ` +Bind generates language bindings for the package named by the import +path, and compiles a library for the named target system. + +The -target flag takes either android (the default), or one or more +comma-delimited Apple platforms (` + strings.Join(applePlatforms, ", ") + `). + +For -target android, the bind command produces an AAR (Android ARchive) +file that archives the precompiled Java API stub classes, the compiled +shared libraries, and all asset files in the /assets subdirectory under +the package directory. The output is named '.aar' by +default. This AAR file is commonly used for binary distribution of an +Android library project and most Android IDEs support AAR import. For +example, in Android Studio (1.2+), an AAR file can be imported using +the module import wizard (File > New > New Module > Import .JAR or +.AAR package), and setting it as a new dependency +(File > Project Structure > Dependencies). This requires 'javac' +(version 1.7+) and Android SDK (API level 16 or newer) to build the +library for Android. The ANDROID_HOME and ANDROID_NDK_HOME environment +variables can be used to specify the Android SDK and NDK if they are +not in the default locations. Use the -javapkg flag to specify the Java +package prefix for the generated classes. + +By default, -target=android builds shared libraries for all supported +instruction sets (arm, arm64, 386, amd64). A subset of instruction sets +can be selected by specifying target type with the architecture name. E.g., +-target=android/arm,android/386. + +For Apple -target platforms, gomobile must be run on an OS X machine with +Xcode installed. The generated Objective-C types can be prefixed with the +-prefix flag. + +For -target android, the -bootclasspath and -classpath flags are used to +control the bootstrap classpath and the classpath for Go wrappers to Java +classes. + +The -v flag provides verbose output, including the list of packages built. + +The build flags -a, -n, -x, -gcflags, -ldflags, -tags, -trimpath, and -work +are shared with the build command. For documentation, see 'go help build'. +`, +} + +func runBind(cmd *command) error { + cleanup, err := buildEnvInit() + if err != nil { + return err + } + defer cleanup() + + args := cmd.flag.Args() + + targets, err := parseBuildTarget(buildTarget) + if err != nil { + return fmt.Errorf(`invalid -target=%q: %v`, buildTarget, err) + } + + if isAndroidPlatform(targets[0].platform) { + if bindPrefix != "" { + return fmt.Errorf("-prefix is supported only for Apple targets") + } + if _, err := ndkRoot(targets[0]); err != nil { + return err + } + } else { + if bindJavaPkg != "" { + return fmt.Errorf("-javapkg is supported only for android target") + } + } + + var gobind string + if !buildN { + gobind, err = exec.LookPath("gobind") + if err != nil { + return errors.New("gobind was not found. Please run gomobile init before trying again") + } + } else { + gobind = "gobind" + } + + if len(args) == 0 { + args = append(args, ".") + } + + // TODO(ydnar): this should work, unless build tags affect loading a single package. + // Should we try to import packages with different build tags per platform? + pkgs, err := packages.Load(packagesConfig(targets[0]), args...) + if err != nil { + return err + } + + // check if any of the package is main + for _, pkg := range pkgs { + if pkg.Name == "main" { + return fmt.Errorf(`binding "main" package (%s) is not supported`, pkg.PkgPath) + } + } + + switch { + case isAndroidPlatform(targets[0].platform): + return goAndroidBind(gobind, pkgs, targets) + case isApplePlatform(targets[0].platform): + if !xcodeAvailable() { + return fmt.Errorf("-target=%q requires Xcode", buildTarget) + } + return goAppleBind(gobind, pkgs, targets) + default: + return fmt.Errorf(`invalid -target=%q`, buildTarget) + } +} + +var ( + bindPrefix string // -prefix + bindJavaPkg string // -javapkg + bindClasspath string // -classpath + bindBootClasspath string // -bootclasspath +) + +func init() { + // bind command specific commands. + cmdBind.flag.StringVar(&bindJavaPkg, "javapkg", "", + "specifies custom Java package path prefix. Valid only with -target=android.") + cmdBind.flag.StringVar(&bindPrefix, "prefix", "", + "custom Objective-C name prefix. Valid only with -target=ios.") + cmdBind.flag.StringVar(&bindClasspath, "classpath", "", "The classpath for imported Java classes. Valid only with -target=android.") + cmdBind.flag.StringVar(&bindBootClasspath, "bootclasspath", "", "The bootstrap classpath for imported Java classes. Valid only with -target=android.") +} + +func bootClasspath() (string, error) { + if bindBootClasspath != "" { + return bindBootClasspath, nil + } + apiPath, err := sdkpath.AndroidAPIPath(buildAndroidAPI) + if err != nil { + return "", err + } + return filepath.Join(apiPath, "android.jar"), nil +} + +func copyFile(dst, src string) error { + if buildX { + printcmd("cp %s %s", src, dst) + } + return writeFile(dst, func(w io.Writer) error { + if buildN { + return nil + } + f, err := os.Open(src) + if err != nil { + return err + } + defer f.Close() + + if _, err := io.Copy(w, f); err != nil { + return fmt.Errorf("cp %s %s failed: %v", src, dst, err) + } + return nil + }) +} + +func writeFile(filename string, generate func(io.Writer) error) error { + if buildV { + fmt.Fprintf(os.Stderr, "write %s\n", filename) + } + + if err := mkdir(filepath.Dir(filename)); err != nil { + return err + } + + if buildN { + return generate(ioutil.Discard) + } + + f, err := os.Create(filename) + if err != nil { + return err + } + defer func() { + if cerr := f.Close(); err == nil { + err = cerr + } + }() + + return generate(f) +} + +func packagesConfig(t targetInfo) *packages.Config { + config := &packages.Config{} + // Add CGO_ENABLED=1 explicitly since Cgo is disabled when GOOS is different from host OS. + config.Env = append(os.Environ(), "GOARCH="+t.arch, "GOOS="+platformOS(t.platform), "CGO_ENABLED=1") + tags := append(buildTags[:], platformTags(t.platform)...) + + if len(tags) > 0 { + config.BuildFlags = []string{"-tags=" + strings.Join(tags, ",")} + } + return config +} + +// getModuleVersions returns a module information at the directory src. +func getModuleVersions(targetPlatform string, targetArch string, src string) (*modfile.File, error) { + cmd := exec.Command("go", "list") + cmd.Env = append(os.Environ(), "GOOS="+platformOS(targetPlatform), "GOARCH="+targetArch) + + tags := append(buildTags[:], platformTags(targetPlatform)...) + + // TODO(hyangah): probably we don't need to add all the dependencies. + cmd.Args = append(cmd.Args, "-m", "-json", "-tags="+strings.Join(tags, ","), "all") + cmd.Dir = src + + output, err := cmd.Output() + if err != nil { + // Module information is not available at src. + return nil, nil + } + + type Module struct { + Main bool + Path string + Version string + Dir string + Replace *Module + } + + f := &modfile.File{} + f.AddModuleStmt("gobind") + e := json.NewDecoder(bytes.NewReader(output)) + for { + var mod *Module + err := e.Decode(&mod) + if err != nil && err != io.EOF { + return nil, err + } + if mod != nil { + if mod.Replace != nil { + p, v := mod.Replace.Path, mod.Replace.Version + if modfile.IsDirectoryPath(p) { + // replaced by a local directory + p = mod.Replace.Dir + } + f.AddReplace(mod.Path, mod.Version, p, v) + } else { + // When the version part is empty, the module is local and mod.Dir represents the location. + if v := mod.Version; v == "" { + f.AddReplace(mod.Path, mod.Version, mod.Dir, "") + } else { + f.AddRequire(mod.Path, v) + } + } + } + if err == io.EOF { + break + } + } + return f, nil +} + +// writeGoMod writes go.mod file at dir when Go modules are used. +func writeGoMod(dir, targetPlatform, targetArch string) error { + m, err := areGoModulesUsed() + if err != nil { + return err + } + // If Go modules are not used, go.mod should not be created because the dependencies might not be compatible with Go modules. + if !m { + return nil + } + + return writeFile(filepath.Join(dir, "go.mod"), func(w io.Writer) error { + f, err := getModuleVersions(targetPlatform, targetArch, ".") + if err != nil { + return err + } + if f == nil { + return nil + } + bs, err := f.Format() + if err != nil { + return err + } + if _, err := w.Write(bs); err != nil { + return err + } + return nil + }) +} + +var ( + areGoModulesUsedResult struct { + used bool + err error + } + areGoModulesUsedOnce sync.Once +) + +func areGoModulesUsed() (bool, error) { + areGoModulesUsedOnce.Do(func() { + out, err := exec.Command("go", "env", "GOMOD").Output() + if err != nil { + areGoModulesUsedResult.err = err + return + } + outstr := strings.TrimSpace(string(out)) + areGoModulesUsedResult.used = outstr != "" + }) + return areGoModulesUsedResult.used, areGoModulesUsedResult.err +} diff --git a/cmd/gomobile/bind_androidapp.go b/cmd/gomobile/bind_androidapp.go new file mode 100644 index 000000000..3fa9cfa7a --- /dev/null +++ b/cmd/gomobile/bind_androidapp.go @@ -0,0 +1,401 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "archive/zip" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + "golang.org/x/mobile/internal/sdkpath" + "golang.org/x/sync/errgroup" + "golang.org/x/tools/go/packages" +) + +func goAndroidBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error { + if _, err := sdkpath.AndroidHome(); err != nil { + return fmt.Errorf("this command requires the Android SDK to be installed: %w", err) + } + + // Run gobind to generate the bindings + cmd := exec.Command( + gobind, + "-lang=go,java", + "-outdir="+tmpdir, + ) + cmd.Env = append(cmd.Env, "GOOS=android") + cmd.Env = append(cmd.Env, "CGO_ENABLED=1") + if len(buildTags) > 0 { + cmd.Args = append(cmd.Args, "-tags="+strings.Join(buildTags, ",")) + } + if bindJavaPkg != "" { + cmd.Args = append(cmd.Args, "-javapkg="+bindJavaPkg) + } + if bindClasspath != "" { + cmd.Args = append(cmd.Args, "-classpath="+bindClasspath) + } + if bindBootClasspath != "" { + cmd.Args = append(cmd.Args, "-bootclasspath="+bindBootClasspath) + } + for _, p := range pkgs { + cmd.Args = append(cmd.Args, p.PkgPath) + } + if err := runCmd(cmd); err != nil { + return err + } + + androidDir := filepath.Join(tmpdir, "android") + + // Generate binding code and java source code only when processing the first package. + var wg errgroup.Group + for _, t := range targets { + t := t + wg.Go(func() error { + return buildAndroidSO(androidDir, t.arch) + }) + } + if err := wg.Wait(); err != nil { + return err + } + + jsrc := filepath.Join(tmpdir, "java") + if err := buildAAR(jsrc, androidDir, pkgs, targets); err != nil { + return err + } + return buildSrcJar(jsrc) +} + +func buildSrcJar(src string) error { + var out io.Writer = ioutil.Discard + if !buildN { + ext := filepath.Ext(buildO) + f, err := os.Create(buildO[:len(buildO)-len(ext)] + "-sources.jar") + if err != nil { + return err + } + defer func() { + if cerr := f.Close(); err == nil { + err = cerr + } + }() + out = f + } + + return writeJar(out, src) +} + +// AAR is the format for the binary distribution of an Android Library Project +// and it is a ZIP archive with extension .aar. +// http://tools.android.com/tech-docs/new-build-system/aar-format +// +// These entries are directly at the root of the archive. +// +// AndroidManifest.xml (mandatory) +// classes.jar (mandatory) +// assets/ (optional) +// jni//libgojni.so +// R.txt (mandatory) +// res/ (mandatory) +// libs/*.jar (optional, not relevant) +// proguard.txt (optional) +// lint.jar (optional, not relevant) +// aidl (optional, not relevant) +// +// javac and jar commands are needed to build classes.jar. +func buildAAR(srcDir, androidDir string, pkgs []*packages.Package, targets []targetInfo) (err error) { + var out io.Writer = ioutil.Discard + if buildO == "" { + buildO = pkgs[0].Name + ".aar" + } + if !strings.HasSuffix(buildO, ".aar") { + return fmt.Errorf("output file name %q does not end in '.aar'", buildO) + } + if !buildN { + f, err := os.Create(buildO) + if err != nil { + return err + } + defer func() { + if cerr := f.Close(); err == nil { + err = cerr + } + }() + out = f + } + + aarw := zip.NewWriter(out) + aarwcreate := func(name string) (io.Writer, error) { + if buildV { + fmt.Fprintf(os.Stderr, "aar: %s\n", name) + } + return aarw.Create(name) + } + w, err := aarwcreate("AndroidManifest.xml") + if err != nil { + return err + } + const manifestFmt = ` +` + fmt.Fprintf(w, manifestFmt, "go."+pkgs[0].Name+".gojni", buildAndroidAPI) + + w, err = aarwcreate("proguard.txt") + if err != nil { + return err + } + fmt.Fprintln(w, `-keep class go.** { *; }`) + if bindJavaPkg != "" { + fmt.Fprintln(w, `-keep class `+bindJavaPkg+`.** { *; }`) + } else { + for _, p := range pkgs { + fmt.Fprintln(w, `-keep class `+p.Name+`.** { *; }`) + } + } + + w, err = aarwcreate("classes.jar") + if err != nil { + return err + } + if err := buildJar(w, srcDir); err != nil { + return err + } + + files := map[string]string{} + for _, pkg := range pkgs { + // TODO(hajimehoshi): This works only with Go tools that assume all source files are in one directory. + // Fix this to work with other Go tools. + assetsDir := filepath.Join(filepath.Dir(pkg.GoFiles[0]), "assets") + assetsDirExists := false + if fi, err := os.Stat(assetsDir); err == nil { + assetsDirExists = fi.IsDir() + } else if !os.IsNotExist(err) { + return err + } + + if assetsDirExists { + err := filepath.Walk( + assetsDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + name := "assets/" + path[len(assetsDir)+1:] + if orig, exists := files[name]; exists { + return fmt.Errorf("package %s asset name conflict: %s already added from package %s", + pkg.PkgPath, name, orig) + } + files[name] = pkg.PkgPath + w, err := aarwcreate(name) + if err != nil { + return nil + } + _, err = io.Copy(w, f) + return err + }) + if err != nil { + return err + } + } + } + + for _, t := range targets { + toolchain := ndk.Toolchain(t.arch) + lib := toolchain.abi + "/libgojni.so" + w, err = aarwcreate("jni/" + lib) + if err != nil { + return err + } + if !buildN { + r, err := os.Open(filepath.Join(androidDir, "src/main/jniLibs/"+lib)) + if err != nil { + return err + } + defer r.Close() + if _, err := io.Copy(w, r); err != nil { + return err + } + } + } + + // TODO(hyangah): do we need to use aapt to create R.txt? + w, err = aarwcreate("R.txt") + if err != nil { + return err + } + + w, err = aarwcreate("res/") + if err != nil { + return err + } + + return aarw.Close() +} + +const ( + javacTargetVer = "1.7" + minAndroidAPI = 16 +) + +func buildJar(w io.Writer, srcDir string) error { + var srcFiles []string + if buildN { + srcFiles = []string{"*.java"} + } else { + err := filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if filepath.Ext(path) == ".java" { + srcFiles = append(srcFiles, filepath.Join(".", path[len(srcDir):])) + } + return nil + }) + if err != nil { + return err + } + } + + dst := filepath.Join(tmpdir, "javac-output") + if !buildN { + if err := os.MkdirAll(dst, 0700); err != nil { + return err + } + } + + bClspath, err := bootClasspath() + + if err != nil { + return err + } + + args := []string{ + "-d", dst, + "-source", javacTargetVer, + "-target", javacTargetVer, + "-bootclasspath", bClspath, + } + if bindClasspath != "" { + args = append(args, "-classpath", bindClasspath) + } + + args = append(args, srcFiles...) + + javac := exec.Command("javac", args...) + javac.Dir = srcDir + if err := runCmd(javac); err != nil { + return err + } + + if buildX { + printcmd("jar c -C %s .", dst) + } + return writeJar(w, dst) +} + +func writeJar(w io.Writer, dir string) error { + if buildN { + return nil + } + jarw := zip.NewWriter(w) + jarwcreate := func(name string) (io.Writer, error) { + if buildV { + fmt.Fprintf(os.Stderr, "jar: %s\n", name) + } + return jarw.Create(name) + } + f, err := jarwcreate("META-INF/MANIFEST.MF") + if err != nil { + return err + } + fmt.Fprintf(f, manifestHeader) + + err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + out, err := jarwcreate(filepath.ToSlash(path[len(dir)+1:])) + if err != nil { + return err + } + in, err := os.Open(path) + if err != nil { + return err + } + defer in.Close() + _, err = io.Copy(out, in) + return err + }) + if err != nil { + return err + } + return jarw.Close() +} + +// buildAndroidSO generates an Android libgojni.so file to outputDir. +// buildAndroidSO is concurrent-safe. +func buildAndroidSO(outputDir string, arch string) error { + // Copy the environment variables to make this function concurrent-safe. + env := make([]string, len(androidEnv[arch])) + copy(env, androidEnv[arch]) + + // Add the generated packages to GOPATH for reverse bindings. + gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, goEnv("GOPATH")) + env = append(env, gopath) + + modulesUsed, err := areGoModulesUsed() + if err != nil { + return err + } + + srcDir := filepath.Join(tmpdir, "src") + + if modulesUsed { + // Copy the source directory for each architecture for concurrent building. + newSrcDir := filepath.Join(tmpdir, "src-android-"+arch) + if !buildN { + if err := doCopyAll(newSrcDir, srcDir); err != nil { + return err + } + } + srcDir = newSrcDir + + if err := writeGoMod(srcDir, "android", arch); err != nil { + return err + } + + // Run `go mod tidy` to force to create go.sum. + // Without go.sum, `go build` fails as of Go 1.16. + if err := goModTidyAt(srcDir, env); err != nil { + return err + } + } + + toolchain := ndk.Toolchain(arch) + if err := goBuildAt( + srcDir, + "./gobind", + env, + "-buildmode=c-shared", + "-o="+filepath.Join(outputDir, "src", "main", "jniLibs", toolchain.abi, "libgojni.so"), + ); err != nil { + return err + } + + return nil +} diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go new file mode 100644 index 000000000..a9f7a7f53 --- /dev/null +++ b/cmd/gomobile/bind_iosapp.go @@ -0,0 +1,316 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "errors" + "fmt" + "io" + "os/exec" + "path/filepath" + "strconv" + "strings" + "text/template" + + "golang.org/x/sync/errgroup" + "golang.org/x/tools/go/packages" +) + +func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error { + var name string + var title string + + if buildO == "" { + name = pkgs[0].Name + title = strings.Title(name) + buildO = title + ".xcframework" + } else { + if !strings.HasSuffix(buildO, ".xcframework") { + return fmt.Errorf("static framework name %q missing .xcframework suffix", buildO) + } + base := filepath.Base(buildO) + name = base[:len(base)-len(".xcframework")] + title = strings.Title(name) + } + + if err := removeAll(buildO); err != nil { + return err + } + + outDirsForPlatform := map[string]string{} + for _, t := range targets { + outDirsForPlatform[t.platform] = filepath.Join(tmpdir, t.platform) + } + + // Run the gobind command for each platform + var gobindWG errgroup.Group + for platform, outDir := range outDirsForPlatform { + platform := platform + outDir := outDir + gobindWG.Go(func() error { + // Catalyst support requires iOS 13+ + v, _ := strconv.ParseFloat(buildIOSVersion, 64) + if platform == "maccatalyst" && v < 13.0 { + return errors.New("catalyst requires -iosversion=13 or higher") + } + + // Run gobind once per platform to generate the bindings + cmd := exec.Command( + gobind, + "-lang=go,objc", + "-outdir="+outDir, + ) + cmd.Env = append(cmd.Env, "GOOS="+platformOS(platform)) + cmd.Env = append(cmd.Env, "CGO_ENABLED=1") + tags := append(buildTags[:], platformTags(platform)...) + cmd.Args = append(cmd.Args, "-tags="+strings.Join(tags, ",")) + if bindPrefix != "" { + cmd.Args = append(cmd.Args, "-prefix="+bindPrefix) + } + for _, p := range pkgs { + cmd.Args = append(cmd.Args, p.PkgPath) + } + if err := runCmd(cmd); err != nil { + return err + } + return nil + }) + } + if err := gobindWG.Wait(); err != nil { + return err + } + + modulesUsed, err := areGoModulesUsed() + if err != nil { + return err + } + + // Build archive files. + var buildWG errgroup.Group + for _, t := range targets { + t := t + buildWG.Go(func() error { + outDir := outDirsForPlatform[t.platform] + outSrcDir := filepath.Join(outDir, "src") + + if modulesUsed { + // Copy the source directory for each architecture for concurrent building. + newOutSrcDir := filepath.Join(outDir, "src-"+t.arch) + if !buildN { + if err := doCopyAll(newOutSrcDir, outSrcDir); err != nil { + return err + } + } + outSrcDir = newOutSrcDir + } + + // Copy the environment variables to make this function concurrent-safe. + env := make([]string, len(appleEnv[t.String()])) + copy(env, appleEnv[t.String()]) + + // Add the generated packages to GOPATH for reverse bindings. + gopath := fmt.Sprintf("GOPATH=%s%c%s", outDir, filepath.ListSeparator, goEnv("GOPATH")) + env = append(env, gopath) + + // Run `go mod tidy` to force to create go.sum. + // Without go.sum, `go build` fails as of Go 1.16. + if modulesUsed { + if err := writeGoMod(outSrcDir, t.platform, t.arch); err != nil { + return err + } + if err := goModTidyAt(outSrcDir, env); err != nil { + return err + } + } + + if err := goAppleBindArchive(appleArchiveFilepath(name, t), env, outSrcDir); err != nil { + return fmt.Errorf("%s/%s: %v", t.platform, t.arch, err) + } + + return nil + }) + } + if err := buildWG.Wait(); err != nil { + return err + } + + var frameworkDirs []string + frameworkArchCount := map[string]int{} + for _, t := range targets { + outDir := outDirsForPlatform[t.platform] + gobindDir := filepath.Join(outDir, "src", "gobind") + + env := appleEnv[t.String()][:] + sdk := getenv(env, "DARWIN_SDK") + + frameworkDir := filepath.Join(tmpdir, t.platform, sdk, title+".framework") + frameworkDirs = append(frameworkDirs, frameworkDir) + frameworkArchCount[frameworkDir] = frameworkArchCount[frameworkDir] + 1 + + versionsDir := filepath.Join(frameworkDir, "Versions") + versionsADir := filepath.Join(versionsDir, "A") + titlePath := filepath.Join(versionsADir, title) + if frameworkArchCount[frameworkDir] > 1 { + // Not the first static lib, attach to a fat library and skip create headers + fatCmd := exec.Command( + "xcrun", + "lipo", appleArchiveFilepath(name, t), titlePath, "-create", "-output", titlePath, + ) + if err := runCmd(fatCmd); err != nil { + return err + } + continue + } + + versionsAHeadersDir := filepath.Join(versionsADir, "Headers") + if err := mkdir(versionsAHeadersDir); err != nil { + return err + } + if err := symlink("A", filepath.Join(versionsDir, "Current")); err != nil { + return err + } + if err := symlink("Versions/Current/Headers", filepath.Join(frameworkDir, "Headers")); err != nil { + return err + } + if err := symlink(filepath.Join("Versions/Current", title), filepath.Join(frameworkDir, title)); err != nil { + return err + } + + lipoCmd := exec.Command( + "xcrun", + "lipo", appleArchiveFilepath(name, t), "-create", "-o", titlePath, + ) + if err := runCmd(lipoCmd); err != nil { + return err + } + + fileBases := make([]string, len(pkgs)+1) + for i, pkg := range pkgs { + fileBases[i] = bindPrefix + strings.Title(pkg.Name) + } + fileBases[len(fileBases)-1] = "Universe" + + // Copy header file next to output archive. + var headerFiles []string + if len(fileBases) == 1 { + headerFiles = append(headerFiles, title+".h") + err := copyFile( + filepath.Join(versionsAHeadersDir, title+".h"), + filepath.Join(gobindDir, bindPrefix+title+".objc.h"), + ) + if err != nil { + return err + } + } else { + for _, fileBase := range fileBases { + headerFiles = append(headerFiles, fileBase+".objc.h") + err := copyFile( + filepath.Join(versionsAHeadersDir, fileBase+".objc.h"), + filepath.Join(gobindDir, fileBase+".objc.h"), + ) + if err != nil { + return err + } + } + err := copyFile( + filepath.Join(versionsAHeadersDir, "ref.h"), + filepath.Join(gobindDir, "ref.h"), + ) + if err != nil { + return err + } + headerFiles = append(headerFiles, title+".h") + err = writeFile(filepath.Join(versionsAHeadersDir, title+".h"), func(w io.Writer) error { + return appleBindHeaderTmpl.Execute(w, map[string]interface{}{ + "pkgs": pkgs, "title": title, "bases": fileBases, + }) + }) + if err != nil { + return err + } + } + + if err := mkdir(filepath.Join(versionsADir, "Resources")); err != nil { + return err + } + if err := symlink("Versions/Current/Resources", filepath.Join(frameworkDir, "Resources")); err != nil { + return err + } + err = writeFile(filepath.Join(frameworkDir, "Resources", "Info.plist"), func(w io.Writer) error { + _, err := w.Write([]byte(appleBindInfoPlist)) + return err + }) + if err != nil { + return err + } + + var mmVals = struct { + Module string + Headers []string + }{ + Module: title, + Headers: headerFiles, + } + err = writeFile(filepath.Join(versionsADir, "Modules", "module.modulemap"), func(w io.Writer) error { + return appleModuleMapTmpl.Execute(w, mmVals) + }) + if err != nil { + return err + } + err = symlink(filepath.Join("Versions/Current/Modules"), filepath.Join(frameworkDir, "Modules")) + if err != nil { + return err + } + } + + // Finally combine all frameworks to an XCFramework + xcframeworkArgs := []string{"-create-xcframework"} + + for _, dir := range frameworkDirs { + xcframeworkArgs = append(xcframeworkArgs, "-framework", dir) + } + + xcframeworkArgs = append(xcframeworkArgs, "-output", buildO) + cmd := exec.Command("xcodebuild", xcframeworkArgs...) + err = runCmd(cmd) + return err +} + +const appleBindInfoPlist = ` + + + + + +` + +var appleModuleMapTmpl = template.Must(template.New("iosmmap").Parse(`framework module "{{.Module}}" { + header "ref.h" +{{range .Headers}} header "{{.}}" +{{end}} + export * +}`)) + +func appleArchiveFilepath(name string, t targetInfo) string { + return filepath.Join(tmpdir, name+"-"+t.platform+"-"+t.arch+".a") +} + +func goAppleBindArchive(out string, env []string, gosrc string) error { + return goBuildAt(gosrc, "./gobind", env, "-buildmode=c-archive", "-o", out) +} + +var appleBindHeaderTmpl = template.Must(template.New("apple.h").Parse(` +// Objective-C API for talking to the following Go packages +// +{{range .pkgs}}// {{.PkgPath}} +{{end}}// +// File is generated by gomobile bind. Do not edit. +#ifndef __{{.title}}_FRAMEWORK_H__ +#define __{{.title}}_FRAMEWORK_H__ + +{{range .bases}}#include "{{.}}.objc.h" +{{end}} +#endif +`)) diff --git a/cmd/gomobile/bind_test.go b/cmd/gomobile/bind_test.go new file mode 100644 index 000000000..fa6b0efb8 --- /dev/null +++ b/cmd/gomobile/bind_test.go @@ -0,0 +1,326 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + "text/template" + + "golang.org/x/mobile/internal/sdkpath" +) + +func TestBindAndroid(t *testing.T) { + platform, err := sdkpath.AndroidAPIPath(minAndroidAPI) + if err != nil { + t.Skip("No compatible Android API platform found, skipping bind") + } + // platform is a path like "/path/to/Android/sdk/platforms/android-32" + components := strings.Split(platform, string(filepath.Separator)) + if len(components) < 2 { + t.Fatalf("API path is too short: %s", platform) + } + components = components[len(components)-2:] + platformRel := filepath.Join("$ANDROID_HOME", components[0], components[1]) + + defer func() { + xout = os.Stderr + buildN = false + buildX = false + buildO = "" + buildTarget = "" + bindJavaPkg = "" + }() + buildN = true + buildX = true + buildO = "asset.aar" + buildTarget = "android/arm" + + tests := []struct { + javaPkg string + }{ + { + // Empty javaPkg + }, + { + javaPkg: "com.example.foo", + }, + } + for _, tc := range tests { + bindJavaPkg = tc.javaPkg + + buf := new(bytes.Buffer) + xout = buf + gopath = filepath.SplitList(goEnv("GOPATH"))[0] + if goos == "windows" { + os.Setenv("HOMEDRIVE", "C:") + } + cmdBind.flag.Parse([]string{"golang.org/x/mobile/asset"}) + err := runBind(cmdBind) + if err != nil { + t.Log(buf.String()) + t.Fatal(err) + } + got := filepath.ToSlash(buf.String()) + + output, err := defaultOutputData("") + if err != nil { + t.Fatal(err) + } + data := struct { + outputData + AndroidPlatform string + JavaPkg string + }{ + outputData: output, + AndroidPlatform: platformRel, + JavaPkg: tc.javaPkg, + } + + wantBuf := new(bytes.Buffer) + if err := bindAndroidTmpl.Execute(wantBuf, data); err != nil { + t.Errorf("%+v: computing diff failed: %v", tc, err) + continue + } + + diff, err := diff(got, wantBuf.String()) + if err != nil { + t.Errorf("%+v: computing diff failed: %v", tc, err) + continue + } + if diff != "" { + t.Errorf("%+v: unexpected output:\n%s", tc, diff) + } + } +} + +func TestBindApple(t *testing.T) { + if !xcodeAvailable() { + t.Skip("Xcode is missing") + } + defer func() { + xout = os.Stderr + buildN = false + buildX = false + buildO = "" + buildTarget = "" + bindPrefix = "" + }() + buildN = true + buildX = true + buildO = "Asset.xcframework" + buildTarget = "ios/arm64" + + tests := []struct { + prefix string + out string + }{ + { + // empty prefix + }, + { + prefix: "Foo", + }, + { + out: "Abcde.xcframework", + }, + } + for _, tc := range tests { + bindPrefix = tc.prefix + if tc.out != "" { + buildO = tc.out + } + + buf := new(bytes.Buffer) + xout = buf + gopath = filepath.SplitList(goEnv("GOPATH"))[0] + if goos == "windows" { + os.Setenv("HOMEDRIVE", "C:") + } + cmdBind.flag.Parse([]string{"golang.org/x/mobile/asset"}) + if err := runBind(cmdBind); err != nil { + t.Log(buf.String()) + t.Fatal(err) + } + got := filepath.ToSlash(buf.String()) + + output, err := defaultOutputData("") + if err != nil { + t.Fatal(err) + } + + data := struct { + outputData + Output string + Prefix string + }{ + outputData: output, + Output: buildO[:len(buildO)-len(".xcframework")], + Prefix: tc.prefix, + } + + wantBuf := new(bytes.Buffer) + if err := bindAppleTmpl.Execute(wantBuf, data); err != nil { + t.Errorf("%+v: computing diff failed: %v", tc, err) + continue + } + + diff, err := diff(got, wantBuf.String()) + if err != nil { + t.Errorf("%+v: computing diff failed: %v", tc, err) + continue + } + if diff != "" { + t.Errorf("%+v: unexpected output:\n%s", tc, diff) + } + } +} + +var bindAndroidTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile +WORK=$WORK +GOOS=android CGO_ENABLED=1 gobind -lang=go,java -outdir=$WORK{{if .JavaPkg}} -javapkg={{.JavaPkg}}{{end}} golang.org/x/mobile/asset +mkdir -p $WORK/src-android-arm +PWD=$WORK/src-android-arm GOMODCACHE=$GOPATH/pkg/mod GOOS=android GOARCH=arm CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang++ CGO_ENABLED=1 GOARM=7 GOPATH=$WORK:$GOPATH go mod tidy +PWD=$WORK/src-android-arm GOMODCACHE=$GOPATH/pkg/mod GOOS=android GOARCH=arm CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang++ CGO_ENABLED=1 GOARM=7 GOPATH=$WORK:$GOPATH go build -x -buildmode=c-shared -o=$WORK/android/src/main/jniLibs/armeabi-v7a/libgojni.so ./gobind +PWD=$WORK/java javac -d $WORK/javac-output -source 1.7 -target 1.7 -bootclasspath {{.AndroidPlatform}}/android.jar *.java +jar c -C $WORK/javac-output . +`)) + +var bindAppleTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile +WORK=$WORK +rm -r -f "{{.Output}}.xcframework" +GOOS=ios CGO_ENABLED=1 gobind -lang=go,objc -outdir=$WORK/ios -tags=ios{{if .Prefix}} -prefix={{.Prefix}}{{end}} golang.org/x/mobile/asset +mkdir -p $WORK/ios/src-arm64 +PWD=$WORK/ios/src-arm64 GOMODCACHE=$GOPATH/pkg/mod GOOS=ios GOARCH=arm64 GOFLAGS=-tags=ios CC=iphoneos-clang CXX=iphoneos-clang++ CGO_CFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_CXXFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_LDFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_ENABLED=1 DARWIN_SDK=iphoneos GOPATH=$WORK/ios:$GOPATH go mod tidy +PWD=$WORK/ios/src-arm64 GOMODCACHE=$GOPATH/pkg/mod GOOS=ios GOARCH=arm64 GOFLAGS=-tags=ios CC=iphoneos-clang CXX=iphoneos-clang++ CGO_CFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_CXXFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_LDFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_ENABLED=1 DARWIN_SDK=iphoneos GOPATH=$WORK/ios:$GOPATH go build -x -buildmode=c-archive -o $WORK/{{.Output}}-ios-arm64.a ./gobind +mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers +ln -s A $WORK/ios/iphoneos/{{.Output}}.framework/Versions/Current +ln -s Versions/Current/Headers $WORK/ios/iphoneos/{{.Output}}.framework/Headers +ln -s Versions/Current/{{.Output}} $WORK/ios/iphoneos/{{.Output}}.framework/{{.Output}} +xcrun lipo $WORK/{{.Output}}-ios-arm64.a -create -o $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/{{.Output}} +cp $WORK/ios/src/gobind/{{.Prefix}}Asset.objc.h $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers/{{.Prefix}}Asset.objc.h +mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers +cp $WORK/ios/src/gobind/Universe.objc.h $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers/Universe.objc.h +mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers +cp $WORK/ios/src/gobind/ref.h $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers/ref.h +mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers +mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers +mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Resources +ln -s Versions/Current/Resources $WORK/ios/iphoneos/{{.Output}}.framework/Resources +mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Resources +mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Modules +ln -s Versions/Current/Modules $WORK/ios/iphoneos/{{.Output}}.framework/Modules +xcodebuild -create-xcframework -framework $WORK/ios/iphoneos/{{.Output}}.framework -output {{.Output}}.xcframework +`)) + +func TestBindAppleAll(t *testing.T) { + if !xcodeAvailable() { + t.Skip("Xcode is missing") + } + defer func() { + xout = os.Stderr + buildN = false + buildX = false + buildO = "" + buildTarget = "" + bindPrefix = "" + }() + buildN = true + buildX = true + buildO = "Asset.xcframework" + buildTarget = "ios" + + buf := new(bytes.Buffer) + xout = buf + gopath = filepath.SplitList(goEnv("GOPATH"))[0] + if goos == "windows" { + os.Setenv("HOMEDRIVE", "C:") + } + cmdBind.flag.Parse([]string{"golang.org/x/mobile/asset"}) + if err := runBind(cmdBind); err != nil { + t.Log(buf.String()) + t.Fatal(err) + } +} + +func TestBindWithGoModules(t *testing.T) { + if runtime.GOOS == "android" || runtime.GOOS == "ios" { + t.Skipf("gomobile and gobind are not available on %s", runtime.GOOS) + } + + dir, err := ioutil.TempDir("", "gomobile-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + if out, err := exec.Command("go", "build", "-o="+dir, "golang.org/x/mobile/cmd/gobind").CombinedOutput(); err != nil { + t.Fatalf("%v: %s", err, string(out)) + } + if out, err := exec.Command("go", "build", "-o="+dir, "golang.org/x/mobile/cmd/gomobile").CombinedOutput(); err != nil { + t.Fatalf("%v: %s", err, string(out)) + } + path := dir + if p := os.Getenv("PATH"); p != "" { + path += string(filepath.ListSeparator) + p + } + + for _, target := range []string{"android", "ios"} { + t.Run(target, func(t *testing.T) { + switch target { + case "android": + if _, err := sdkpath.AndroidAPIPath(minAndroidAPI); err != nil { + t.Skip("No compatible Android API platform found, skipping bind") + } + case "ios": + if !xcodeAvailable() { + t.Skip("Xcode is missing") + } + } + + var out string + switch target { + case "android": + out = filepath.Join(dir, "cgopkg.aar") + case "ios": + out = filepath.Join(dir, "Cgopkg.xcframework") + } + + tests := []struct { + Name string + Path string + Dir string + }{ + { + Name: "Absolute Path", + Path: "golang.org/x/mobile/bind/testdata/cgopkg", + }, + { + Name: "Relative Path", + Path: "./bind/testdata/cgopkg", + Dir: filepath.Join("..", ".."), + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.Name, func(t *testing.T) { + cmd := exec.Command(filepath.Join(dir, "gomobile"), "bind", "-target="+target, "-o="+out, tc.Path) + cmd.Env = append(os.Environ(), "PATH="+path, "GO111MODULE=on") + cmd.Dir = tc.Dir + if out, err := cmd.CombinedOutput(); err != nil { + t.Errorf("gomobile bind failed: %v\n%s", err, string(out)) + } + }) + } + }) + } +} diff --git a/cmd/gomobile/build.go b/cmd/gomobile/build.go new file mode 100644 index 000000000..c9483434d --- /dev/null +++ b/cmd/gomobile/build.go @@ -0,0 +1,448 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run gendex.go -o dex.go + +package main + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + + "golang.org/x/mobile/internal/sdkpath" + "golang.org/x/tools/go/packages" +) + +var tmpdir string + +var cmdBuild = &command{ + run: runBuild, + Name: "build", + Usage: "[-target android|" + strings.Join(applePlatforms, "|") + "] [-o output] [-bundleid bundleID] [build flags] [package]", + Short: "compile android APK and iOS app", + Long: ` +Build compiles and encodes the app named by the import path. + +The named package must define a main function. + +The -target flag takes either android (the default), or one or more +comma-delimited Apple platforms (` + strings.Join(applePlatforms, ", ") + `). + +For -target android, if an AndroidManifest.xml is defined in the +package directory, it is added to the APK output. Otherwise, a default +manifest is generated. By default, this builds a fat APK for all supported +instruction sets (arm, 386, amd64, arm64). A subset of instruction sets can +be selected by specifying target type with the architecture name. E.g. +-target=android/arm,android/386. + +For Apple -target platforms, gomobile must be run on an OS X machine with +Xcode installed. + +By default, -target ios will generate an XCFramework for both ios +and iossimulator. Multiple Apple targets can be specified, creating a "fat" +XCFramework with each slice. To generate a fat XCFramework that supports +iOS, macOS, and macCatalyst for all supportec architectures (amd64 and arm64), +specify -target ios,macos,maccatalyst. A subset of instruction sets can be +selectged by specifying the platform with an architecture name. E.g. +-target=ios/arm64,maccatalyst/arm64. + +If the package directory contains an assets subdirectory, its contents +are copied into the output. + +Flag -iosversion sets the minimal version of the iOS SDK to compile against. +The default version is 13.0. + +Flag -androidapi sets the Android API version to compile against. +The default and minimum is 16. + +The -bundleid flag is required for -target ios and sets the bundle ID to use +with the app. + +The -o flag specifies the output file name. If not specified, the +output file name depends on the package built. + +The -v flag provides verbose output, including the list of packages built. + +The build flags -a, -i, -n, -x, -gcflags, -ldflags, -tags, -trimpath, and -work are +shared with the build command. For documentation, see 'go help build'. +`, +} + +func runBuild(cmd *command) (err error) { + _, err = runBuildImpl(cmd) + return +} + +// runBuildImpl builds a package for mobiles based on the given commands. +// runBuildImpl returns a built package information and an error if exists. +func runBuildImpl(cmd *command) (*packages.Package, error) { + cleanup, err := buildEnvInit() + if err != nil { + return nil, err + } + defer cleanup() + + args := cmd.flag.Args() + + targets, err := parseBuildTarget(buildTarget) + if err != nil { + return nil, fmt.Errorf(`invalid -target=%q: %v`, buildTarget, err) + } + + var buildPath string + switch len(args) { + case 0: + buildPath = "." + case 1: + buildPath = args[0] + default: + cmd.usage() + os.Exit(1) + } + + // TODO(ydnar): this should work, unless build tags affect loading a single package. + // Should we try to import packages with different build tags per platform? + pkgs, err := packages.Load(packagesConfig(targets[0]), buildPath) + if err != nil { + return nil, err + } + + // len(pkgs) can be more than 1 e.g., when the specified path includes `...`. + if len(pkgs) != 1 { + cmd.usage() + os.Exit(1) + } + + pkg := pkgs[0] + + if pkg.Name != "main" && buildO != "" { + return nil, fmt.Errorf("cannot set -o when building non-main package") + } + + var nmpkgs map[string]bool + switch { + case isAndroidPlatform(targets[0].platform): + if pkg.Name != "main" { + for _, t := range targets { + if err := goBuild(pkg.PkgPath, androidEnv[t.arch]); err != nil { + return nil, err + } + } + return pkg, nil + } + nmpkgs, err = goAndroidBuild(pkg, targets) + if err != nil { + return nil, err + } + case isApplePlatform(targets[0].platform): + if !xcodeAvailable() { + return nil, fmt.Errorf("-target=%s requires XCode", buildTarget) + } + if pkg.Name != "main" { + for _, t := range targets { + // Catalyst support requires iOS 13+ + v, _ := strconv.ParseFloat(buildIOSVersion, 64) + if t.platform == "maccatalyst" && v < 13.0 { + return nil, errors.New("catalyst requires -iosversion=13 or higher") + } + if err := goBuild(pkg.PkgPath, appleEnv[t.String()]); err != nil { + return nil, err + } + } + return pkg, nil + } + if buildBundleID == "" { + return nil, fmt.Errorf("-target=ios requires -bundleid set") + } + nmpkgs, err = goAppleBuild(pkg, buildBundleID, targets) + if err != nil { + return nil, err + } + } + + if !nmpkgs["golang.org/x/mobile/app"] { + return nil, fmt.Errorf(`%s does not import "golang.org/x/mobile/app"`, pkg.PkgPath) + } + + return pkg, nil +} + +var nmRE = regexp.MustCompile(`[0-9a-f]{8} t _?(?:.*/vendor/)?(golang.org/x.*/[^.]*)`) + +func extractPkgs(nm string, path string) (map[string]bool, error) { + if buildN { + return map[string]bool{"golang.org/x/mobile/app": true}, nil + } + r, w := io.Pipe() + cmd := exec.Command(nm, path) + cmd.Stdout = w + cmd.Stderr = os.Stderr + + nmpkgs := make(map[string]bool) + errc := make(chan error, 1) + go func() { + s := bufio.NewScanner(r) + for s.Scan() { + if res := nmRE.FindStringSubmatch(s.Text()); res != nil { + nmpkgs[res[1]] = true + } + } + errc <- s.Err() + }() + + err := cmd.Run() + w.Close() + if err != nil { + return nil, fmt.Errorf("%s %s: %v", nm, path, err) + } + if err := <-errc; err != nil { + return nil, fmt.Errorf("%s %s: %v", nm, path, err) + } + return nmpkgs, nil +} + +var xout io.Writer = os.Stderr + +func printcmd(format string, args ...interface{}) { + cmd := fmt.Sprintf(format+"\n", args...) + if tmpdir != "" { + cmd = strings.Replace(cmd, tmpdir, "$WORK", -1) + } + if androidHome, err := sdkpath.AndroidHome(); err == nil { + cmd = strings.Replace(cmd, androidHome, "$ANDROID_HOME", -1) + } + if gomobilepath != "" { + cmd = strings.Replace(cmd, gomobilepath, "$GOMOBILE", -1) + } + if gopath := goEnv("GOPATH"); gopath != "" { + cmd = strings.Replace(cmd, gopath, "$GOPATH", -1) + } + if env := os.Getenv("HOMEPATH"); env != "" { + cmd = strings.Replace(cmd, env, "$HOMEPATH", -1) + } + fmt.Fprint(xout, cmd) +} + +// "Build flags", used by multiple commands. +var ( + buildA bool // -a + buildI bool // -i + buildN bool // -n + buildV bool // -v + buildX bool // -x + buildO string // -o + buildGcflags string // -gcflags + buildLdflags string // -ldflags + buildTarget string // -target + buildTrimpath bool // -trimpath + buildWork bool // -work + buildBundleID string // -bundleid + buildIOSVersion string // -iosversion + buildAndroidAPI int // -androidapi + buildTags stringsFlag // -tags +) + +func addBuildFlags(cmd *command) { + cmd.flag.StringVar(&buildO, "o", "", "") + cmd.flag.StringVar(&buildGcflags, "gcflags", "", "") + cmd.flag.StringVar(&buildLdflags, "ldflags", "", "") + cmd.flag.StringVar(&buildTarget, "target", "android", "") + cmd.flag.StringVar(&buildBundleID, "bundleid", "", "") + cmd.flag.StringVar(&buildIOSVersion, "iosversion", "13.0", "") + cmd.flag.IntVar(&buildAndroidAPI, "androidapi", minAndroidAPI, "") + + cmd.flag.BoolVar(&buildA, "a", false, "") + cmd.flag.BoolVar(&buildI, "i", false, "") + cmd.flag.BoolVar(&buildTrimpath, "trimpath", false, "") + cmd.flag.Var(&buildTags, "tags", "") +} + +func addBuildFlagsNVXWork(cmd *command) { + cmd.flag.BoolVar(&buildN, "n", false, "") + cmd.flag.BoolVar(&buildV, "v", false, "") + cmd.flag.BoolVar(&buildX, "x", false, "") + cmd.flag.BoolVar(&buildWork, "work", false, "") +} + +func init() { + addBuildFlags(cmdBuild) + addBuildFlagsNVXWork(cmdBuild) + + addBuildFlags(cmdInstall) + addBuildFlagsNVXWork(cmdInstall) + + addBuildFlagsNVXWork(cmdInit) + + addBuildFlags(cmdBind) + addBuildFlagsNVXWork(cmdBind) + + addBuildFlagsNVXWork(cmdClean) +} + +func goBuild(src string, env []string, args ...string) error { + return goCmd("build", []string{src}, env, args...) +} + +func goBuildAt(at string, src string, env []string, args ...string) error { + return goCmdAt(at, "build", []string{src}, env, args...) +} + +func goInstall(srcs []string, env []string, args ...string) error { + return goCmd("install", srcs, env, args...) +} + +func goCmd(subcmd string, srcs []string, env []string, args ...string) error { + return goCmdAt("", subcmd, srcs, env, args...) +} + +func goCmdAt(at string, subcmd string, srcs []string, env []string, args ...string) error { + cmd := exec.Command("go", subcmd) + tags := buildTags + if len(tags) > 0 { + cmd.Args = append(cmd.Args, "-tags", strings.Join(tags, ",")) + } + if buildV { + cmd.Args = append(cmd.Args, "-v") + } + if subcmd != "install" && buildI { + cmd.Args = append(cmd.Args, "-i") + } + if buildX { + cmd.Args = append(cmd.Args, "-x") + } + if buildGcflags != "" { + cmd.Args = append(cmd.Args, "-gcflags", buildGcflags) + } + if buildLdflags != "" { + cmd.Args = append(cmd.Args, "-ldflags", buildLdflags) + } + if buildTrimpath { + cmd.Args = append(cmd.Args, "-trimpath") + } + if buildWork { + cmd.Args = append(cmd.Args, "-work") + } + cmd.Args = append(cmd.Args, args...) + cmd.Args = append(cmd.Args, srcs...) + + // Specify GOMODCACHE explicitly. The default cache path is GOPATH[0]/pkg/mod, + // but the path varies when GOPATH is specified at env, which results in cold cache. + if gmc, err := goModCachePath(); err == nil { + env = append([]string{"GOMODCACHE=" + gmc}, env...) + } else { + env = append([]string{}, env...) + } + cmd.Env = env + cmd.Dir = at + return runCmd(cmd) +} + +func goModTidyAt(at string, env []string) error { + cmd := exec.Command("go", "mod", "tidy") + if buildV { + cmd.Args = append(cmd.Args, "-v") + } + + // Specify GOMODCACHE explicitly. The default cache path is GOPATH[0]/pkg/mod, + // but the path varies when GOPATH is specified at env, which results in cold cache. + if gmc, err := goModCachePath(); err == nil { + env = append([]string{"GOMODCACHE=" + gmc}, env...) + } else { + env = append([]string{}, env...) + } + cmd.Env = env + cmd.Dir = at + return runCmd(cmd) +} + +// parseBuildTarget parses buildTarget into 1 or more platforms and architectures. +// Returns an error if buildTarget contains invalid input. +// Example valid target strings: +// +// android +// android/arm64,android/386,android/amd64 +// ios,iossimulator,maccatalyst +// macos/amd64 +func parseBuildTarget(buildTarget string) ([]targetInfo, error) { + if buildTarget == "" { + return nil, fmt.Errorf(`invalid target ""`) + } + + targets := []targetInfo{} + targetsAdded := make(map[targetInfo]bool) + + addTarget := func(platform, arch string) { + t := targetInfo{platform, arch} + if targetsAdded[t] { + return + } + targets = append(targets, t) + targetsAdded[t] = true + } + + addPlatform := func(platform string) { + for _, arch := range platformArchs(platform) { + addTarget(platform, arch) + } + } + + var isAndroid, isApple bool + for _, target := range strings.Split(buildTarget, ",") { + tuple := strings.SplitN(target, "/", 2) + platform := tuple[0] + hasArch := len(tuple) == 2 + + if isAndroidPlatform(platform) { + isAndroid = true + } else if isApplePlatform(platform) { + isApple = true + } else { + return nil, fmt.Errorf("unsupported platform: %q", platform) + } + if isAndroid && isApple { + return nil, fmt.Errorf(`cannot mix android and Apple platforms`) + } + + if hasArch { + arch := tuple[1] + if !isSupportedArch(platform, arch) { + return nil, fmt.Errorf(`unsupported platform/arch: %q`, target) + } + addTarget(platform, arch) + } else { + addPlatform(platform) + } + } + + // Special case to build iossimulator if -target=ios + if buildTarget == "ios" { + addPlatform("iossimulator") + } + + return targets, nil +} + +type targetInfo struct { + platform string + arch string +} + +func (t targetInfo) String() string { + return t.platform + "/" + t.arch +} + +func goModCachePath() (string, error) { + out, err := exec.Command("go", "env", "GOMODCACHE").Output() + if err != nil { + return "", err + } + return strings.TrimSpace(string(out)), nil +} diff --git a/cmd/gomobile/build_androidapp.go b/cmd/gomobile/build_androidapp.go new file mode 100644 index 000000000..bcd2664bd --- /dev/null +++ b/cmd/gomobile/build_androidapp.go @@ -0,0 +1,358 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "encoding/xml" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + "strings" + + "golang.org/x/mobile/internal/binres" + "golang.org/x/tools/go/packages" +) + +func goAndroidBuild(pkg *packages.Package, targets []targetInfo) (map[string]bool, error) { + ndkRoot, err := ndkRoot(targets...) + if err != nil { + return nil, err + } + appName := path.Base(pkg.PkgPath) + libName := androidPkgName(appName) + + // TODO(hajimehoshi): This works only with Go tools that assume all source files are in one directory. + // Fix this to work with other Go tools. + dir := filepath.Dir(pkg.GoFiles[0]) + + manifestPath := filepath.Join(dir, "AndroidManifest.xml") + manifestData, err := ioutil.ReadFile(manifestPath) + if err != nil { + if !os.IsNotExist(err) { + return nil, err + } + + buf := new(bytes.Buffer) + buf.WriteString(``) + err := manifestTmpl.Execute(buf, manifestTmplData{ + // TODO(crawshaw): a better package path. + JavaPkgPath: "org.golang.todo." + libName, + Name: strings.Title(appName), + LibName: libName, + }) + if err != nil { + return nil, err + } + manifestData = buf.Bytes() + if buildV { + fmt.Fprintf(os.Stderr, "generated AndroidManifest.xml:\n%s\n", manifestData) + } + } else { + libName, err = manifestLibName(manifestData) + if err != nil { + return nil, fmt.Errorf("error parsing %s: %v", manifestPath, err) + } + } + + libFiles := []string{} + nmpkgs := make(map[string]map[string]bool) // map: arch -> extractPkgs' output + + for _, t := range targets { + toolchain := ndk.Toolchain(t.arch) + libPath := "lib/" + toolchain.abi + "/lib" + libName + ".so" + libAbsPath := filepath.Join(tmpdir, libPath) + if err := mkdir(filepath.Dir(libAbsPath)); err != nil { + return nil, err + } + err = goBuild( + pkg.PkgPath, + androidEnv[t.arch], + "-buildmode=c-shared", + "-o", libAbsPath, + ) + if err != nil { + return nil, err + } + nmpkgs[t.arch], err = extractPkgs(toolchain.Path(ndkRoot, "nm"), libAbsPath) + if err != nil { + return nil, err + } + libFiles = append(libFiles, libPath) + } + + block, _ := pem.Decode([]byte(debugCert)) + if block == nil { + return nil, errors.New("no debug cert") + } + privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + if buildO == "" { + buildO = androidPkgName(path.Base(pkg.PkgPath)) + ".apk" + } + if !strings.HasSuffix(buildO, ".apk") { + return nil, fmt.Errorf("output file name %q does not end in '.apk'", buildO) + } + var out io.Writer + if !buildN { + f, err := os.Create(buildO) + if err != nil { + return nil, err + } + defer func() { + if cerr := f.Close(); err == nil { + err = cerr + } + }() + out = f + } + + var apkw *Writer + if !buildN { + apkw = NewWriter(out, privKey) + } + apkwCreate := func(name string) (io.Writer, error) { + if buildV { + fmt.Fprintf(os.Stderr, "apk: %s\n", name) + } + if buildN { + return ioutil.Discard, nil + } + return apkw.Create(name) + } + apkwWriteFile := func(dst, src string) error { + w, err := apkwCreate(dst) + if err != nil { + return err + } + if !buildN { + f, err := os.Open(src) + if err != nil { + return err + } + defer f.Close() + if _, err := io.Copy(w, f); err != nil { + return err + } + } + return nil + } + + w, err := apkwCreate("classes.dex") + if err != nil { + return nil, err + } + dexData, err := base64.StdEncoding.DecodeString(dexStr) + if err != nil { + log.Fatalf("internal error bad dexStr: %v", err) + } + if _, err := w.Write(dexData); err != nil { + return nil, err + } + + for _, libFile := range libFiles { + if err := apkwWriteFile(libFile, filepath.Join(tmpdir, libFile)); err != nil { + return nil, err + } + } + + for _, t := range targets { + toolchain := ndk.Toolchain(t.arch) + if nmpkgs[t.arch]["golang.org/x/mobile/exp/audio/al"] { + dst := "lib/" + toolchain.abi + "/libopenal.so" + src := filepath.Join(gomobilepath, dst) + if _, err := os.Stat(src); err != nil { + return nil, errors.New("the Android requires the golang.org/x/mobile/exp/audio/al, but the OpenAL libraries was not found. Please run gomobile init with the -openal flag pointing to an OpenAL source directory.") + } + if err := apkwWriteFile(dst, src); err != nil { + return nil, err + } + } + } + + // Add any assets. + var arsc struct { + iconPath string + } + assetsDir := filepath.Join(dir, "assets") + assetsDirExists := true + fi, err := os.Stat(assetsDir) + if err != nil { + if os.IsNotExist(err) { + assetsDirExists = false + } else { + return nil, err + } + } else { + assetsDirExists = fi.IsDir() + } + if assetsDirExists { + // if assets is a symlink, follow the symlink. + assetsDir, err = filepath.EvalSymlinks(assetsDir) + if err != nil { + return nil, err + } + err = filepath.Walk(assetsDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if name := filepath.Base(path); strings.HasPrefix(name, ".") { + // Do not include the hidden files. + return nil + } + if info.IsDir() { + return nil + } + + if rel, err := filepath.Rel(assetsDir, path); rel == "icon.png" && err == nil { + arsc.iconPath = path + // TODO returning here does not write the assets/icon.png to the final assets output, + // making it unavailable via the assets API. Should the file be duplicated into assets + // or should assets API be able to retrieve files from the generated resource table? + return nil + } + + name := "assets/" + path[len(assetsDir)+1:] + return apkwWriteFile(name, path) + }) + if err != nil { + return nil, fmt.Errorf("asset %v", err) + } + } + + bxml, err := binres.UnmarshalXML(bytes.NewReader(manifestData), arsc.iconPath != "") + if err != nil { + return nil, err + } + + // generate resources.arsc identifying single xxxhdpi icon resource. + if arsc.iconPath != "" { + pkgname, err := bxml.RawValueByName("manifest", xml.Name{Local: "package"}) + if err != nil { + return nil, err + } + tbl, name := binres.NewMipmapTable(pkgname) + if err := apkwWriteFile(name, arsc.iconPath); err != nil { + return nil, err + } + w, err := apkwCreate("resources.arsc") + if err != nil { + return nil, err + } + bin, err := tbl.MarshalBinary() + if err != nil { + return nil, err + } + if _, err := w.Write(bin); err != nil { + return nil, err + } + } + + w, err = apkwCreate("AndroidManifest.xml") + if err != nil { + return nil, err + } + bin, err := bxml.MarshalBinary() + if err != nil { + return nil, err + } + if _, err := w.Write(bin); err != nil { + return nil, err + } + + // TODO: add gdbserver to apk? + + if !buildN { + if err := apkw.Close(); err != nil { + return nil, err + } + } + + // TODO: return nmpkgs + return nmpkgs[targets[0].arch], nil +} + +// androidPkgName sanitizes the go package name to be acceptable as a android +// package name part. The android package name convention is similar to the +// java package name convention described in +// https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.5.3.1 +// but not exactly same. +func androidPkgName(name string) string { + var res []rune + for _, r := range name { + switch { + case 'a' <= r && r <= 'z', 'A' <= r && r <= 'Z', '0' <= r && r <= '9': + res = append(res, r) + default: + res = append(res, '_') + } + } + if len(res) == 0 || res[0] == '_' || ('0' <= res[0] && res[0] <= '9') { + // Android does not seem to allow the package part starting with _. + res = append([]rune{'g', 'o'}, res...) + } + s := string(res) + // Look for Java keywords that are not Go keywords, and avoid using + // them as a package name. + // + // This is not a problem for normal Go identifiers as we only expose + // exported symbols. The upper case first letter saves everything + // from accidentally matching except for the package name. + // + // Note that basic type names (like int) are not keywords in Go. + switch s { + case "abstract", "assert", "boolean", "byte", "catch", "char", "class", + "do", "double", "enum", "extends", "final", "finally", "float", + "implements", "instanceof", "int", "long", "native", "private", + "protected", "public", "short", "static", "strictfp", "super", + "synchronized", "this", "throw", "throws", "transient", "try", + "void", "volatile", "while": + s += "_" + } + return s +} + +// A random uninteresting private key. +// Must be consistent across builds so newer app versions can be installed. +const debugCert = ` +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAy6ItnWZJ8DpX9R5FdWbS9Kr1U8Z7mKgqNByGU7No99JUnmyu +NQ6Uy6Nj0Gz3o3c0BXESECblOC13WdzjsH1Pi7/L9QV8jXOXX8cvkG5SJAyj6hcO +LOapjDiN89NXjXtyv206JWYvRtpexyVrmHJgRAw3fiFI+m4g4Qop1CxcIF/EgYh7 +rYrqh4wbCM1OGaCleQWaOCXxZGm+J5YNKQcWpjZRrDrb35IZmlT0bK46CXUKvCqK +x7YXHgfhC8ZsXCtsScKJVHs7gEsNxz7A0XoibFw6DoxtjKzUCktnT0w3wxdY7OTj +9AR8mobFlM9W3yirX8TtwekWhDNTYEu8dwwykwIDAQABAoIBAA2hjpIhvcNR9H9Z +BmdEecydAQ0ZlT5zy1dvrWI++UDVmIp+Ve8BSd6T0mOqV61elmHi3sWsBN4M1Rdz +3N38lW2SajG9q0fAvBpSOBHgAKmfGv3Ziz5gNmtHgeEXfZ3f7J95zVGhlHqWtY95 +JsmuplkHxFMyITN6WcMWrhQg4A3enKLhJLlaGLJf9PeBrvVxHR1/txrfENd2iJBH +FmxVGILL09fIIktJvoScbzVOneeWXj5vJGzWVhB17DHBbANGvVPdD5f+k/s5aooh +hWAy/yLKocr294C4J+gkO5h2zjjjSGcmVHfrhlXQoEPX+iW1TGoF8BMtl4Llc+jw +lKWKfpECgYEA9C428Z6CvAn+KJ2yhbAtuRo41kkOVoiQPtlPeRYs91Pq4+NBlfKO +2nWLkyavVrLx4YQeCeaEU2Xoieo9msfLZGTVxgRlztylOUR+zz2FzDBYGicuUD3s +EqC0Wv7tiX6dumpWyOcVVLmR9aKlOUzA9xemzIsWUwL3PpyONhKSq7kCgYEA1X2F +f2jKjoOVzglhtuX4/SP9GxS4gRf9rOQ1Q8DzZhyH2LZ6Dnb1uEQvGhiqJTU8CXxb +7odI0fgyNXq425Nlxc1Tu0G38TtJhwrx7HWHuFcbI/QpRtDYLWil8Zr7Q3BT9rdh +moo4m937hLMvqOG9pyIbyjOEPK2WBCtKW5yabqsCgYEAu9DkUBr1Qf+Jr+IEU9I8 +iRkDSMeusJ6gHMd32pJVCfRRQvIlG1oTyTMKpafmzBAd/rFpjYHynFdRcutqcShm +aJUq3QG68U9EAvWNeIhA5tr0mUEz3WKTt4xGzYsyWES8u4tZr3QXMzD9dOuinJ1N ++4EEumXtSPKKDG3M8Qh+KnkCgYBUEVSTYmF5EynXc2xOCGsuy5AsrNEmzJqxDUBI +SN/P0uZPmTOhJIkIIZlmrlW5xye4GIde+1jajeC/nG7U0EsgRAV31J4pWQ5QJigz +0+g419wxIUFryGuIHhBSfpP472+w1G+T2mAGSLh1fdYDq7jx6oWE7xpghn5vb9id +EKLjdwKBgBtz9mzbzutIfAW0Y8F23T60nKvQ0gibE92rnUbjPnw8HjL3AZLU05N+ +cSL5bhq0N5XHK77sscxW9vXjG0LJMXmFZPp9F6aV6ejkMIXyJ/Yz/EqeaJFwilTq +Mc6xR47qkdzu0dQ1aPm4XD7AWDtIvPo/GG2DKOucLBbQc2cOWtKS +-----END RSA PRIVATE KEY----- +` diff --git a/cmd/gomobile/build_apple.go b/cmd/gomobile/build_apple.go new file mode 100644 index 000000000..f7b682389 --- /dev/null +++ b/cmd/gomobile/build_apple.go @@ -0,0 +1,618 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "crypto/x509" + "encoding/pem" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + "text/template" + + "golang.org/x/tools/go/packages" +) + +func goAppleBuild(pkg *packages.Package, bundleID string, targets []targetInfo) (map[string]bool, error) { + src := pkg.PkgPath + if buildO != "" && !strings.HasSuffix(buildO, ".app") { + return nil, fmt.Errorf("-o must have an .app for -target=ios") + } + + productName := rfc1034Label(path.Base(pkg.PkgPath)) + if productName == "" { + productName = "ProductName" // like xcode. + } + + infoplist := new(bytes.Buffer) + if err := infoplistTmpl.Execute(infoplist, infoplistTmplData{ + BundleID: bundleID + "." + productName, + Name: strings.Title(path.Base(pkg.PkgPath)), + }); err != nil { + return nil, err + } + + // Detect the team ID + teamID, err := detectTeamID() + if err != nil { + return nil, err + } + + projPbxproj := new(bytes.Buffer) + if err := projPbxprojTmpl.Execute(projPbxproj, projPbxprojTmplData{ + TeamID: teamID, + }); err != nil { + return nil, err + } + + files := []struct { + name string + contents []byte + }{ + {tmpdir + "/main.xcodeproj/project.pbxproj", projPbxproj.Bytes()}, + {tmpdir + "/main/Info.plist", infoplist.Bytes()}, + {tmpdir + "/main/Images.xcassets/AppIcon.appiconset/Contents.json", []byte(contentsJSON)}, + } + + for _, file := range files { + if err := mkdir(filepath.Dir(file.name)); err != nil { + return nil, err + } + if buildX { + printcmd("echo \"%s\" > %s", file.contents, file.name) + } + if !buildN { + if err := ioutil.WriteFile(file.name, file.contents, 0644); err != nil { + return nil, err + } + } + } + + // We are using lipo tool to build multiarchitecture binaries. + cmd := exec.Command( + "xcrun", "lipo", + "-o", filepath.Join(tmpdir, "main/main"), + "-create", + ) + + var nmpkgs map[string]bool + builtArch := map[string]bool{} + for _, t := range targets { + // Only one binary per arch allowed + // e.g. ios/arm64 + iossimulator/amd64 + if builtArch[t.arch] { + continue + } + builtArch[t.arch] = true + + path := filepath.Join(tmpdir, t.platform, t.arch) + + // Disable DWARF; see golang.org/issues/25148. + if err := goBuild(src, appleEnv[t.String()], "-ldflags=-w", "-o="+path); err != nil { + return nil, err + } + if nmpkgs == nil { + var err error + nmpkgs, err = extractPkgs(appleNM, path) + if err != nil { + return nil, err + } + } + cmd.Args = append(cmd.Args, path) + + } + + if err := runCmd(cmd); err != nil { + return nil, err + } + + // TODO(jbd): Set the launcher icon. + if err := appleCopyAssets(pkg, tmpdir); err != nil { + return nil, err + } + + // Build and move the release build to the output directory. + cmdStrings := []string{ + "xcodebuild", + "-configuration", "Release", + "-project", tmpdir + "/main.xcodeproj", + "-allowProvisioningUpdates", + "DEVELOPMENT_TEAM=" + teamID, + } + + cmd = exec.Command("xcrun", cmdStrings...) + if err := runCmd(cmd); err != nil { + return nil, err + } + + // TODO(jbd): Fallback to copying if renaming fails. + if buildO == "" { + n := pkg.PkgPath + if n == "." { + // use cwd name + cwd, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("cannot create .app; cannot get the current working dir: %v", err) + } + n = cwd + } + n = path.Base(n) + buildO = n + ".app" + } + if buildX { + printcmd("mv %s %s", tmpdir+"/build/Release-iphoneos/main.app", buildO) + } + if !buildN { + // if output already exists, remove. + if err := os.RemoveAll(buildO); err != nil { + return nil, err + } + if err := os.Rename(tmpdir+"/build/Release-iphoneos/main.app", buildO); err != nil { + return nil, err + } + } + return nmpkgs, nil +} + +func detectTeamID() (string, error) { + // Grabs the first certificate for "Apple Development"; will not work if there + // are multiple certificates and the first is not desired. + cmd := exec.Command( + "security", "find-certificate", + "-c", "Apple Development", "-p", + ) + pemString, err := cmd.Output() + if err != nil { + err = fmt.Errorf("failed to pull the signing certificate to determine your team ID: %v", err) + return "", err + } + + block, _ := pem.Decode(pemString) + if block == nil { + err = fmt.Errorf("failed to decode the PEM to determine your team ID: %s", pemString) + return "", err + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + err = fmt.Errorf("failed to parse your signing certificate to determine your team ID: %v", err) + return "", err + } + + if len(cert.Subject.OrganizationalUnit) == 0 { + err = fmt.Errorf("the signing certificate has no organizational unit (team ID)") + return "", err + } + + return cert.Subject.OrganizationalUnit[0], nil +} + +func appleCopyAssets(pkg *packages.Package, xcodeProjDir string) error { + dstAssets := xcodeProjDir + "/main/assets" + if err := mkdir(dstAssets); err != nil { + return err + } + + // TODO(hajimehoshi): This works only with Go tools that assume all source files are in one directory. + // Fix this to work with other Go tools. + srcAssets := filepath.Join(filepath.Dir(pkg.GoFiles[0]), "assets") + fi, err := os.Stat(srcAssets) + if err != nil { + if os.IsNotExist(err) { + // skip walking through the directory to deep copy. + return nil + } + return err + } + if !fi.IsDir() { + // skip walking through to deep copy. + return nil + } + // if assets is a symlink, follow the symlink. + srcAssets, err = filepath.EvalSymlinks(srcAssets) + if err != nil { + return err + } + return filepath.Walk(srcAssets, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if name := filepath.Base(path); strings.HasPrefix(name, ".") { + // Do not include the hidden files. + return nil + } + if info.IsDir() { + return nil + } + dst := dstAssets + "/" + path[len(srcAssets)+1:] + return copyFile(dst, path) + }) +} + +type infoplistTmplData struct { + BundleID string + Name string +} + +var infoplistTmpl = template.Must(template.New("infoplist").Parse(` + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + main + CFBundleIdentifier + {{.BundleID}} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + {{.Name}} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + +`)) + +type projPbxprojTmplData struct { + TeamID string +} + +var projPbxprojTmpl = template.Must(template.New("projPbxproj").Parse(`// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 254BB84F1B1FD08900C56DE9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 254BB84E1B1FD08900C56DE9 /* Images.xcassets */; }; + 254BB8681B1FD16500C56DE9 /* main in Resources */ = {isa = PBXBuildFile; fileRef = 254BB8671B1FD16500C56DE9 /* main */; }; + 25FB30331B30FDEE0005924C /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 25FB30321B30FDEE0005924C /* assets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 254BB83E1B1FD08900C56DE9 /* main.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = main.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 254BB8421B1FD08900C56DE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 254BB84E1B1FD08900C56DE9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 254BB8671B1FD16500C56DE9 /* main */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = main; sourceTree = ""; }; + 25FB30321B30FDEE0005924C /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = assets; path = main/assets; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + 254BB8351B1FD08900C56DE9 = { + isa = PBXGroup; + children = ( + 25FB30321B30FDEE0005924C /* assets */, + 254BB8401B1FD08900C56DE9 /* main */, + 254BB83F1B1FD08900C56DE9 /* Products */, + ); + sourceTree = ""; + usesTabs = 0; + }; + 254BB83F1B1FD08900C56DE9 /* Products */ = { + isa = PBXGroup; + children = ( + 254BB83E1B1FD08900C56DE9 /* main.app */, + ); + name = Products; + sourceTree = ""; + }; + 254BB8401B1FD08900C56DE9 /* main */ = { + isa = PBXGroup; + children = ( + 254BB8671B1FD16500C56DE9 /* main */, + 254BB84E1B1FD08900C56DE9 /* Images.xcassets */, + 254BB8411B1FD08900C56DE9 /* Supporting Files */, + ); + path = main; + sourceTree = ""; + }; + 254BB8411B1FD08900C56DE9 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 254BB8421B1FD08900C56DE9 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 254BB83D1B1FD08900C56DE9 /* main */ = { + isa = PBXNativeTarget; + buildConfigurationList = 254BB8611B1FD08900C56DE9 /* Build configuration list for PBXNativeTarget "main" */; + buildPhases = ( + 254BB83C1B1FD08900C56DE9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = main; + productName = main; + productReference = 254BB83E1B1FD08900C56DE9 /* main.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 254BB8361B1FD08900C56DE9 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = Developer; + TargetAttributes = { + 254BB83D1B1FD08900C56DE9 = { + CreatedOnToolsVersion = 6.3.1; + DevelopmentTeam = {{.TeamID}}; + }; + }; + }; + buildConfigurationList = 254BB8391B1FD08900C56DE9 /* Build configuration list for PBXProject "main" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 254BB8351B1FD08900C56DE9; + productRefGroup = 254BB83F1B1FD08900C56DE9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 254BB83D1B1FD08900C56DE9 /* main */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 254BB83C1B1FD08900C56DE9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 25FB30331B30FDEE0005924C /* assets in Resources */, + 254BB8681B1FD16500C56DE9 /* main in Resources */, + 254BB84F1B1FD08900C56DE9 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 254BB8601B1FD08900C56DE9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + ENABLE_BITCODE = YES; + }; + name = Release; + }; + 254BB8631B1FD08900C56DE9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = main/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 254BB8391B1FD08900C56DE9 /* Build configuration list for PBXProject "main" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 254BB8601B1FD08900C56DE9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 254BB8611B1FD08900C56DE9 /* Build configuration list for PBXNativeTarget "main" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 254BB8631B1FD08900C56DE9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 254BB8361B1FD08900C56DE9 /* Project object */; +} +`)) + +const contentsJSON = `{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} +` + +// rfc1034Label sanitizes the name to be usable in a uniform type identifier. +// The sanitization is similar to xcode's rfc1034identifier macro that +// replaces illegal characters (not conforming the rfc1034 label rule) with '-'. +func rfc1034Label(name string) string { + // * Uniform type identifier: + // + // According to + // https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html + // + // A uniform type identifier is a Unicode string that usually contains characters + // in the ASCII character set. However, only a subset of the ASCII characters are + // permitted. You may use the Roman alphabet in upper and lower case (A–Z, a–z), + // the digits 0 through 9, the dot (“.”), and the hyphen (“-”). This restriction + // is based on DNS name restrictions, set forth in RFC 1035. + // + // Uniform type identifiers may also contain any of the Unicode characters greater + // than U+007F. + // + // Note: the actual implementation of xcode does not allow some unicode characters + // greater than U+007f. In this implementation, we just replace everything non + // alphanumeric with "-" like the rfc1034identifier macro. + // + // * RFC1034 Label + // + //