fn escape(component: &str) -> String {
let mut out = String::with_capacity(component.len());
for c in component.chars() {
match c {
'A'..='Z' | 'a'..='z' | '0'..='9' => out.push(c),
'/' => out.push('_'),
'_' => out.push_str("_1"),
';' => out.push_str("_2"),
'[' => out.push_str("_3"),
other => {
let mut units = [0u16; 2];
for unit in other.encode_utf16(&mut units) {
out.push_str(&format!("_0{unit:04x}"));
}
}
}
}
out
}
pub(crate) fn native_symbol(package: &str, class: &str, method: &str) -> String {
let mut out = String::from("Java");
if !package.is_empty() {
for segment in package.split('.') {
out.push('_');
out.push_str(&escape(segment));
}
}
out.push('_');
out.push_str(&escape(class));
out.push('_');
out.push_str(&escape(method));
out
}
#[allow(dead_code)]
pub(crate) fn native_symbol_overloaded(
package: &str,
class: &str,
method: &str,
arg_sig: &str,
) -> String {
format!(
"{}__{}",
native_symbol(package, class, method),
escape(arg_sig)
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn javac_golden_underscores() {
assert_eq!(
native_symbol("io.example.my_pkg", "Native_Harness", "do_work"),
"Java_io_example_my_1pkg_Native_1Harness_do_1work"
);
}
#[test]
fn javac_golden_unicode() {
assert_eq!(
native_symbol("io.example.my_pkg", "Native_Harness", "café"),
"Java_io_example_my_1pkg_Native_1Harness_caf_000e9"
);
}
#[test]
fn javac_golden_overloaded_long_names() {
assert_eq!(
native_symbol_overloaded("io.example.my_pkg", "Native_Harness", "g", "I"),
"Java_io_example_my_1pkg_Native_1Harness_g__I"
);
assert_eq!(
native_symbol_overloaded(
"io.example.my_pkg",
"Native_Harness",
"g",
"Ljava/lang/String;[I"
),
"Java_io_example_my_1pkg_Native_1Harness_g__Ljava_lang_String_2_3I"
);
}
#[test]
fn identity_on_escape_free_names() {
assert_eq!(
native_symbol("io.prebindgen.covertest", "CovNative", "storageSummary"),
"Java_io_prebindgen_covertest_CovNative_storageSummary"
);
}
#[test]
fn empty_package() {
assert_eq!(
native_symbol("", "Native_Harness", "do_work"),
"Java_Native_1Harness_do_1work"
);
}
#[test]
fn supplementary_plane_escapes_per_utf16_unit() {
assert_eq!(escape("𐐀"), "_0d801_0dc00");
}
}