blob: 4ea676c7d3c5fb7af0553042c23a3bcffeed7c76 [file] [log] [blame]
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use jni::{
descriptors::Desc,
objects::{AutoLocal, JClass, JObject, JObjectArray},
JNIEnv,
};
/// Collects an iterator of `I`, calling `item_into_jobject` on each element and collecting them
/// into a `JObjectArray`.
pub(crate) fn collect_to_jarray<'local, I, O>(
env: &mut JNIEnv<'local>,
element_class: impl Desc<'local, JClass<'local>>,
iter: impl ExactSizeIterator<Item = I>,
item_into_jobject: impl Fn(
&mut JNIEnv<'local>,
I,
) -> Result<AutoLocal<'local, O>, jni::errors::Error>,
) -> Result<JObjectArray<'local>, jni::errors::Error>
where
O: Into<JObject<'local>> + AsRef<JObject<'local>>,
{
let arr = env.new_object_array(
iter.len()
.try_into()
.expect("Array length should be convertible to i32"),
element_class,
JObject::default(),
)?;
for (i, item) in iter.enumerate() {
let item = item_into_jobject(env, item)?;
env.set_object_array_element(
&arr,
i.try_into()
.expect("Array index should be convertible to i32"),
item,
)?;
}
Ok(arr)
}
/// Define a handle suitable for JNI use.
///
/// In addition to declaring [handle_map::declare_handle_map!], this also generates conversions to
/// and from `jlong` for use with JNI. The handle can be converted to `jlong` using
/// `fooHandle.jlong()`. A `jlong` value can be converted back to `handle` using [`TryFrom`].
///
/// # Example
/// ```no_run
/// declare_handle! {
/// pub struct FooHandle for Foo;
/// }
/// ```
macro_rules! declare_handle {
( pub struct $handlename:ident for $target:ty; ) => {
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct $handlename {
pub(crate) handle_id: u64,
}
impl $handlename {
pub fn jlong(&self) -> jlong {
self.handle_id
.try_into()
.expect("Handle ID can't be larger than max_active_handles(131072)")
}
}
::handle_map::declare_handle_map!(
::handle_map::HandleMapDimensions {
num_shards: 4,
max_active_handles: 131072
},
$handlename,
$target
);
impl TryFrom<jlong> for $handlename {
type Error = ::handle_map::HandleNotPresentError;
fn try_from(value: jlong) -> Result<Self, Self::Error> {
Ok(Self {
handle_id: u64::try_from(value)
.map_err(|_| ::handle_map::HandleNotPresentError)?,
})
}
}
};
}
pub(crate) use declare_handle;