alef 0.109.6

Opinionated polyglot binding generator for Rust libraries
Documentation
const JNI_COMPONENT_UNSUPPORTED: &str = "downloadable native components are unsupported by the Android-only JNI backend; v1 supports desktop Linux, macOS, and Windows hosts";

fn emit_unsupported_component_shims(out: &mut String, package: &str, bridge: &str) {
    let load = jni_symbol(package, bridge, "nativeComponentLoad");
    let prefetch = jni_symbol(package, bridge, "nativeComponentPrefetch");
    let status = jni_symbol(package, bridge, "nativeComponentStatus");
    let cache_path = jni_symbol(package, bridge, "nativeComponentCachePath");

    out.push_str(&format!(
        r#"
/// Android JNI does not load downloadable native executable components.
#[unsafe(no_mangle)]
pub unsafe extern "system" fn {load}(
    mut env: EnvUnowned,
    _class: JClass,
    _component: JString,
) {{
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut guard = unsafe {{ jni::AttachGuard::from_unowned(env.as_raw()) }};
    throw_jni_error(guard.borrow_env_mut(), "{message}");
}}

/// Android JNI does not prefetch downloadable native executable components.
#[unsafe(no_mangle)]
pub unsafe extern "system" fn {prefetch}(
    mut env: EnvUnowned,
    _class: JClass,
    _component: JString,
) -> jstring {{
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut guard = unsafe {{ jni::AttachGuard::from_unowned(env.as_raw()) }};
    throw_jni_error(guard.borrow_env_mut(), "{message}");
    std::ptr::null_mut()
}}

/// Android JNI does not report status for downloadable native executable components.
#[unsafe(no_mangle)]
pub unsafe extern "system" fn {status}(
    mut env: EnvUnowned,
    _class: JClass,
    _component: JString,
) -> jstring {{
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut guard = unsafe {{ jni::AttachGuard::from_unowned(env.as_raw()) }};
    throw_jni_error(guard.borrow_env_mut(), "{message}");
    std::ptr::null_mut()
}}

/// Android JNI does not expose cache paths for downloadable native executable components.
#[unsafe(no_mangle)]
pub unsafe extern "system" fn {cache_path}(
    mut env: EnvUnowned,
    _class: JClass,
    _component: JString,
) -> jstring {{
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut guard = unsafe {{ jni::AttachGuard::from_unowned(env.as_raw()) }};
    throw_jni_error(guard.borrow_env_mut(), "{message}");
    std::ptr::null_mut()
}}
"#,
        message = JNI_COMPONENT_UNSUPPORTED,
    ));
}

#[cfg(test)]
mod component_tests {
    use super::*;

    #[test]
    fn jni_emits_explicit_android_unsupported_component_surface() {
        let mut generated = String::new();
        emit_unsupported_component_shims(&mut generated, "dev.demo", "DemoBridge");
        assert!(generated.contains("Java_dev_demo_DemoBridge_nativeComponentLoad"));
        assert!(generated.contains("Java_dev_demo_DemoBridge_nativeComponentPrefetch"));
        assert!(generated.contains("Java_dev_demo_DemoBridge_nativeComponentStatus"));
        assert!(generated.contains("Java_dev_demo_DemoBridge_nativeComponentCachePath"));
        assert!(generated.contains("Android-only JNI backend"));
    }
}