Skip to content

Commit

Permalink
Merge pull request #1641 from daira/simpler-rust_vec_to_java
Browse files Browse the repository at this point in the history
Simpler API for `rust_vec_to_java`
  • Loading branch information
str4d authored Nov 22, 2024
2 parents e9a822f + 7a19443 commit 3558ecf
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 58 deletions.
67 changes: 18 additions & 49 deletions backend-lib/src/main/rust/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,24 +348,12 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getAccoun
.filter(|account| matches!(account.source(), AccountSource::Derived { .. }))
.collect::<Vec<_>>();

let first_account = accounts.first().cloned();

Ok(utils::rust_vec_to_java(
env,
accounts,
JNI_ACCOUNT,
|env, account| encode_account(env, &network, account),
|env| {
// The array contains non-null values in Kotlin. This returns `null` if
// there are no accounts, which is fine because the array has no entries
// and thus the empty element is never used.
match first_account {
Some(account) => encode_account(env, &network, account),
None => Ok(JObject::null()),
}
},
)?
.into_raw())
Ok(
utils::rust_vec_to_java(env, accounts, JNI_ACCOUNT, |env, account| {
encode_account(env, &network, account)
})?
.into_raw(),
)
});
unwrap_exc_or(&mut env, res, ptr::null_mut())
}
Expand Down Expand Up @@ -1249,7 +1237,6 @@ fn encode_wallet_summary<'a, P: Parameters>(
.collect::<Result<_, _>>()?,
JNI_ACCOUNT_BALANCE,
|env, (account_index, balance)| encode_account_balance(env, &account_index, balance),
|env| encode_account_balance(env, &zip32::AccountId::ZERO, &AccountBalance::ZERO),
)?;

let (progress_numerator, progress_denominator) =
Expand Down Expand Up @@ -1349,12 +1336,6 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_suggestSc
ranges,
"cash/z/ecc/android/sdk/internal/model/JniScanRange",
|env, scan_range| encode_scan_range(env, scan_range),
|env| {
encode_scan_range(
env,
ScanRange::from_parts((0.into())..(0.into()), ScanPriority::Scanned),
)
},
)?
.into_raw())
});
Expand Down Expand Up @@ -1487,13 +1468,6 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_transacti
ranges,
"cash/z/ecc/android/sdk/internal/model/JniTransactionDataRequest",
|env, request| encode_transaction_data_request(env, net, request),
|env| {
encode_transaction_data_request(
env,
net,
TransactionDataRequest::GetStatus(TxId::from_bytes([0; 32])),
)
},
)?
.into_raw())
});
Expand Down Expand Up @@ -1895,14 +1869,12 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createPro
)
.map_err(|e| anyhow!("Error while creating transactions: {}", e))?;

Ok(utils::rust_vec_to_java(
env,
txids.into(),
"[B",
|env, txid| utils::rust_bytes_to_java(env, txid.as_ref()),
|env| env.new_byte_array(32),
)?
.into_raw())
Ok(
utils::rust_vec_to_java(env, txids.into(), "[B", |env, txid| {
utils::rust_bytes_to_java(env, txid.as_ref())
})?
.into_raw(),
)
});
unwrap_exc_or(&mut env, res, ptr::null_mut())
}
Expand Down Expand Up @@ -1994,14 +1966,12 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustDerivationTool_de
})
.collect::<Result<_, _>>()?;

Ok(utils::rust_vec_to_java(
env,
ufvks,
"java/lang/String",
|env, ufvk| env.new_string(ufvk),
|env| env.new_string(""),
)?
.into_raw())
Ok(
utils::rust_vec_to_java(env, ufvks, "java/lang/String", |env, ufvk| {
env.new_string(ufvk)
})?
.into_raw(),
)
});
unwrap_exc_or(&mut env, res, ptr::null_mut())
}
Expand Down Expand Up @@ -2298,7 +2268,6 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_listTrans
trasparent_receivers,
"java/lang/String",
|env, taddr| env.new_string(taddr),
|env| env.new_string(""),
)?
.into_raw())
}
Expand Down
35 changes: 26 additions & 9 deletions backend-lib/src/main/rust/utils.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use core::slice;
use std::convert::TryFrom;
use std::panic::{self, AssertUnwindSafe, UnwindSafe};
use std::thread;

use jni::{
descriptors::Desc,
errors::Result as JNIResult,
errors::{Error as JNIError, Result as JNIResult},
objects::{JByteArray, JClass, JObject, JObjectArray, JString},
sys::jsize,
JNIEnv,
Expand Down Expand Up @@ -51,26 +52,42 @@ pub(crate) fn rust_bytes_to_java<'a>(env: &JNIEnv<'a>, data: &[u8]) -> JNIResult
Ok(jret)
}

pub(crate) fn rust_vec_to_java<'a, T, U, V, F, G>(
pub(crate) fn rust_vec_to_java<'a, T, U, V, F>(
env: &mut JNIEnv<'a>,
data: Vec<T>,
element_class: U,
element_map: F,
empty_element: G,
) -> JNIResult<JObjectArray<'a>>
where
U: Desc<'a, JClass<'a>>,
V: Into<JObject<'a>>,
F: Fn(&mut JNIEnv<'a>, T) -> JNIResult<V>,
G: FnOnce(&mut JNIEnv<'a>) -> JNIResult<V>,
{
let jempty = empty_element(env)?;
let jret = env.new_object_array(data.len() as jsize, element_class, jempty.into())?;
for (i, elem) in data.into_iter().enumerate() {
let length = jsize::try_from(data.len())
// not quite the right error but close enough
.map_err(|_| JNIError::WrongJValueType("jsize", "usize"))?;
let mut iter = data.into_iter().enumerate();

if let Some((_, elem)) = iter.next() {
let jelem = element_map(env, elem)?;
env.set_object_array_element(&jret, i as jsize, jelem.into())?;
// All array entries, and in particular the one at index 0, are initialized to jelem.into().
let jret = env.new_object_array(length, element_class, jelem.into())?;

// All array entries after the first will be set.
for (i, elem) in iter {
let jelem = element_map(env, elem)?;
env.set_object_array_element(
&jret,
jsize::try_from(i).expect("i fits in jsize"),
jelem.into(),
)?;
}
Ok(jret)
} else {
// It is okay to use null for initial_element here even if the Kotlin type is non-nullable,
// because the array is empty.
Ok(env.new_object_array(0, element_class, JObject::null())?)
}
Ok(jret)
}

// // 2D array
Expand Down

0 comments on commit 3558ecf

Please sign in to comment.