---
source: tests/backends_jni_gen_shims_test.rs
expression: content
---
// Generated by alef. Do not edit by hand.
//
// JNI shim for the Android AAR.  Every `pub unsafe extern "system" fn`
// here matches one `external fun native*` in the paired Kotlin Bridge object.

#![allow(non_snake_case)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::missing_safety_doc)]
#![allow(unused_imports)]
#![allow(unused_variables)]
#![allow(unused_mut)]
#![allow(dead_code)]
#![allow(clippy::let_unit_value)]
#![allow(clippy::unused_unit)]
#![allow(clippy::let_and_return)]
#![allow(missing_docs)]

use std::sync::OnceLock;
use std::sync::Mutex;
use futures_util::stream::BoxStream;
use futures_util::StreamExt;
use jni::{AttachGuard, Env, EnvUnowned};
use jni::objects::{JClass, JObject, JString};
use jni::sys::{jboolean, jbyteArray, jlong, jstring};
use tokio::runtime::Runtime;

use demo as core_crate;
use core_crate::*; // bring trait methods into scope

const ERROR_CLASS: &str = "dev/sample_crate/demo/DemoBridgeException";
fn runtime() -> &'static Runtime {
    static RT: OnceLock<Runtime> = OnceLock::new();
    RT.get_or_init(|| Runtime::new().expect("create tokio runtime"))
}

fn jstring_to_string(env: &mut Env<'_>, s: JString) -> std::result::Result<String, jni::errors::Error> {
    s.try_to_string(env)
}

fn string_to_jstring(env: &mut Env<'_>, s: impl AsRef<str>) -> jstring {
    match env.new_string(s.as_ref()) {
        Ok(o) => o.into_raw(),
        Err(_) => std::ptr::null_mut(),
    }
}

fn jni_call_string_method(env: &mut Env<'_>, obj: JObject, method_name: &str, method_sig: &str) -> std::result::Result<String, jni::errors::Error> {
    use std::str::FromStr;
    let class = env.get_object_class(&obj)?;
    let name_jni = jni::strings::JNIString::from(method_name);
    let sig_runtime = jni::signature::RuntimeMethodSignature::from_str(method_sig)?;
    let sig = sig_runtime.method_signature();
    let method_id = env.get_method_id(&class, name_jni, sig)?;
    // SAFETY: method_id is valid from the preceding get_method_id call, and the method exists on the class.
    let result = unsafe { env.call_method_unchecked(&obj, method_id, jni::signature::ReturnType::Object, &[])? }
        .l()?;
    // SAFETY: JNI return type guaranteed a String, so the raw jstring pointer is valid.
    let jstring = unsafe { JString::from_raw(env, result.into_raw()) };
    jstring_to_string(env, jstring)
}

fn throw_jni_error(env: &mut Env<'_>, msg: &str) {
    // If the error class cannot be found (misconfigured AAR), fall back to a
    // generic RuntimeException so the caller always gets *some* exception rather
    // than a silent null/zero return that looks like a valid result.
    let class_jni = jni::strings::JNIString::from(ERROR_CLASS);
    let msg_jni = jni::strings::JNIString::from(msg);
    if env.throw_new(&class_jni, &msg_jni).is_err() {
        let fallback = jni::strings::JNIString::from("java/lang/RuntimeException");
        let _ = env.throw_new(&fallback, &msg_jni);
    }
}

