├── .gitattributes ├── .gitignore ├── .editorconfig ├── kotlin ├── Rust.kt └── Main.kt ├── Cargo.toml ├── Makefile ├── src └── lib.rs ├── README.md ├── LICENSE.txt └── Cargo.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | *.rs.bk 3 | *.jar 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | indent_style = space 11 | indent_size = 4 12 | -------------------------------------------------------------------------------- /kotlin/Rust.kt: -------------------------------------------------------------------------------- 1 | /** This file is used as a namespace for all the exported Rust functions. */ 2 | @file:JvmName("RustLibrary") 3 | 4 | /** Sorts a string's letters in lexicographic order. */ 5 | external fun sortLetters(str: String): String; 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kotlin-example" 3 | version = "0.1.0" 4 | authors = ["Gabriel Majeri "] 5 | 6 | [lib] 7 | name = "rust_kotlin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | jni = "0.8" 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Rust build type. 2 | config := release 3 | 4 | # The name of the shared library. 5 | lib_name := librust_jni.so 6 | 7 | # The name of the JAR file. 8 | jar_name := KotlinRust.jar 9 | 10 | # The path of the shared library 11 | lib_path := target/$(config)/$(lib_name) 12 | # The path of the JAR file. 13 | jar_path := $(jar_name) 14 | 15 | # Extract the directory with the native library. 16 | lib_dir := $(dir $(lib_path)) 17 | 18 | # Kotlin source files. 19 | kotlin_srcs := kotlin/Main.kt kotlin/Rust.kt 20 | 21 | .PHONY: run 22 | 23 | run: $(lib_path) $(jar_path) 24 | java -Djava.library.path=$(lib_dir) -jar $(jar_path) 25 | 26 | $(lib_path): src/lib.rs 27 | cargo build --release 28 | 29 | $(jar_path): $(kotlin_srcs) 30 | kotlinc $(kotlin_srcs) -include-runtime -d $(jar_path) 31 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate jni; 2 | use jni::JNIEnv; 3 | use jni::objects::{JClass, JString}; 4 | use jni::sys::jstring; 5 | 6 | fn sort_string(string: &str) -> String { 7 | let mut chars: Vec<_> = string.chars().collect(); 8 | 9 | chars.sort_unstable(); 10 | 11 | let sorted: String = chars.iter().collect(); 12 | 13 | sorted 14 | } 15 | 16 | #[allow(non_snake_case)] 17 | #[no_mangle] 18 | pub extern "system" fn Java_RustLibrary_sortLetters( 19 | // Java environment. 20 | env: JNIEnv, 21 | // Static class which owns this method. 22 | _class: JClass, 23 | // The string which must be sorted 24 | input: JString, 25 | ) -> jstring { 26 | let input: String = env.get_string(input).unwrap().into(); 27 | 28 | let result = sort_string(&input); 29 | 30 | let output = env.new_string(result).unwrap(); 31 | 32 | output.into_inner() 33 | } 34 | -------------------------------------------------------------------------------- /kotlin/Main.kt: -------------------------------------------------------------------------------- 1 | import kotlin.system.measureNanoTime 2 | 3 | fun sortString(input: String): String = input.chars().sorted().toString() 4 | 5 | fun main(args: Array) { 6 | System.loadLibrary("rust_kotlin") 7 | 8 | val str = "Kotlin <3 Rust" 9 | 10 | // How many times to run the micro-benchmark 11 | val times = 2048 12 | 13 | var rustTotal = 0L 14 | var kotlinTotal = 0L 15 | 16 | var count = 0 17 | 18 | for (i in 0..times) { 19 | var sortedRust: String = "" 20 | var sortedKotlin: String = "" 21 | 22 | val rustTime = measureNanoTime { 23 | sortedRust = sortLetters(str) 24 | } 25 | 26 | val kotlinTime = measureNanoTime { 27 | sortedKotlin = sortString(str) 28 | } 29 | 30 | assert(sortedRust == sortedKotlin) 31 | 32 | rustTotal += rustTime 33 | kotlinTotal += kotlinTime 34 | 35 | count += 1 36 | } 37 | 38 | val rustAvg = rustTotal / count 39 | val kotlinAvg = kotlinTotal / count 40 | 41 | println("Rust time: ${rustAvg} ns") 42 | println("Kotlin time: ${kotlinAvg} ns") 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kotlin - Rust interop 2 | This repository contains some sample code for using Rust together with Kotlin. 3 | 4 | ## Contents 5 | The app runs a simple micro-benchmark between Kotlin and Rust. 6 | It consists of sorting a random string lexicographically. 7 | 8 | Both the Kotlin and Rust implementation are using functional-programming, 9 | with Kotlin using [streams][streams] and Rust using [iterators][iter]. 10 | 11 | [streams]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.streams/index.html 12 | [iter]: https://doc.rust-lang.org/std/iter/ 13 | 14 | ## Dependencies 15 | You will need: 16 | - a Java runtime (such as Oracle's JRE on Windows or OpenJDK on Linux) 17 | - [Kotlin](https://github.com/JetBrains/kotlin) 18 | - [Rust](https://www.rust-lang.org) 19 | - GNU [Make](https://www.gnu.org/software/make/) 20 | 21 | ## Building / Running 22 | Just run `make`. 23 | 24 | ## Results 25 | Rust is consistently 3-5 times faster than the equivalent Kotlin code. 26 | 27 | ## Support libraries 28 | The [jni-rs](https://github.com/prevoty/jni-rs) crate is used in Rust to access JVM types, 29 | and a simple Kotlin app loads and runs the Rust code. 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "ascii" 3 | version = "0.7.1" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | 6 | [[package]] 7 | name = "backtrace" 8 | version = "0.3.4" 9 | source = "registry+https://github.com/rust-lang/crates.io-index" 10 | dependencies = [ 11 | "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 12 | "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 13 | "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 14 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 15 | "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", 16 | "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 18 | ] 19 | 20 | [[package]] 21 | name = "backtrace-sys" 22 | version = "0.1.16" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | dependencies = [ 25 | "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", 27 | ] 28 | 29 | [[package]] 30 | name = "byteorder" 31 | version = "1.2.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | 34 | [[package]] 35 | name = "cc" 36 | version = "1.0.3" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | 39 | [[package]] 40 | name = "cesu8" 41 | version = "1.1.0" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | 44 | [[package]] 45 | name = "cfg-if" 46 | version = "0.1.2" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | 49 | [[package]] 50 | name = "combine" 51 | version = "2.5.2" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | dependencies = [ 54 | "ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 55 | "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 56 | ] 57 | 58 | [[package]] 59 | name = "dbghelp-sys" 60 | version = "0.2.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | dependencies = [ 63 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 65 | ] 66 | 67 | [[package]] 68 | name = "error-chain" 69 | version = "0.11.0" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | dependencies = [ 72 | "backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 73 | ] 74 | 75 | [[package]] 76 | name = "jni" 77 | version = "0.8.1" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | dependencies = [ 80 | "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 81 | "combine 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 82 | "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 83 | "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 84 | "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", 85 | ] 86 | 87 | [[package]] 88 | name = "jni-sys" 89 | version = "0.3.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | 92 | [[package]] 93 | name = "kernel32-sys" 94 | version = "0.2.2" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | dependencies = [ 97 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 98 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 99 | ] 100 | 101 | [[package]] 102 | name = "kotlin-example" 103 | version = "0.1.0" 104 | dependencies = [ 105 | "jni 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 106 | ] 107 | 108 | [[package]] 109 | name = "libc" 110 | version = "0.2.34" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | 113 | [[package]] 114 | name = "log" 115 | version = "0.3.9" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | dependencies = [ 118 | "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 119 | ] 120 | 121 | [[package]] 122 | name = "log" 123 | version = "0.4.1" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | dependencies = [ 126 | "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 127 | ] 128 | 129 | [[package]] 130 | name = "rustc-demangle" 131 | version = "0.1.5" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | 134 | [[package]] 135 | name = "winapi" 136 | version = "0.2.8" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | 139 | [[package]] 140 | name = "winapi-build" 141 | version = "0.1.1" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | 144 | [metadata] 145 | "checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" 146 | "checksum backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8709cc7ec06f6f0ae6c2c7e12f6ed41540781f72b488d83734978295ceae182e" 147 | "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" 148 | "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" 149 | "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" 150 | "checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" 151 | "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" 152 | "checksum combine 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1645a65a99c7c8d345761f4b75a6ffe5be3b3b27a93ee731fccc5050ba6be97c" 153 | "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" 154 | "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" 155 | "checksum jni 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3209fc0e2ab37d6ba955b76000a2f6cfeee172cb562274d8db161beba1a21b16" 156 | "checksum jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" 157 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 158 | "checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" 159 | "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" 160 | "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" 161 | "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" 162 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 163 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 164 | --------------------------------------------------------------------------------