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 .whMath.is_prime(7) and Math.isPrime(7) both compile to Math.isPrime(7) — so Rust code can keep reading like Rust.

NativeFrom .wh
src/ffi/rust/math.rs$ffi.rust.Math
src/ffi/cpp/string_utils.cpp$ffi.cpp.StringUtils
fn is_primeisPrime

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