fn run_or_throw<T, F>(env: &mut Env<'_>, f: F) -> Option<T>
where
    F: FnOnce() -> T + std::panic::UnwindSafe,
{
    match std::panic::catch_unwind(f) {
        Ok(v) => Some(v),
        Err(payload) => {
            let msg = payload.downcast_ref::<String>().cloned()
                .or_else(|| payload.downcast_ref::<&str>().map(|s| (*s).to_string()))
                .unwrap_or_else(|| "panic in native code".to_string());
            throw_jni_error(env, &format!("native panic: {msg}"));
            None
        }
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_dev_sample_1crate_demo_DemoBridge_nativeCreateClient(
    mut env: EnvUnowned,
    _class: JClass,
    api_key: JString,
) -> jlong {
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut __jni_attach_guard = unsafe { jni::AttachGuard::from_unowned(env.as_raw()) };
    let env = __jni_attach_guard.borrow_env_mut();
    let api_key = match jstring_to_string(env, api_key) {
        Ok(s) => s,
        Err(e) => { throw_jni_error(env, &format!("{e}")); return 0; }
    };
    let Some(result) = run_or_throw(env, std::panic::AssertUnwindSafe(|| runtime().block_on(core_crate::create_client(api_key)))) else {
        return 0;
    };
    match result {
        Err(e) => {
            throw_jni_error(env, &format!("{e}"));
            0
        }
        Ok(v) => {
            Box::into_raw(Box::new(v)) as jlong
        }
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_dev_sample_1crate_demo_DemoBridge_nativeDemoClientDoThing(
    mut env: EnvUnowned,
    _class: JClass,
    handle: jlong,
    request_json: JString,
) -> jstring {
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut __jni_attach_guard = unsafe { jni::AttachGuard::from_unowned(env.as_raw()) };
    let env = __jni_attach_guard.borrow_env_mut();
    // SAFETY: handle was allocated by the matching constructor shim and remains
    // valid until nativeFree is called. The Kotlin AutoCloseable.close() guarantee
    // ensures the handle outlives this call.
    let client: &core_crate::DemoClient = unsafe { &*(handle as *const core_crate::DemoClient) };
    let req_str = match jstring_to_string(env, request_json) {
        Ok(s) => s,
        Err(e) => { throw_jni_error(env, &format!("{e}")); return std::ptr::null_mut(); }
    };
    let input: String = match serde_json::from_str(&req_str) {
        Ok(s) => s,
        Err(_) => req_str,
    };
    let Some(v) = run_or_throw(env, std::panic::AssertUnwindSafe(|| runtime().block_on(client.do_thing(input)))) else {
        return std::ptr::null_mut();
    };
    string_to_jstring(env, v)
}
#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_dev_sample_1crate_demo_DemoBridge_nativeDemoClientPing(
    mut env: EnvUnowned,
    _class: JClass,
    handle: jlong,
) -> jboolean {
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut __jni_attach_guard = unsafe { jni::AttachGuard::from_unowned(env.as_raw()) };
    let env = __jni_attach_guard.borrow_env_mut();
    // SAFETY: handle was allocated by the matching constructor shim and remains
    // valid until nativeFree is called. The Kotlin AutoCloseable.close() guarantee
    // ensures the handle outlives this call.
    let client: &core_crate::DemoClient = unsafe { &*(handle as *const core_crate::DemoClient) };
    let Some(v) = run_or_throw(env, std::panic::AssertUnwindSafe(|| runtime().block_on(client.ping()))) else {
        return false;
    };
    v
}
#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_dev_sample_1crate_demo_DemoBridge_nativeDemoClientFetchBlob(
    mut env: EnvUnowned,
    _class: JClass,
    handle: jlong,
) -> jbyteArray {
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut __jni_attach_guard = unsafe { jni::AttachGuard::from_unowned(env.as_raw()) };
    let env = __jni_attach_guard.borrow_env_mut();
    // SAFETY: handle was allocated by the matching constructor shim and remains
    // valid until nativeFree is called. The Kotlin AutoCloseable.close() guarantee
    // ensures the handle outlives this call.
    let client: &core_crate::DemoClient = unsafe { &*(handle as *const core_crate::DemoClient) };
    let Some(v) = run_or_throw(env, std::panic::AssertUnwindSafe(|| runtime().block_on(client.fetch_blob()))) else {
        return std::ptr::null_mut();
    };
    match env.byte_array_from_slice(&v) {
        Ok(arr) => { use jni::objects::JObject; JObject::from(arr).into_raw() as jbyteArray }
        Err(_) => std::ptr::null_mut(),
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_dev_sample_1crate_demo_DemoBridge_nativeFreeDemoClient(
    _env: EnvUnowned,
    _class: JClass,
    handle: jlong,
) {
    if handle == 0 { return; }
    // SAFETY: `handle` was allocated by the matching constructor shim and
    // ownership is transferred back here for drop via Box::from_raw.
    unsafe { let _ = Box::from_raw(handle as *mut core_crate::DemoClient); }
}
type DemoClientStreamDataStreamHandleItem = std::result::Result<core_crate::DataChunk, Box<dyn std::error::Error + Send + Sync + 'static>>;
type DemoClientStreamDataStreamHandleStream = BoxStream<'static, DemoClientStreamDataStreamHandleItem>;

struct DemoClientStreamDataStreamHandle {
    rt: &'static Runtime,
    stream: Mutex<Option<DemoClientStreamDataStreamHandleStream>>,
}

#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_dev_sample_1crate_demo_DemoBridge_nativeDemoClientStreamDataStart(
    mut env: EnvUnowned,
    _class: JClass,
    client_handle: jlong,
    request_json: JString,
) -> jlong {
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut __jni_attach_guard = unsafe { jni::AttachGuard::from_unowned(env.as_raw()) };
    let env = __jni_attach_guard.borrow_env_mut();
    // SAFETY: client_handle was produced by the matching constructor shim.
    let client: &core_crate::DemoClient = unsafe { &*(client_handle as *const core_crate::DemoClient) };
    let req_str = match jstring_to_string(env, request_json) {
        Ok(s) => s,
        Err(e) => { throw_jni_error(env, &format!("{e}")); return 0; }
    };
    let request: core_crate::StreamRequest = match serde_json::from_str(&req_str) {
        Ok(v) => v,
        Err(e) => { throw_jni_error(env, &format!("{e}")); return 0; }
    };
    let Some(stream_result) = run_or_throw(env, std::panic::AssertUnwindSafe(|| runtime().block_on(async { client.stream_data(request).await }))) else {
        return 0;
    };
    let stream = match stream_result {
        Ok(s) => s,
        Err(e) => { throw_jni_error(env, &format!("{e}")); return 0; }
    };
    // Map the concrete error type to Box<dyn Error> so the handle type is
    // independent of the stream's error associated type.
    let mapped = {
        use futures_util::StreamExt;
        Box::pin(stream.map(|r| r.map_err(|e| -> Box<dyn std::error::Error + Send + Sync + 'static> { Box::new(e) })))
    };
    let handle = Box::new(DemoClientStreamDataStreamHandle {
        rt: runtime(),
        stream: Mutex::new(Some(mapped)),
    });
    Box::into_raw(handle) as jlong
}

#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_dev_sample_1crate_demo_DemoBridge_nativeDemoClientStreamDataNext(
    mut env: EnvUnowned,
    _class: JClass,
    stream_handle: jlong,
) -> jstring {
    // SAFETY: env is a valid EnvUnowned passed by the JVM for this native call frame.
    let mut __jni_attach_guard = unsafe { jni::AttachGuard::from_unowned(env.as_raw()) };
    let env = __jni_attach_guard.borrow_env_mut();
    if stream_handle == 0 { return std::ptr::null_mut(); }
    // SAFETY: stream_handle was produced by the matching Start shim.
    let h = unsafe { &*(stream_handle as *const DemoClientStreamDataStreamHandle) };
    let mut guard = match h.stream.lock() {
        Ok(g) => g,
        Err(_) => return std::ptr::null_mut(),
    };
    let Some(stream) = guard.as_mut() else { return std::ptr::null_mut(); };
    let Some(next) = run_or_throw(env, std::panic::AssertUnwindSafe(|| h.rt.block_on(stream.next()))) else {
        return std::ptr::null_mut();
    };
    match next {
        None => std::ptr::null_mut(),
        Some(Err(e)) => {
            throw_jni_error(env, &format!("{e}"));
            std::ptr::null_mut()
        }
        Some(Ok(chunk)) => {
            let s = match serde_json::to_string(&chunk) {
                Ok(s) => s,
                Err(e) => {
                    throw_jni_error(env, &format!("serialize: {e}")); return std::ptr::null_mut();
                }
            };
            string_to_jstring(env, &s)
        }
    }
}

#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_dev_sample_1crate_demo_DemoBridge_nativeDemoClientStreamDataFree(
    _env: EnvUnowned,
    _class: JClass,
    stream_handle: jlong,
) {
    if stream_handle == 0 { return; }
    // SAFETY: stream_handle was produced by the matching Start shim.
    unsafe { let _ = Box::from_raw(stream_handle as *mut DemoClientStreamDataStreamHandle); }
}
