use heck::ToUpperCamelCase;
pub fn bridge_class_name(crate_name: &str) -> String {
format!("{}Bridge", crate_name.to_upper_camel_case())
}
pub fn bridge_method_name(owner: &str, method: &str) -> String {
let owner_pascal = owner.to_upper_camel_case();
let method_pascal = method.to_upper_camel_case();
if owner_pascal.is_empty() {
format!("native{method_pascal}")
} else {
format!("native{owner_pascal}{method_pascal}")
}
}
pub fn streaming_method_names(owner: &str, method: &str) -> (String, String, String) {
let owner_pascal = owner.to_upper_camel_case();
let method_pascal = method.to_upper_camel_case();
(
format!("native{owner_pascal}{method_pascal}Start"),
format!("native{owner_pascal}{method_pascal}Next"),
format!("native{owner_pascal}{method_pascal}Free"),
)
}
pub fn destructor_method_name(owner: &str) -> String {
let owner_pascal = owner.to_upper_camel_case();
format!("nativeFree{owner_pascal}")
}
pub fn jni_symbol(package: &str, class: &str, method: &str) -> String {
let encode = |s: &str| s.replace('_', "_1").replace('.', "_");
let pkg_encoded = encode(package);
let class_encoded = encode(class);
if method.is_empty() {
format!("Java_{pkg_encoded}_{class_encoded}")
} else {
let method_encoded = encode(method);
format!("Java_{pkg_encoded}_{class_encoded}_{method_encoded}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bridge_class_name_basic() {
assert_eq!(bridge_class_name("demo"), "DemoBridge");
assert_eq!(bridge_class_name("my-lib"), "MyLibBridge");
assert_eq!(bridge_class_name("my_lib"), "MyLibBridge");
}
#[test]
fn bridge_method_name_with_owner() {
assert_eq!(bridge_method_name("DemoClient", "foo"), "nativeDemoClientFoo");
assert_eq!(bridge_method_name("demo_client", "bar_baz"), "nativeDemoClientBarBaz");
}
#[test]
fn bridge_method_name_no_owner() {
assert_eq!(bridge_method_name("", "createClient"), "nativeCreateClient");
assert_eq!(bridge_method_name("", "create_client"), "nativeCreateClient");
}
#[test]
fn streaming_method_names_basic() {
let (s, n, f) = streaming_method_names("DemoClient", "streamData");
assert_eq!(s, "nativeDemoClientStreamDataStart");
assert_eq!(n, "nativeDemoClientStreamDataNext");
assert_eq!(f, "nativeDemoClientStreamDataFree");
}
#[test]
fn destructor_method_name_basic() {
assert_eq!(destructor_method_name("DemoClient"), "nativeFreeDemoClient");
assert_eq!(destructor_method_name("demo_client"), "nativeFreeDemoClient");
}
#[test]
fn jni_symbol_basic() {
let sym = jni_symbol("dev.kreuzberg.demo", "DemoBridge", "nativeFoo");
assert_eq!(sym, "Java_dev_kreuzberg_demo_DemoBridge_nativeFoo");
}
#[test]
fn jni_symbol_underscore_in_class_encoded() {
let sym = jni_symbol("dev.demo", "Demo_Bridge", "nativeBar");
assert_eq!(sym, "Java_dev_demo_Demo_1Bridge_nativeBar");
}
#[test]
fn jni_symbol_empty_method_gives_prefix() {
let prefix = jni_symbol("dev.kreuzberg.demo", "DemoBridge", "");
assert_eq!(prefix, "Java_dev_kreuzberg_demo_DemoBridge");
}
}