use crate::errors::{LimboError, Result}; use jni::objects::{JByteArray, JObject}; use jni::sys::{jint, jlong}; use jni::JNIEnv; use limbo_core::Database; use std::sync::Arc; const ERROR_CODE_ETC: i32 = 9999; #[no_mangle] #[allow(clippy::arc_with_non_send_sync)] pub extern "system" fn Java_org_github_tursodatabase_core_LimboDB_openUtf8<'local>( mut env: JNIEnv<'local>, obj: JObject<'local>, file_name_byte_arr: JByteArray<'local>, _open_flags: jint, ) -> jlong { let io = match limbo_core::PlatformIO::new() { Ok(io) => Arc::new(io), Err(e) => { set_err_msg_and_throw_exception(&mut env, obj, ERROR_CODE_ETC, e.to_string()); return -1; } }; let path = match env .convert_byte_array(file_name_byte_arr) .map_err(|e| e.to_string()) { Ok(bytes) => match String::from_utf8(bytes) { Ok(s) => s, Err(e) => { set_err_msg_and_throw_exception(&mut env, obj, ERROR_CODE_ETC, e.to_string()); return -1; } }, Err(e) => { set_err_msg_and_throw_exception(&mut env, obj, ERROR_CODE_ETC, e.to_string()); return -1; } }; let db = match Database::open_file(io.clone(), &path) { Ok(db) => db, Err(e) => { set_err_msg_and_throw_exception(&mut env, obj, ERROR_CODE_ETC, e.to_string()); return -1; } }; Box::into_raw(Box::new(db)) as jlong } #[no_mangle] pub extern "system" fn Java_org_github_tursodatabase_core_LimboDB_connect0<'local>( mut env: JNIEnv<'local>, obj: JObject<'local>, db_pointer: jlong, ) -> jlong { let db = match to_db(db_pointer) { Ok(db) => db, Err(e) => { set_err_msg_and_throw_exception(&mut env, obj, ERROR_CODE_ETC, e.to_string()); return 0; } }; Box::into_raw(Box::new(db.connect())) as jlong } fn to_db(db_pointer: jlong) -> Result<&'static mut Arc> { if db_pointer == 0 { Err(LimboError::InvalidDatabasePointer) } else { unsafe { Ok(&mut *(db_pointer as *mut Arc)) } } } #[no_mangle] pub extern "system" fn Java_org_github_tursodatabase_core_LimboDB_throwJavaException<'local>( mut env: JNIEnv<'local>, obj: JObject<'local>, error_code: jint, ) { set_err_msg_and_throw_exception( &mut env, obj, error_code, "throw java exception".to_string(), ); } fn utf8_byte_arr_to_str(env: &JNIEnv, bytes: JByteArray) -> Result { let bytes = env .convert_byte_array(bytes) .map_err(|e| LimboError::CustomError("Failed to retrieve bytes".to_string()))?; let str = String::from_utf8(bytes).map_err(|e| { LimboError::CustomError("Failed to convert utf8 byte array into string".to_string()) })?; Ok(str) } /// Sets the error message and throws a Java exception. /// /// This function converts the provided error message to a byte array and calls the /// `throwLimboException` method on the provided Java object to throw an exception. /// /// # Parameters /// - `env`: The JNI environment. /// - `obj`: The Java object on which the exception will be thrown. /// - `err_code`: The error code corresponding to the exception. Refer to `org.github.tursodatabase.core.Codes` for the list of error codes. /// - `err_msg`: The error message to be included in the exception. /// /// # Example /// ```rust /// set_err_msg_and_throw_exception(env, obj, Codes::SQLITE_ERROR, "An error occurred".to_string()); /// ``` fn set_err_msg_and_throw_exception<'local>( env: &mut JNIEnv<'local>, obj: JObject<'local>, err_code: i32, err_msg: String, ) { let error_message_bytes = env .byte_array_from_slice(err_msg.as_bytes()) .expect("Failed to convert to byte array"); match env.call_method( obj, "throwLimboException", "(I[B)V", &[err_code.into(), (&error_message_bytes).into()], ) { Ok(_) => { // do nothing because above method will always return Err } Err(_e) => { // do nothing because our java app will handle Err } } }