Documentation
FFI
Rust and C++ in src/ffi/, callable from .wh as ordinary objects. No
JNI, no header files, no CMakeLists.txt.
Rust
Mark a function with #[ffi] and it becomes callable:
// src/ffi/rust/lib.rs
use whitehall::ffi;
#[ffi]
pub fn add(a: i32, b: i32) -> i32 { a + b }
#[ffi]
pub fn is_prime(n: i64) -> bool { … } import $ffi.rust.Math
<Text>{Math.add(5, 3)}</Text> C++
An // @ffi comment does the same job:
// src/ffi/cpp/string_utils.cpp
// @ffi
std::string to_uppercase(const std::string& str) { … } import $ffi.cpp.StringUtils
<Text>{StringUtils.toUppercase("hello")}</Text> Naming
The file becomes the object and functions become camelCase. You can write either spelling in .wh — Math.is_prime(7) and Math.isPrime(7) both compile
to Math.isPrime(7) — so Rust code can keep reading like Rust.
| Native | From .wh |
|---|---|
src/ffi/rust/math.rs | $ffi.rust.Math |
src/ffi/cpp/string_utils.cpp | $ffi.cpp.StringUtils |
fn is_prime | isPrime |
Types that cross
int, long, float, double, bool, String, Vec<T>, and Vec<u8> which arrives as a Kotlin ByteArray.
Anything crossing the boundary is copied, not shared. Passing a large
Vec<u8> back and forth in a loop will cost more than the native code saves — move the loop into the
native side instead.Shipping a binary
A Rust bin crate is packaged into the APK but is not reachable through $ffi, because it is a process rather than a library. Use it for a daemon or a
tool you launch; use #[ffi] for anything you call.
See Also
- Project Structure — where
src/ffi/sits - Coroutines — keeping slow native calls off the main thread