Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1,264 @@
use log::error;
use std::ptr::NonNull;
use crate::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
use crate::wrapper::objects::ReleaseMode;
use crate::{errors::*, sys, JNIEnv};
use super::JPrimitiveArray;
#[cfg(doc)]
use super::JByteArray;
mod type_array_sealed {
use crate::sys::{jarray, jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
use crate::{errors::*, JNIEnv};
use std::ptr::NonNull;
/// Trait to define type array access/release
///
/// # Safety
///
/// The methods of this trait must uphold the invariants described in [`JNIEnv::unsafe_clone`] when
/// using the provided [`JNIEnv`].
///
/// The `get` method must return a valid pointer to the beginning of the JNI array.
///
/// The `release` method must not invalidate the `ptr` if the `mode` is [`sys::JNI_COMMIT`].
pub unsafe trait TypeArraySealed: Copy {
/// getter
///
/// # Safety
///
/// `array` must be a valid pointer to an `Array` object, or `null`
///
/// The caller is responsible for passing the returned pointer to [`release`], along
/// with the same `env` and `array` reference (which needs to still be valid)
unsafe fn get(env: &mut JNIEnv, array: jarray, is_copy: &mut jboolean)
-> Result<*mut Self>;
/// releaser
///
/// # Safety
///
/// `ptr` must have been previously returned by the `get` function.
///
/// If `mode` is not [`sys::JNI_COMMIT`], `ptr` must not be used again after calling this
/// function.
unsafe fn release(
env: &mut JNIEnv,
array: jarray,
ptr: NonNull<Self>,
mode: i32,
) -> Result<()>;
}
// TypeArray builder
macro_rules! type_array {
( $jni_type:ty, $jni_get:tt, $jni_release:tt ) => {
/// $jni_type array access/release impl
unsafe impl TypeArraySealed for $jni_type {
/// Get Java $jni_type array
unsafe fn get(
env: &mut JNIEnv,
array: jarray,
is_copy: &mut jboolean,
) -> Result<*mut Self> {
let internal = env.get_native_interface();
// Even though this method may throw OoME, use `jni_unchecked`
// instead of `jni_non_null_call` to remove (a slight) overhead
// of exception checking. An error will still be detected as a `null`
// result inside AutoElements ctor. Also, modern Hotspot in case of lack
// of memory will return null and won't throw an exception:
// https://sourcegraph.com/github.com/openjdk/jdk/-/blob/src/hotspot/share/memory/allocation.hpp#L488-489
let res = jni_unchecked!(internal, $jni_get, array, is_copy);
Ok(res)
}
/// Release Java $jni_type array
unsafe fn release(
env: &mut JNIEnv,
array: jarray,
ptr: NonNull<Self>,
mode: i32,
) -> Result<()> {
let internal = env.get_native_interface();
jni_unchecked!(internal, $jni_release, array, ptr.as_ptr(), mode as i32);
Ok(())
}
}
};
}
type_array!(jint, GetIntArrayElements, ReleaseIntArrayElements);
type_array!(jlong, GetLongArrayElements, ReleaseLongArrayElements);
type_array!(jbyte, GetByteArrayElements, ReleaseByteArrayElements);
type_array!(
jboolean,
GetBooleanArrayElements,
ReleaseBooleanArrayElements
);
type_array!(jchar, GetCharArrayElements, ReleaseCharArrayElements);
type_array!(jshort, GetShortArrayElements, ReleaseShortArrayElements);
type_array!(jfloat, GetFloatArrayElements, ReleaseFloatArrayElements);
type_array!(jdouble, GetDoubleArrayElements, ReleaseDoubleArrayElements);
}
/// A sealed trait to define type array access/release for primitive JNI types
pub trait TypeArray: type_array_sealed::TypeArraySealed {}
impl TypeArray for jint {}
impl TypeArray for jlong {}
impl TypeArray for jbyte {}
impl TypeArray for jboolean {}
impl TypeArray for jchar {}
impl TypeArray for jshort {}
impl TypeArray for jfloat {}
impl TypeArray for jdouble {}
/// Auto-release wrapper for a mutable pointer to the elements of a [`JPrimitiveArray`]
/// (such as [`JByteArray`])
///
/// This type is used to wrap pointers returned by `Get<Type>ArrayElements`
/// and ensure the pointer is released via `Release<Type>ArrayElements` when dropped.
pub struct AutoElements<'local, 'other_local, 'array, T: TypeArray> {
array: &'array JPrimitiveArray<'other_local, T>,
len: usize,
ptr: NonNull<T>,
mode: ReleaseMode,
is_copy: bool,
env: JNIEnv<'local>,
}
impl<'local, 'other_local, 'array, T: TypeArray> AutoElements<'local, 'other_local, 'array, T> {
/// # Safety
///
/// `len` must be the correct length (number of elements) of the given `array`
pub(crate) unsafe fn new_with_len(
env: &mut JNIEnv<'local>,
array: &'array JPrimitiveArray<'other_local, T>,
len: usize,
mode: ReleaseMode,
) -> Result<Self> {
// Safety: The cloned `JNIEnv` will not be used to create any local references. It will be
// passed to the methods of the `TypeArray` implementation, but that trait is `unsafe` and
// implementations are required to uphold the invariants of `unsafe_clone`.
let mut env = unsafe { env.unsafe_clone() };
let mut is_copy: jboolean = 0xff;
let ptr = unsafe { T::get(&mut env, array.as_raw(), &mut is_copy) }?;
Ok(AutoElements {
array,
len,
ptr: NonNull::new(ptr).ok_or(Error::NullPtr("Non-null ptr expected"))?,
mode,
is_copy: is_copy == sys::JNI_TRUE,
env,
})
}
pub(crate) fn new(
env: &mut JNIEnv<'local>,
array: &'array JPrimitiveArray<'other_local, T>,
mode: ReleaseMode,
) -> Result<Self> {
let len = env.get_array_length(array)? as usize;
unsafe { Self::new_with_len(env, array, len, mode) }
}
/// Get a reference to the wrapped pointer
pub fn as_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
/// Commits the changes to the array, if it is a copy
pub fn commit(&mut self) -> Result<()> {
unsafe { self.release_array_elements(sys::JNI_COMMIT) }
}
/// Calls the release function.
///
/// # Safety
///
/// `mode` must be a valid parameter to the JNI `Release<PrimitiveType>ArrayElements`' `mode`
/// parameter.
///
/// If `mode` is not [`sys::JNI_COMMIT`], then `self.ptr` must not have already been released.
unsafe fn release_array_elements(&mut self, mode: i32) -> Result<()> {
T::release(&mut self.env, self.array.as_raw(), self.ptr, mode)
}
/// Don't copy back the changes to the array on release (if it is a copy).
///
/// This has no effect if the array is not a copy.
///
/// This method is useful to change the release mode of an array originally created
/// with `ReleaseMode::CopyBack`.
pub fn discard(&mut self) {
self.mode = ReleaseMode::NoCopyBack;
}
/// Indicates if the array is a copy or not
pub fn is_copy(&self) -> bool {
self.is_copy
}
/// Returns the array length (number of elements)
pub fn len(&self) -> usize {
self.len
}
/// Returns true if the vector contains no elements.
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl<'local, 'other_local, 'array, T: TypeArray>
AsRef<AutoElements<'local, 'other_local, 'array, T>>
for AutoElements<'local, 'other_local, 'array, T>
{
fn as_ref(&self) -> &AutoElements<'local, 'other_local, 'array, T> {
self
}
}
impl<'local, 'other_local, 'array, T: TypeArray> Drop
for AutoElements<'local, 'other_local, 'array, T>
{
fn drop(&mut self) {
// Safety: `self.mode` is valid and the array has not yet been released.
let res = unsafe { self.release_array_elements(self.mode as i32) };
match res {
Ok(()) => {}
Err(e) => error!("error releasing array: {:#?}", e),
}
}
}
impl<'local, 'other_local, 'array, T: TypeArray>
From<&AutoElements<'local, 'other_local, 'array, T>> for *mut T
{
fn from(other: &AutoElements<T>) -> *mut T {
other.as_ptr()
}
}
impl<'local, 'other_local, 'array, T: TypeArray> std::ops::Deref
for AutoElements<'local, 'other_local, 'array, T>
{
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
}
impl<'local, 'other_local, 'array, T: TypeArray> std::ops::DerefMut
for AutoElements<'local, 'other_local, 'array, T>
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_mut(), self.len) }
}
}

View File

@@ -0,0 +1,168 @@
use log::error;
use std::ptr::NonNull;
use crate::sys::jboolean;
use crate::wrapper::objects::ReleaseMode;
use crate::{errors::*, sys, JNIEnv};
use super::{JPrimitiveArray, TypeArray};
#[cfg(doc)]
use super::JByteArray;
/// Auto-release wrapper for a mutable pointer to the elements of a [`JPrimitiveArray`]
/// (such as [`JByteArray`])
///
/// This type is used to wrap pointers returned by `GetPrimitiveArrayCritical`
/// and ensure the pointer is released via `ReleasePrimitiveArrayCritical` when dropped.
pub struct AutoElementsCritical<'local, 'other_local, 'array, 'env, T: TypeArray> {
array: &'array JPrimitiveArray<'other_local, T>,
len: usize,
ptr: NonNull<T>,
mode: ReleaseMode,
is_copy: bool,
env: &'env mut JNIEnv<'local>,
}
impl<'local, 'other_local, 'array, 'env, T: TypeArray>
AutoElementsCritical<'local, 'other_local, 'array, 'env, T>
{
/// # Safety
///
/// `len` must be the correct length (number of elements) of the given `array`
pub(crate) unsafe fn new_with_len(
env: &'env mut JNIEnv<'local>,
array: &'array JPrimitiveArray<'other_local, T>,
len: usize,
mode: ReleaseMode,
) -> Result<Self> {
let mut is_copy: jboolean = 0xff;
// Even though this method may throw OoME, use `jni_unchecked`
// instead of `jni_non_null_call` to remove (a slight) overhead
// of exception checking. An error will still be detected as a `null`
// result below; and, as this method is unlikely to create a copy,
// an OoME is highly unlikely.
let ptr = jni_unchecked!(
env.get_native_interface(),
GetPrimitiveArrayCritical,
array.as_raw(),
&mut is_copy
) as *mut T;
Ok(AutoElementsCritical {
array,
len,
ptr: NonNull::new(ptr).ok_or(Error::NullPtr("Non-null ptr expected"))?,
mode,
is_copy: is_copy == sys::JNI_TRUE,
env,
})
}
pub(crate) fn new(
env: &'env mut JNIEnv<'local>,
array: &'array JPrimitiveArray<'other_local, T>,
mode: ReleaseMode,
) -> Result<Self> {
let len = env.get_array_length(array)? as usize;
unsafe { Self::new_with_len(env, array, len, mode) }
}
/// Get a reference to the wrapped pointer
pub fn as_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
/// Calls `ReleasePrimitiveArrayCritical`.
///
/// # Safety
///
/// `mode` must be a valid parameter to the JNI `ReleasePrimitiveArrayCritical` `mode`
/// parameter.
///
/// If `mode` is not [`sys::JNI_COMMIT`], then `self.ptr` must not have already been released.
unsafe fn release_primitive_array_critical(&mut self, mode: i32) -> Result<()> {
jni_unchecked!(
self.env.get_native_interface(),
ReleasePrimitiveArrayCritical,
self.array.as_raw(),
self.ptr.as_ptr().cast(),
mode
);
Ok(())
}
/// Don't copy back the changes to the array on release (if it is a copy).
///
/// This has no effect if the array is not a copy.
///
/// This method is useful to change the release mode of an array originally created
/// with `ReleaseMode::CopyBack`.
pub fn discard(&mut self) {
self.mode = ReleaseMode::NoCopyBack;
}
/// Indicates if the array is a copy or not
pub fn is_copy(&self) -> bool {
self.is_copy
}
/// Returns the array length (number of elements)
pub fn len(&self) -> usize {
self.len
}
/// Returns true if the vector contains no elements.
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl<'local, 'other_local, 'array, 'env, T: TypeArray>
AsRef<AutoElementsCritical<'local, 'other_local, 'array, 'env, T>>
for AutoElementsCritical<'local, 'other_local, 'array, 'env, T>
{
fn as_ref(&self) -> &AutoElementsCritical<'local, 'other_local, 'array, 'env, T> {
self
}
}
impl<'local, 'other_local, 'array, 'env, T: TypeArray> Drop
for AutoElementsCritical<'local, 'other_local, 'array, 'env, T>
{
fn drop(&mut self) {
// Safety: `self.mode` is valid and the array has not yet been released.
let res = unsafe { self.release_primitive_array_critical(self.mode as i32) };
match res {
Ok(()) => {}
Err(e) => error!("error releasing primitive array: {:#?}", e),
}
}
}
impl<'local, 'other_local, 'array, 'env, T: TypeArray>
From<&AutoElementsCritical<'local, 'other_local, 'array, 'env, T>> for *mut T
{
fn from(other: &AutoElementsCritical<T>) -> *mut T {
other.as_ptr()
}
}
impl<'local, 'other_local, 'array, 'env, T: TypeArray> std::ops::Deref
for AutoElementsCritical<'local, 'other_local, 'array, 'env, T>
{
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
}
impl<'local, 'other_local, 'array, 'env, T: TypeArray> std::ops::DerefMut
for AutoElementsCritical<'local, 'other_local, 'array, 'env, T>
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_mut(), self.len) }
}
}

View File

@@ -0,0 +1,156 @@
use std::{
mem::ManuallyDrop,
ops::{Deref, DerefMut},
ptr,
};
use log::debug;
use crate::{objects::JObject, JNIEnv};
/// Auto-delete wrapper for local refs.
///
/// Anything passed to a foreign method _and_ returned from JNI methods is considered a local ref
/// unless it is specified otherwise.
/// These refs are automatically deleted once the foreign method exits, but it's possible that
/// they may reach the JVM-imposed limit before that happens.
///
/// This wrapper provides automatic local ref deletion when it goes out of
/// scope.
///
/// See also the [JNI specification][spec-references] for details on referencing Java objects
/// and some [extra information][android-jni-references].
///
/// [spec-references]: https://docs.oracle.com/en/java/javase/12/docs/specs/jni/design.html#referencing-java-objects
/// [android-jni-references]: https://developer.android.com/training/articles/perf-jni#local-and-global-references
#[derive(Debug)]
pub struct AutoLocal<'local, T>
where
T: Into<JObject<'local>>,
{
obj: ManuallyDrop<T>,
env: JNIEnv<'local>,
}
impl<'local, T> AutoLocal<'local, T>
where
// Note that this bound prevents `AutoLocal` from wrapping a `GlobalRef`, which implements
// `AsRef<JObject<'static>>` but *not* `Into<JObject<'static>>`. This is good, because trying
// to delete a global reference as though it were local would cause undefined behavior.
T: Into<JObject<'local>>,
{
/// Creates a new auto-delete wrapper for a local ref.
///
/// Once this wrapper goes out of scope, the `delete_local_ref` will be
/// called on the object. While wrapped, the object can be accessed via
/// the `Deref` impl.
pub fn new(obj: T, env: &JNIEnv<'local>) -> Self {
// Safety: The cloned `JNIEnv` will not be used to create any local references, only to
// delete one.
let env = unsafe { env.unsafe_clone() };
AutoLocal {
obj: ManuallyDrop::new(obj),
env,
}
}
/// Forget the wrapper, returning the original object.
///
/// This prevents `delete_local_ref` from being called when the `AutoLocal`
/// gets
/// dropped. You must either remember to delete the local ref manually, or
/// be
/// ok with it getting deleted once the foreign method returns.
pub fn forget(self) -> T {
// We need to move `self.obj` out of `self`. Normally that's trivial, but moving out of a
// type with a `Drop` implementation is not allowed. We'll have to do it manually (and
// carefully) with `unsafe`.
//
// This could be done without `unsafe` by adding `where T: Default` and using
// `std::mem::replace` to extract `self.obj`, but doing it this way avoids unnecessarily
// running the drop routine on `self`.
// Before we mutilate `self`, make sure its drop code will not be automatically run. That
// would cause undefined behavior.
let mut self_md = ManuallyDrop::new(self);
unsafe {
// Drop the `JNIEnv` in place. As of this writing, that's a no-op, but if `JNIEnv`
// gains any drop code in the future, this will run it.
//
// Safety: The `&mut` proves that `self_md.env` is valid and not aliased. It is not
// accessed again after this point. It is wrapped inside `ManuallyDrop`, and will
// therefore not be dropped twice.
ptr::drop_in_place(&mut self_md.env);
// Move `obj` out of `self` and return it.
//
// Safety: The `&mut` proves that `self_md.obj` is valid and not aliased. It is not
// accessed again after this point. It is wrapped inside `ManuallyDrop`, and will
// therefore not be dropped after it is moved.
ptr::read(&*self_md.obj)
}
}
}
impl<'local, T> Drop for AutoLocal<'local, T>
where
T: Into<JObject<'local>>,
{
fn drop(&mut self) {
// Extract the local reference from `self.obj` so that we can delete it.
//
// This is needed because it is not allowed to move out of `self` during drop. A safe
// alternative would be to wrap `self.obj` in `Option`, but that would incur a run-time
// performance penalty from constantly checking if it's `None`.
//
// Safety: `self.obj` is not used again after this `take` call.
let obj = unsafe { ManuallyDrop::take(&mut self.obj) };
// Delete the extracted local reference.
let res = self.env.delete_local_ref(obj);
match res {
Ok(()) => {}
Err(e) => debug!("error dropping global ref: {:#?}", e),
}
}
}
impl<'local, T, U> AsRef<U> for AutoLocal<'local, T>
where
T: AsRef<U> + Into<JObject<'local>>,
{
fn as_ref(&self) -> &U {
self.obj.as_ref()
}
}
impl<'local, T, U> AsMut<U> for AutoLocal<'local, T>
where
T: AsMut<U> + Into<JObject<'local>>,
{
fn as_mut(&mut self) -> &mut U {
self.obj.as_mut()
}
}
impl<'local, T> Deref for AutoLocal<'local, T>
where
T: Into<JObject<'local>>,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.obj
}
}
impl<'local, T> DerefMut for AutoLocal<'local, T>
where
T: Into<JObject<'local>>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.obj
}
}

View File

@@ -0,0 +1,116 @@
use std::{mem, ops::Deref, sync::Arc};
use log::{debug, warn};
use crate::{errors::Result, objects::JObject, sys, JNIEnv, JavaVM};
// Note: `GlobalRef` must not implement `Into<JObject>`! If it did, then it would be possible to
// wrap it in `AutoLocal`, which would cause undefined behavior upon drop as a result of calling
// the wrong JNI function to delete the reference.
/// A global JVM reference. These are "pinned" by the garbage collector and are
/// guaranteed to not get collected until released. Thus, this is allowed to
/// outlive the `JNIEnv` that it came from and can be used in other threads.
///
/// `GlobalRef` can be cloned to use _the same_ global reference in different
/// contexts. If you want to create yet another global ref to the same java object
/// you may call `JNIEnv#new_global_ref` just like you do when create `GlobalRef`
/// from a local reference.
///
/// Underlying global reference will be dropped, when the last instance
/// of `GlobalRef` leaves its scope.
///
/// It is _recommended_ that a native thread that drops the global reference is attached
/// to the Java thread (i.e., has an instance of `JNIEnv`). If the native thread is *not* attached,
/// the `GlobalRef#drop` will print a warning and implicitly `attach` and `detach` it, which
/// significantly affects performance.
#[derive(Clone, Debug)]
pub struct GlobalRef {
inner: Arc<GlobalRefGuard>,
}
#[derive(Debug)]
struct GlobalRefGuard {
obj: JObject<'static>,
vm: JavaVM,
}
impl AsRef<GlobalRef> for GlobalRef {
fn as_ref(&self) -> &GlobalRef {
self
}
}
impl AsRef<JObject<'static>> for GlobalRef {
fn as_ref(&self) -> &JObject<'static> {
self
}
}
impl Deref for GlobalRef {
type Target = JObject<'static>;
fn deref(&self) -> &Self::Target {
&self.inner.obj
}
}
impl GlobalRef {
/// Creates a new wrapper for a global reference.
///
/// # Safety
///
/// Expects a valid raw global reference that should be created with `NewGlobalRef` JNI function.
pub(crate) unsafe fn from_raw(vm: JavaVM, raw_global_ref: sys::jobject) -> Self {
GlobalRef {
inner: Arc::new(GlobalRefGuard::from_raw(vm, raw_global_ref)),
}
}
/// Get the object from the global ref
///
/// This borrows the ref and prevents it from being dropped as long as the
/// JObject sticks around.
pub fn as_obj(&self) -> &JObject<'static> {
self.as_ref()
}
}
impl GlobalRefGuard {
/// Creates a new global reference guard. This assumes that `NewGlobalRef`
/// has already been called.
unsafe fn from_raw(vm: JavaVM, obj: sys::jobject) -> Self {
GlobalRefGuard {
obj: JObject::from_raw(obj),
vm,
}
}
}
impl Drop for GlobalRefGuard {
fn drop(&mut self) {
let raw: sys::jobject = mem::take(&mut self.obj).into_raw();
let drop_impl = |env: &JNIEnv| -> Result<()> {
let internal = env.get_native_interface();
// This method is safe to call in case of pending exceptions (see chapter 2 of the spec)
jni_unchecked!(internal, DeleteGlobalRef, raw);
Ok(())
};
let res = match self.vm.get_env() {
Ok(env) => drop_impl(&env),
Err(_) => {
warn!("Dropping a GlobalRef in a detached thread. Fix your code if this message appears frequently (see the GlobalRef docs).");
self.vm
.attach_current_thread()
.and_then(|env| drop_impl(&env))
}
};
if let Err(err) = res {
debug!("error dropping global ref: {:#?}", err);
}
}
}

View File

@@ -0,0 +1,68 @@
use crate::{objects::JObject, sys::jobject};
/// Lifetime'd representation of a `jobject` that is an instance of the
/// ByteBuffer Java class. Just a `JObject` wrapped in a new class.
#[repr(transparent)]
#[derive(Debug)]
pub struct JByteBuffer<'local>(JObject<'local>);
impl<'local> AsRef<JByteBuffer<'local>> for JByteBuffer<'local> {
fn as_ref(&self) -> &JByteBuffer<'local> {
self
}
}
impl<'local> AsRef<JObject<'local>> for JByteBuffer<'local> {
fn as_ref(&self) -> &JObject<'local> {
self
}
}
impl<'local> ::std::ops::Deref for JByteBuffer<'local> {
type Target = JObject<'local>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'local> From<JByteBuffer<'local>> for JObject<'local> {
fn from(other: JByteBuffer) -> JObject {
other.0
}
}
impl<'local> From<JObject<'local>> for JByteBuffer<'local> {
fn from(other: JObject) -> Self {
unsafe { Self::from_raw(other.into_raw()) }
}
}
impl<'local, 'obj_ref> From<&'obj_ref JObject<'local>> for &'obj_ref JByteBuffer<'local> {
fn from(other: &'obj_ref JObject<'local>) -> Self {
// Safety: `JByteBuffer` is `repr(transparent)` around `JObject`.
unsafe { &*(other as *const JObject<'local> as *const JByteBuffer<'local>) }
}
}
impl<'local> std::default::Default for JByteBuffer<'local> {
fn default() -> Self {
Self(JObject::null())
}
}
impl<'local> JByteBuffer<'local> {
/// Creates a [`JByteBuffer`] that wraps the given `raw` [`jobject`]
///
/// # Safety
/// No runtime check is made to verify that the given [`jobject`] is an instance of
/// a `ByteBuffer`.
pub unsafe fn from_raw(raw: jobject) -> Self {
Self(JObject::from_raw(raw as jobject))
}
/// Unwrap to the raw jni type.
pub fn into_raw(self) -> jobject {
self.0.into_raw() as jobject
}
}

View File

@@ -0,0 +1,83 @@
use crate::{
objects::JObject,
sys::{jclass, jobject},
};
/// Lifetime'd representation of a `jclass`. Just a `JObject` wrapped in a new
/// class.
#[repr(transparent)]
#[derive(Debug)]
pub struct JClass<'local>(JObject<'local>);
impl<'local> AsRef<JClass<'local>> for JClass<'local> {
fn as_ref(&self) -> &JClass<'local> {
self
}
}
impl<'local> AsRef<JObject<'local>> for JClass<'local> {
fn as_ref(&self) -> &JObject<'local> {
self
}
}
impl<'local> ::std::ops::Deref for JClass<'local> {
type Target = JObject<'local>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'local> From<JClass<'local>> for JObject<'local> {
fn from(other: JClass) -> JObject {
other.0
}
}
/// This conversion assumes that the `JObject` is a pointer to a class object.
impl<'local> From<JObject<'local>> for JClass<'local> {
fn from(other: JObject) -> Self {
unsafe { Self::from_raw(other.into_raw()) }
}
}
/// This conversion assumes that the `JObject` is a pointer to a class object.
impl<'local, 'obj_ref> From<&'obj_ref JObject<'local>> for &'obj_ref JClass<'local> {
fn from(other: &'obj_ref JObject<'local>) -> Self {
// Safety: `JClass` is `repr(transparent)` around `JObject`.
unsafe { &*(other as *const JObject<'local> as *const JClass<'local>) }
}
}
impl<'local> std::default::Default for JClass<'local> {
fn default() -> Self {
Self(JObject::null())
}
}
impl<'local> JClass<'local> {
/// Creates a [`JClass`] that wraps the given `raw` [`jclass`]
///
/// # Safety
///
/// `raw` may be a null pointer. If `raw` is not a null pointer, then:
///
/// * `raw` must be a valid raw JNI local reference.
/// * There must not be any other `JObject` representing the same local reference.
/// * The lifetime `'local` must not outlive the local reference frame that the local reference
/// was created in.
pub unsafe fn from_raw(raw: jclass) -> Self {
Self(JObject::from_raw(raw as jobject))
}
/// Returns the raw JNI pointer.
pub fn as_raw(&self) -> jclass {
self.0.as_raw() as jclass
}
/// Unwrap to the raw jni type.
pub fn into_raw(self) -> jclass {
self.0.into_raw() as jclass
}
}

View File

@@ -0,0 +1,60 @@
use crate::sys::jfieldID;
/// Wrapper around [`jfieldID`] that implements `Send` + `Sync` since method IDs
/// are valid across threads (not tied to a `JNIEnv`).
///
/// There is no lifetime associated with these since they aren't garbage
/// collected like objects and their lifetime is not implicitly connected with
/// the scope in which they are queried.
///
/// It matches C's representation of the raw pointer, so it can be used in any
/// of the extern function argument positions that would take a [`jfieldID`].
///
/// # Safety
///
/// According to the JNI spec field IDs may be invalidated when the
/// corresponding class is unloaded.
///
/// Since this constraint can't be encoded as a Rust lifetime, and to avoid the
/// excessive cost of having every Method ID be associated with a global
/// reference to the corresponding class then it is the developers
/// responsibility to ensure they hold some class reference for the lifetime of
/// cached method IDs.
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct JFieldID {
internal: jfieldID,
}
// Field IDs are valid across threads (not tied to a JNIEnv)
unsafe impl Send for JFieldID {}
unsafe impl Sync for JFieldID {}
impl JFieldID {
/// Creates a [`JFieldID`] that wraps the given `raw` [`jfieldID`]
///
/// # Safety
///
/// Expects a valid, non-`null` ID
pub unsafe fn from_raw(raw: jfieldID) -> Self {
debug_assert!(!raw.is_null(), "from_raw fieldID argument");
Self { internal: raw }
}
/// Unwrap to the internal jni type.
pub fn into_raw(self) -> jfieldID {
self.internal
}
}
impl AsRef<JFieldID> for JFieldID {
fn as_ref(&self) -> &JFieldID {
self
}
}
impl AsMut<JFieldID> for JFieldID {
fn as_mut(&mut self) -> &mut JFieldID {
self
}
}

299
vendor/jni/src/wrapper/objects/jlist.rs vendored Normal file
View File

@@ -0,0 +1,299 @@
use crate::{
errors::*,
objects::{AutoLocal, JClass, JMethodID, JObject, JValue},
signature::{Primitive, ReturnType},
sys::jint,
JNIEnv,
};
use std::marker::PhantomData;
/// Wrapper for JObjects that implement `java/util/List`. Provides methods to get,
/// add, and remove elements.
///
/// Looks up the class and method ids on creation rather than for every method
/// call.
pub struct JList<'local, 'other_local_1: 'obj_ref, 'obj_ref> {
internal: &'obj_ref JObject<'other_local_1>,
_phantom_class: PhantomData<AutoLocal<'local, JClass<'local>>>,
get: JMethodID,
add: JMethodID,
add_idx: JMethodID,
remove: JMethodID,
size: JMethodID,
}
impl<'local, 'other_local_1: 'obj_ref, 'obj_ref> AsRef<JList<'local, 'other_local_1, 'obj_ref>>
for JList<'local, 'other_local_1, 'obj_ref>
{
fn as_ref(&self) -> &JList<'local, 'other_local_1, 'obj_ref> {
self
}
}
impl<'local, 'other_local_1: 'obj_ref, 'obj_ref> AsRef<JObject<'other_local_1>>
for JList<'local, 'other_local_1, 'obj_ref>
{
fn as_ref(&self) -> &JObject<'other_local_1> {
self.internal
}
}
impl<'local, 'other_local_1: 'obj_ref, 'obj_ref> JList<'local, 'other_local_1, 'obj_ref> {
/// Create a map from the environment and an object. This looks up the
/// necessary class and method ids to call all of the methods on it so that
/// exra work doesn't need to be done on every method call.
pub fn from_env(
env: &mut JNIEnv<'local>,
obj: &'obj_ref JObject<'other_local_1>,
) -> Result<JList<'local, 'other_local_1, 'obj_ref>> {
let class = AutoLocal::new(env.find_class("java/util/List")?, env);
let get = env.get_method_id(&class, "get", "(I)Ljava/lang/Object;")?;
let add = env.get_method_id(&class, "add", "(Ljava/lang/Object;)Z")?;
let add_idx = env.get_method_id(&class, "add", "(ILjava/lang/Object;)V")?;
let remove = env.get_method_id(&class, "remove", "(I)Ljava/lang/Object;")?;
let size = env.get_method_id(&class, "size", "()I")?;
Ok(JList {
internal: obj,
_phantom_class: PhantomData,
get,
add,
add_idx,
remove,
size,
})
}
/// Look up the value for a key. Returns `Some` if it's found and `None` if
/// a null pointer would be returned.
pub fn get<'other_local_2>(
&self,
env: &mut JNIEnv<'other_local_2>,
idx: jint,
) -> Result<Option<JObject<'other_local_2>>> {
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
// Provided argument is statically known as a JObject/null, rather than another primitive type.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.get,
ReturnType::Object,
&[JValue::from(idx).as_jni()],
)
};
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
/// Append an element to the list
pub fn add(&self, env: &mut JNIEnv, value: &JObject) -> Result<()> {
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
// Provided argument is statically known as a JObject/null, rather than another primitive type.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.add,
ReturnType::Primitive(Primitive::Boolean),
&[JValue::from(value).as_jni()],
)
};
let _ = result?;
Ok(())
}
/// Insert an element at a specific index
pub fn insert(&self, env: &mut JNIEnv, idx: jint, value: &JObject) -> Result<()> {
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
// Provided argument is statically known as a JObject/null, rather than another primitive type.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.add_idx,
ReturnType::Primitive(Primitive::Void),
&[JValue::from(idx).as_jni(), JValue::from(value).as_jni()],
)
};
let _ = result?;
Ok(())
}
/// Remove an element from the list by index
pub fn remove<'other_local_2>(
&self,
env: &mut JNIEnv<'other_local_2>,
idx: jint,
) -> Result<Option<JObject<'other_local_2>>> {
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
// Provided argument is statically known as a int, rather than any other java type.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.remove,
ReturnType::Object,
&[JValue::from(idx).as_jni()],
)
};
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
/// Get the size of the list
pub fn size(&self, env: &mut JNIEnv) -> Result<jint> {
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.size,
ReturnType::Primitive(Primitive::Int),
&[],
)
};
result.and_then(|v| v.i())
}
/// Pop the last element from the list
///
/// Note that this calls `size()` to determine the last index.
pub fn pop<'other_local_2>(
&self,
env: &mut JNIEnv<'other_local_2>,
) -> Result<Option<JObject<'other_local_2>>> {
let size = self.size(env)?;
if size == 0 {
return Ok(None);
}
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
// Provided argument is statically known as a int.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.remove,
ReturnType::Object,
&[JValue::from(size - 1).as_jni()],
)
};
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
/// Get key/value iterator for the map. This is done by getting the
/// `EntrySet` from java and iterating over it.
///
/// The returned iterator does not implement [`std::iter::Iterator`] and
/// cannot be used with a `for` loop. This is because its `next` method
/// uses a `&mut JNIEnv` to call the Java iterator. Use a `while let` loop
/// instead:
///
/// ```rust,no_run
/// # use jni::{errors::Result, JNIEnv, objects::{AutoLocal, JList, JObject}};
/// #
/// # fn example(env: &mut JNIEnv, list: JList) -> Result<()> {
/// let mut iterator = list.iter(env)?;
///
/// while let Some(obj) = iterator.next(env)? {
/// let obj: AutoLocal<JObject> = env.auto_local(obj);
///
/// // Do something with `obj` here.
/// }
/// # Ok(())
/// # }
/// ```
///
/// Each call to `next` creates a new local reference. To prevent excessive
/// memory usage or overflow error, the local reference should be deleted
/// using [`JNIEnv::delete_local_ref`] or [`JNIEnv::auto_local`] before the
/// next loop iteration. Alternatively, if the list is known to have a
/// small, predictable size, the loop could be wrapped in
/// [`JNIEnv::with_local_frame`] to delete all of the local references at
/// once.
pub fn iter<'list>(
&'list self,
env: &mut JNIEnv,
) -> Result<JListIter<'list, 'local, 'obj_ref, 'other_local_1>> {
Ok(JListIter {
list: self,
current: 0,
size: self.size(env)?,
})
}
}
/// An iterator over the keys and values in a `java.util.List`. See
/// [`JList::iter`] for more information.
///
/// TODO: make the iterator implementation for java iterators its own thing
/// and generic enough to use elsewhere.
pub struct JListIter<'list, 'local, 'other_local_1: 'obj_ref, 'obj_ref> {
list: &'list JList<'local, 'other_local_1, 'obj_ref>,
current: jint,
size: jint,
}
impl<'list, 'local, 'other_local_1: 'obj_ref, 'obj_ref>
JListIter<'list, 'local, 'other_local_1, 'obj_ref>
{
/// Advances the iterator and returns the next object in the
/// `java.util.List`, or `None` if there are no more objects.
///
/// See [`JList::iter`] for more information.
///
/// This method creates a new local reference. To prevent excessive memory
/// usage or overflow error, the local reference should be deleted using
/// [`JNIEnv::delete_local_ref`] or [`JNIEnv::auto_local`] before the next
/// loop iteration. Alternatively, if the list is known to have a small,
/// predictable size, the loop could be wrapped in
/// [`JNIEnv::with_local_frame`] to delete all of the local references at
/// once.
///
/// This method returns:
///
/// * `Ok(Some(_))`: if there was another object in the list.
/// * `Ok(None)`: if there are no more objects in the list.
/// * `Err(_)`: if there was an error calling the Java method to
/// get the next object.
///
/// This is like [`std::iter::Iterator::next`], but requires a parameter of
/// type `&mut JNIEnv` in order to call into Java.
pub fn next<'other_local_2>(
&mut self,
env: &mut JNIEnv<'other_local_2>,
) -> Result<Option<JObject<'other_local_2>>> {
if self.current == self.size {
return Ok(None);
}
let res = self.list.get(env, self.current);
self.current = match &res {
Ok(Some(_)) => self.current + 1,
Ok(None) => self.current,
Err(_) => self.size,
};
res
}
}

312
vendor/jni/src/wrapper/objects/jmap.rs vendored Normal file
View File

@@ -0,0 +1,312 @@
use crate::{
errors::*,
objects::{AutoLocal, JClass, JMethodID, JObject, JValue},
signature::{Primitive, ReturnType},
JNIEnv,
};
use std::marker::PhantomData;
/// Wrapper for JObjects that implement `java/util/Map`. Provides methods to get
/// and set entries and a way to iterate over key/value pairs.
///
/// Looks up the class and method ids on creation rather than for every method
/// call.
pub struct JMap<'local, 'other_local_1: 'obj_ref, 'obj_ref> {
internal: &'obj_ref JObject<'other_local_1>,
class: AutoLocal<'local, JClass<'local>>,
get: JMethodID,
put: JMethodID,
remove: JMethodID,
}
impl<'local, 'other_local_1: 'obj_ref, 'obj_ref> AsRef<JMap<'local, 'other_local_1, 'obj_ref>>
for JMap<'local, 'other_local_1, 'obj_ref>
{
fn as_ref(&self) -> &JMap<'local, 'other_local_1, 'obj_ref> {
self
}
}
impl<'local, 'other_local_1: 'obj_ref, 'obj_ref> AsRef<JObject<'other_local_1>>
for JMap<'local, 'other_local_1, 'obj_ref>
{
fn as_ref(&self) -> &JObject<'other_local_1> {
self.internal
}
}
impl<'local, 'other_local_1: 'obj_ref, 'obj_ref> JMap<'local, 'other_local_1, 'obj_ref> {
/// Create a map from the environment and an object. This looks up the
/// necessary class and method ids to call all of the methods on it so that
/// exra work doesn't need to be done on every method call.
pub fn from_env(
env: &mut JNIEnv<'local>,
obj: &'obj_ref JObject<'other_local_1>,
) -> Result<JMap<'local, 'other_local_1, 'obj_ref>> {
let class = AutoLocal::new(env.find_class("java/util/Map")?, env);
let get = env.get_method_id(&class, "get", "(Ljava/lang/Object;)Ljava/lang/Object;")?;
let put = env.get_method_id(
&class,
"put",
"(Ljava/lang/Object;Ljava/lang/Object;\
)Ljava/lang/Object;",
)?;
let remove =
env.get_method_id(&class, "remove", "(Ljava/lang/Object;)Ljava/lang/Object;")?;
Ok(JMap {
internal: obj,
class,
get,
put,
remove,
})
}
/// Look up the value for a key. Returns `Some` if it's found and `None` if
/// a null pointer would be returned.
pub fn get<'other_local_2>(
&self,
env: &mut JNIEnv<'other_local_2>,
key: &JObject,
) -> Result<Option<JObject<'other_local_2>>> {
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
// Provided argument is statically known as a JObject/null, rather than another primitive type.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.get,
ReturnType::Object,
&[JValue::from(key).as_jni()],
)
};
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
/// Look up the value for a key. Returns `Some` with the old value if the
/// key already existed and `None` if it's a new key.
pub fn put<'other_local_2>(
&self,
env: &mut JNIEnv<'other_local_2>,
key: &JObject,
value: &JObject,
) -> Result<Option<JObject<'other_local_2>>> {
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
// Provided argument is statically known as a JObject/null, rather than another primitive type.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.put,
ReturnType::Object,
&[JValue::from(key).as_jni(), JValue::from(value).as_jni()],
)
};
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
/// Remove a value from the map. Returns `Some` with the removed value and
/// `None` if there was no value for the key.
pub fn remove<'other_local_2>(
&self,
env: &mut JNIEnv<'other_local_2>,
key: &JObject,
) -> Result<Option<JObject<'other_local_2>>> {
// SAFETY: We keep the class loaded, and fetched the method ID for this function.
// Provided argument is statically known as a JObject/null, rather than another primitive type.
let result = unsafe {
env.call_method_unchecked(
self.internal,
self.remove,
ReturnType::Object,
&[JValue::from(key).as_jni()],
)
};
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
/// Get key/value iterator for the map. This is done by getting the
/// `EntrySet` from java and iterating over it.
///
/// The returned iterator does not implement [`std::iter::Iterator`] and
/// cannot be used with a `for` loop. This is because its `next` method
/// uses a `&mut JNIEnv` to call the Java iterator. Use a `while let` loop
/// instead:
///
/// ```rust,no_run
/// # use jni::{errors::Result, JNIEnv, objects::{AutoLocal, JMap, JObject}};
/// #
/// # fn example(env: &mut JNIEnv, map: JMap) -> Result<()> {
/// let mut iterator = map.iter(env)?;
///
/// while let Some((key, value)) = iterator.next(env)? {
/// let key: AutoLocal<JObject> = env.auto_local(key);
/// let value: AutoLocal<JObject> = env.auto_local(value);
///
/// // Do something with `key` and `value` here.
/// }
/// # Ok(())
/// # }
/// ```
///
/// Each call to `next` creates two new local references. To prevent
/// excessive memory usage or overflow error, the local references should
/// be deleted using [`JNIEnv::delete_local_ref`] or [`JNIEnv::auto_local`]
/// before the next loop iteration. Alternatively, if the map is known to
/// have a small, predictable size, the loop could be wrapped in
/// [`JNIEnv::with_local_frame`] to delete all of the local references at
/// once.
pub fn iter<'map, 'iter_local>(
&'map self,
env: &mut JNIEnv<'iter_local>,
) -> Result<JMapIter<'map, 'local, 'other_local_1, 'obj_ref, 'iter_local>> {
let iter_class = AutoLocal::new(env.find_class("java/util/Iterator")?, env);
let has_next = env.get_method_id(&iter_class, "hasNext", "()Z")?;
let next = env.get_method_id(&iter_class, "next", "()Ljava/lang/Object;")?;
let entry_class = AutoLocal::new(env.find_class("java/util/Map$Entry")?, env);
let get_key = env.get_method_id(&entry_class, "getKey", "()Ljava/lang/Object;")?;
let get_value = env.get_method_id(&entry_class, "getValue", "()Ljava/lang/Object;")?;
// Get the iterator over Map entries.
// SAFETY: We keep the class loaded, and fetched the method ID for this function. Arg list is known empty.
let entry_set = AutoLocal::new(
unsafe {
env.call_method_unchecked(
self.internal,
(&self.class, "entrySet", "()Ljava/util/Set;"),
ReturnType::Object,
&[],
)
}?
.l()?,
env,
);
// SAFETY: We keep the class loaded, and fetched the method ID for this function. Arg list is known empty.
let iter = AutoLocal::new(
unsafe {
env.call_method_unchecked(
entry_set,
("java/util/Set", "iterator", "()Ljava/util/Iterator;"),
ReturnType::Object,
&[],
)
}?
.l()?,
env,
);
Ok(JMapIter {
_phantom_map: PhantomData,
has_next,
next,
get_key,
get_value,
iter,
})
}
}
/// An iterator over the keys and values in a map. See [`JMap::iter`] for more
/// information.
///
/// TODO: make the iterator implementation for java iterators its own thing
/// and generic enough to use elsewhere.
pub struct JMapIter<'map, 'local, 'other_local_1: 'obj_ref, 'obj_ref, 'iter_local> {
_phantom_map: PhantomData<&'map JMap<'local, 'other_local_1, 'obj_ref>>,
has_next: JMethodID,
next: JMethodID,
get_key: JMethodID,
get_value: JMethodID,
iter: AutoLocal<'iter_local, JObject<'iter_local>>,
}
impl<'map, 'local, 'other_local_1: 'obj_ref, 'obj_ref, 'iter_local>
JMapIter<'map, 'local, 'other_local_1, 'obj_ref, 'iter_local>
{
/// Advances the iterator and returns the next key-value pair in the
/// `java.util.Map`, or `None` if there are no more objects.
///
/// See [`JMap::iter`] for more information.
///
/// This method creates two new local references. To prevent excessive
/// memory usage or overflow error, the local references should be deleted
/// using [`JNIEnv::delete_local_ref`] or [`JNIEnv::auto_local`] before the
/// next loop iteration. Alternatively, if the map is known to have a
/// small, predictable size, the loop could be wrapped in
/// [`JNIEnv::with_local_frame`] to delete all of the local references at
/// once.
///
/// This method returns:
///
/// * `Ok(Some(_))`: if there was another key-value pair in the map.
/// * `Ok(None)`: if there are no more key-value pairs in the map.
/// * `Err(_)`: if there was an error calling the Java method to
/// get the next key-value pair.
///
/// This is like [`std::iter::Iterator::next`], but requires a parameter of
/// type `&mut JNIEnv` in order to call into Java.
pub fn next<'other_local_2>(
&mut self,
env: &mut JNIEnv<'other_local_2>,
) -> Result<Option<(JObject<'other_local_2>, JObject<'other_local_2>)>> {
// SAFETY: We keep the class loaded, and fetched the method ID for these functions. We know none expect args.
let has_next = unsafe {
env.call_method_unchecked(
&self.iter,
self.has_next,
ReturnType::Primitive(Primitive::Boolean),
&[],
)
}?
.z()?;
if !has_next {
return Ok(None);
}
let next =
unsafe { env.call_method_unchecked(&self.iter, self.next, ReturnType::Object, &[]) }?
.l()?;
let next = env.auto_local(next);
let key =
unsafe { env.call_method_unchecked(&next, self.get_key, ReturnType::Object, &[]) }?
.l()?;
let value =
unsafe { env.call_method_unchecked(&next, self.get_value, ReturnType::Object, &[]) }?
.l()?;
Ok(Some((key, value)))
}
}

View File

@@ -0,0 +1,60 @@
use crate::sys::jmethodID;
/// Wrapper around [`jmethodID`] that implements `Send` + `Sync` since method IDs
/// are valid across threads (not tied to a `JNIEnv`).
///
/// There is no lifetime associated with these since they aren't garbage
/// collected like objects and their lifetime is not implicitly connected with
/// the scope in which they are queried.
///
/// It matches C's representation of the raw pointer, so it can be used in any
/// of the extern function argument positions that would take a [`jmethodID`].
///
/// # Safety
///
/// According to the JNI spec method IDs may be invalidated when the
/// corresponding class is unloaded.
///
/// Since this constraint can't be encoded as a Rust lifetime, and to avoid the
/// excessive cost of having every Method ID be associated with a global
/// reference to the corresponding class then it is the developers
/// responsibility to ensure they hold some class reference for the lifetime of
/// cached method IDs.
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct JMethodID {
internal: jmethodID,
}
// Method IDs are valid across threads (not tied to a JNIEnv)
unsafe impl Send for JMethodID {}
unsafe impl Sync for JMethodID {}
impl JMethodID {
/// Creates a [`JMethodID`] that wraps the given `raw` [`jmethodID`]
///
/// # Safety
///
/// Expects a valid, non-`null` ID
pub unsafe fn from_raw(raw: jmethodID) -> Self {
debug_assert!(!raw.is_null(), "from_raw methodID argument");
Self { internal: raw }
}
/// Unwrap to the internal jni type.
pub fn into_raw(self) -> jmethodID {
self.internal
}
}
impl AsRef<JMethodID> for JMethodID {
fn as_ref(&self) -> &JMethodID {
self
}
}
impl AsMut<JMethodID> for JMethodID {
fn as_mut(&mut self) -> &mut JMethodID {
self
}
}

View File

@@ -0,0 +1,103 @@
use std::marker::PhantomData;
use crate::sys::jobject;
#[cfg(doc)]
use crate::{objects::GlobalRef, JNIEnv};
/// Wrapper around [`sys::jobject`] that adds a lifetime to ensure that
/// the underlying JNI pointer won't be accessible to safe Rust code if the
/// object reference is released.
///
/// It matches C's representation of the raw pointer, so it can be used in any
/// of the extern function argument positions that would take a `jobject`.
///
/// Most other types in the `objects` module deref to this, as they do in the C
/// representation.
///
/// The lifetime `'local` represents the local reference frame that this
/// reference belongs to. See the [`JNIEnv`] documentation for more information
/// about local reference frames. If `'local` is `'static`, then this reference
/// does not belong to a local reference frame, that is, it is either null or a
/// [global reference][GlobalRef].
///
/// Note that an *owned* `JObject` is always a local reference and will never
/// have the `'static` lifetime. [`GlobalRef`] does implement
/// <code>[AsRef]&lt;JObject&lt;'static>></code>, but this only yields a
/// *borrowed* `&JObject<'static>`, never an owned `JObject<'static>`.
///
/// Local references belong to a single thread and are not safe to share across
/// threads. This type implements [`Send`] and [`Sync`] if and only if the
/// lifetime `'local` is `'static`.
#[repr(transparent)]
#[derive(Debug)]
pub struct JObject<'local> {
internal: jobject,
lifetime: PhantomData<&'local ()>,
}
unsafe impl Send for JObject<'static> {}
unsafe impl Sync for JObject<'static> {}
impl<'local> AsRef<JObject<'local>> for JObject<'local> {
fn as_ref(&self) -> &JObject<'local> {
self
}
}
impl<'local> AsMut<JObject<'local>> for JObject<'local> {
fn as_mut(&mut self) -> &mut JObject<'local> {
self
}
}
impl<'local> ::std::ops::Deref for JObject<'local> {
type Target = jobject;
fn deref(&self) -> &Self::Target {
&self.internal
}
}
impl<'local> JObject<'local> {
/// Creates a [`JObject`] that wraps the given `raw` [`jobject`]
///
/// # Safety
///
/// `raw` may be a null pointer. If `raw` is not a null pointer, then:
///
/// * `raw` must be a valid raw JNI local reference.
/// * There must not be any other `JObject` representing the same local reference.
/// * The lifetime `'local` must not outlive the local reference frame that the local reference
/// was created in.
pub unsafe fn from_raw(raw: jobject) -> Self {
Self {
internal: raw,
lifetime: PhantomData,
}
}
/// Returns the raw JNI pointer.
pub fn as_raw(&self) -> jobject {
self.internal
}
/// Unwrap to the internal jni type.
pub fn into_raw(self) -> jobject {
self.internal
}
/// Creates a new null reference.
///
/// Null references are always valid and do not belong to a local reference frame. Therefore,
/// the returned `JObject` always has the `'static` lifetime.
pub fn null() -> JObject<'static> {
unsafe { JObject::from_raw(std::ptr::null_mut() as jobject) }
}
}
impl<'local> std::default::Default for JObject<'local> {
fn default() -> Self {
Self::null()
}
}

View File

@@ -0,0 +1,81 @@
use crate::{
objects::JObject,
sys::{jobject, jobjectArray},
};
use super::AsJArrayRaw;
/// Lifetime'd representation of a [`jobjectArray`] which wraps a [`JObject`] reference
#[repr(transparent)]
#[derive(Debug)]
pub struct JObjectArray<'local>(JObject<'local>);
impl<'local> AsRef<JObjectArray<'local>> for JObjectArray<'local> {
fn as_ref(&self) -> &JObjectArray<'local> {
self
}
}
impl<'local> AsRef<JObject<'local>> for JObjectArray<'local> {
fn as_ref(&self) -> &JObject<'local> {
self
}
}
impl<'local> ::std::ops::Deref for JObjectArray<'local> {
type Target = JObject<'local>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'local> From<JObjectArray<'local>> for JObject<'local> {
fn from(other: JObjectArray) -> JObject {
other.0
}
}
/// This conversion assumes that the `JObject` is a pointer to a class object.
impl<'local> From<JObject<'local>> for JObjectArray<'local> {
fn from(other: JObject) -> Self {
unsafe { Self::from_raw(other.into_raw()) }
}
}
/// This conversion assumes that the `JObject` is a pointer to a class object.
impl<'local, 'obj_ref> From<&'obj_ref JObject<'local>> for &'obj_ref JObjectArray<'local> {
fn from(other: &'obj_ref JObject<'local>) -> Self {
// Safety: `JObjectArray` is `repr(transparent)` around `JObject`.
unsafe { &*(other as *const JObject<'local> as *const JObjectArray<'local>) }
}
}
impl<'local> std::default::Default for JObjectArray<'local> {
fn default() -> Self {
Self(JObject::null())
}
}
unsafe impl<'local> AsJArrayRaw<'local> for JObjectArray<'local> {}
impl<'local> JObjectArray<'local> {
/// Creates a [`JObjectArray`] that wraps the given `raw` [`jobjectArray`]
///
/// # Safety
///
/// `raw` may be a null pointer. If `raw` is not a null pointer, then:
///
/// * `raw` must be a valid raw JNI local reference.
/// * There must not be any other `JObject` representing the same local reference.
/// * The lifetime `'local` must not outlive the local reference frame that the local reference
/// was created in.
pub unsafe fn from_raw(raw: jobjectArray) -> Self {
Self(JObject::from_raw(raw as jobject))
}
/// Unwrap to the raw jni type.
pub fn into_raw(self) -> jobjectArray {
self.0.into_raw() as jobjectArray
}
}

View File

@@ -0,0 +1,144 @@
use std::marker::PhantomData;
use crate::{
objects::JObject,
sys::{jarray, jobject},
};
use super::TypeArray;
#[cfg(doc)]
use crate::JNIEnv;
/// Lifetime'd representation of a [`jarray`] which wraps a [`JObject`] reference
///
/// This is a wrapper type for a [`JObject`] local reference that's used to
/// differentiate JVM array types.
#[repr(transparent)]
#[derive(Debug)]
pub struct JPrimitiveArray<'local, T: TypeArray> {
obj: JObject<'local>,
lifetime: PhantomData<&'local T>,
}
impl<'local, T: TypeArray> AsRef<JPrimitiveArray<'local, T>> for JPrimitiveArray<'local, T> {
fn as_ref(&self) -> &JPrimitiveArray<'local, T> {
self
}
}
impl<'local, T: TypeArray> AsMut<JPrimitiveArray<'local, T>> for JPrimitiveArray<'local, T> {
fn as_mut(&mut self) -> &mut JPrimitiveArray<'local, T> {
self
}
}
impl<'local, T: TypeArray> AsRef<JObject<'local>> for JPrimitiveArray<'local, T> {
fn as_ref(&self) -> &JObject<'local> {
&self.obj
}
}
impl<'local, T: TypeArray> ::std::ops::Deref for JPrimitiveArray<'local, T> {
type Target = JObject<'local>;
fn deref(&self) -> &Self::Target {
&self.obj
}
}
impl<'local, T: TypeArray> From<JPrimitiveArray<'local, T>> for JObject<'local> {
fn from(other: JPrimitiveArray<'local, T>) -> JObject {
other.obj
}
}
/// This conversion assumes that the `JObject` is a pointer to a class object.
impl<'local, T: TypeArray> From<JObject<'local>> for JPrimitiveArray<'local, T> {
fn from(other: JObject) -> Self {
unsafe { Self::from_raw(other.into_raw()) }
}
}
/// This conversion assumes that the `JObject` is a pointer to a class object.
impl<'local, 'obj_ref, T: TypeArray> From<&'obj_ref JObject<'local>>
for &'obj_ref JPrimitiveArray<'local, T>
{
fn from(other: &'obj_ref JObject<'local>) -> Self {
// Safety: `JPrimitiveArray` is `repr(transparent)` around `JObject`.
unsafe { &*(other as *const JObject<'local> as *const JPrimitiveArray<'local, T>) }
}
}
impl<'local, T: TypeArray> std::default::Default for JPrimitiveArray<'local, T> {
fn default() -> Self {
Self {
obj: JObject::null(),
lifetime: PhantomData,
}
}
}
impl<'local, T: TypeArray> JPrimitiveArray<'local, T> {
/// Creates a [`JPrimitiveArray`] that wraps the given `raw` [`jarray`]
///
/// # Safety
///
/// `raw` may be a null pointer. If `raw` is not a null pointer, then:
///
/// * `raw` must be a valid raw JNI local reference.
/// * There must not be any other `JObject` representing the same local reference.
/// * The lifetime `'local` must not outlive the local reference frame that the local reference
/// was created in.
pub unsafe fn from_raw(raw: jarray) -> Self {
Self {
obj: JObject::from_raw(raw as jobject),
lifetime: PhantomData,
}
}
/// Unwrap to the raw jni type.
pub fn into_raw(self) -> jarray {
self.obj.into_raw() as jarray
}
}
/// Lifetime'd representation of a [`crate::sys::jbooleanArray`] which wraps a [`JObject`] reference
pub type JBooleanArray<'local> = JPrimitiveArray<'local, crate::sys::jboolean>;
/// Lifetime'd representation of a [`crate::sys::jbyteArray`] which wraps a [`JObject`] reference
pub type JByteArray<'local> = JPrimitiveArray<'local, crate::sys::jbyte>;
/// Lifetime'd representation of a [`crate::sys::jcharArray`] which wraps a [`JObject`] reference
pub type JCharArray<'local> = JPrimitiveArray<'local, crate::sys::jchar>;
/// Lifetime'd representation of a [`crate::sys::jshortArray`] which wraps a [`JObject`] reference
pub type JShortArray<'local> = JPrimitiveArray<'local, crate::sys::jshort>;
/// Lifetime'd representation of a [`crate::sys::jintArray`] which wraps a [`JObject`] reference
pub type JIntArray<'local> = JPrimitiveArray<'local, crate::sys::jint>;
/// Lifetime'd representation of a [`crate::sys::jlongArray`] which wraps a [`JObject`] reference
pub type JLongArray<'local> = JPrimitiveArray<'local, crate::sys::jlong>;
/// Lifetime'd representation of a [`crate::sys::jfloatArray`] which wraps a [`JObject`] reference
pub type JFloatArray<'local> = JPrimitiveArray<'local, crate::sys::jfloat>;
/// Lifetime'd representation of a [`crate::sys::jdoubleArray`] which wraps a [`JObject`] reference
pub type JDoubleArray<'local> = JPrimitiveArray<'local, crate::sys::jdouble>;
/// Trait to access the raw `jarray` pointer for types that wrap an array reference
///
/// # Safety
///
/// Implementing this trait will allow a type to be passed to [`JNIEnv::get_array_length()`]
/// or other JNI APIs that only work with a valid reference to an array (or `null`)
///
pub unsafe trait AsJArrayRaw<'local>: AsRef<JObject<'local>> {
/// Returns the raw JNI pointer as a `jarray`
fn as_jarray_raw(&self) -> jarray {
self.as_ref().as_raw() as jarray
}
}
unsafe impl<'local, T: TypeArray> AsJArrayRaw<'local> for JPrimitiveArray<'local, T> {}

View File

@@ -0,0 +1,60 @@
use crate::sys::jfieldID;
/// Wrapper around [`jfieldID`] that implements `Send` + `Sync` since field IDs
/// are valid across threads (not tied to a `JNIEnv`).
///
/// There is no lifetime associated with these since they aren't garbage
/// collected like objects and their lifetime is not implicitly connected with
/// the scope in which they are queried.
///
/// It matches C's representation of the raw pointer, so it can be used in any
/// of the extern function argument positions that would take a [`jfieldID`].
///
/// # Safety
///
/// According to the JNI spec field IDs may be invalidated when the
/// corresponding class is unloaded.
///
/// Since this constraint can't be encoded as a Rust lifetime, and to avoid the
/// excessive cost of having every Method ID be associated with a global
/// reference to the corresponding class then it is the developers
/// responsibility to ensure they hold some class reference for the lifetime of
/// cached method IDs.
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct JStaticFieldID {
internal: jfieldID,
}
// Static Field IDs are valid across threads (not tied to a JNIEnv)
unsafe impl Send for JStaticFieldID {}
unsafe impl Sync for JStaticFieldID {}
impl JStaticFieldID {
/// Creates a [`JStaticFieldID`] that wraps the given `raw` [`jfieldID`]
///
/// # Safety
///
/// Expects a valid, non-`null` ID
pub unsafe fn from_raw(raw: jfieldID) -> Self {
debug_assert!(!raw.is_null(), "from_raw fieldID argument");
Self { internal: raw }
}
/// Unwrap to the internal jni type.
pub fn into_raw(self) -> jfieldID {
self.internal
}
}
impl AsRef<JStaticFieldID> for JStaticFieldID {
fn as_ref(&self) -> &JStaticFieldID {
self
}
}
impl AsMut<JStaticFieldID> for JStaticFieldID {
fn as_mut(&mut self) -> &mut JStaticFieldID {
self
}
}

View File

@@ -0,0 +1,60 @@
use crate::sys::jmethodID;
/// Wrapper around [`jmethodID`] that implements `Send` + `Sync` since method IDs
/// are valid across threads (not tied to a `JNIEnv`).
///
/// There is no lifetime associated with these since they aren't garbage
/// collected like objects and their lifetime is not implicitly connected with
/// the scope in which they are queried.
///
/// It matches C's representation of the raw pointer, so it can be used in any
/// of the extern function argument positions that would take a [`jmethodID`].
///
/// # Safety
///
/// According to the JNI spec method IDs may be invalidated when the
/// corresponding class is unloaded.
///
/// Since this constraint can't be encoded as a Rust lifetime, and to avoid the
/// excessive cost of having every Method ID be associated with a global
/// reference to the corresponding class then it is the developers
/// responsibility to ensure they hold some class reference for the lifetime of
/// cached method IDs.
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct JStaticMethodID {
internal: jmethodID,
}
// Method IDs are valid across threads (not tied to a JNIEnv)
unsafe impl Send for JStaticMethodID {}
unsafe impl Sync for JStaticMethodID {}
impl JStaticMethodID {
/// Creates a [`JStaticMethodID`] that wraps the given `raw` [`jmethodID`]
///
/// # Safety
///
/// Expects a valid, non-`null` ID
pub unsafe fn from_raw(raw: jmethodID) -> Self {
debug_assert!(!raw.is_null(), "from_raw methodID argument");
Self { internal: raw }
}
/// Unwrap to the internal jni type.
pub fn into_raw(self) -> jmethodID {
self.internal
}
}
impl AsRef<JStaticMethodID> for JStaticMethodID {
fn as_ref(&self) -> &JStaticMethodID {
self
}
}
impl AsMut<JStaticMethodID> for JStaticMethodID {
fn as_mut(&mut self) -> &mut JStaticMethodID {
self
}
}

View File

@@ -0,0 +1,75 @@
use crate::{
objects::JObject,
sys::{jobject, jstring},
};
/// Lifetime'd representation of a `jstring`. Just a `JObject` wrapped in a new
/// class.
#[repr(transparent)]
pub struct JString<'local>(JObject<'local>);
impl<'local> AsRef<JString<'local>> for JString<'local> {
fn as_ref(&self) -> &JString<'local> {
self
}
}
impl<'local> AsRef<JObject<'local>> for JString<'local> {
fn as_ref(&self) -> &JObject<'local> {
self
}
}
impl<'local> ::std::ops::Deref for JString<'local> {
type Target = JObject<'local>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'local> From<JString<'local>> for JObject<'local> {
fn from(other: JString) -> JObject {
other.0
}
}
impl<'local> From<JObject<'local>> for JString<'local> {
fn from(other: JObject) -> Self {
unsafe { Self::from_raw(other.into_raw()) }
}
}
impl<'local, 'obj_ref> From<&'obj_ref JObject<'local>> for &'obj_ref JString<'local> {
fn from(other: &'obj_ref JObject<'local>) -> Self {
// Safety: `JString` is `repr(transparent)` around `JObject`.
unsafe { &*(other as *const JObject<'local> as *const JString<'local>) }
}
}
impl<'local> std::default::Default for JString<'local> {
fn default() -> Self {
Self(JObject::null())
}
}
impl<'local> JString<'local> {
/// Creates a [`JString`] that wraps the given `raw` [`jstring`]
///
/// # Safety
///
/// `raw` may be a null pointer. If `raw` is not a null pointer, then:
///
/// * `raw` must be a valid raw JNI local reference.
/// * There must not be any other `JObject` representing the same local reference.
/// * The lifetime `'local` must not outlive the local reference frame that the local reference
/// was created in.
pub unsafe fn from_raw(raw: jstring) -> Self {
Self(JObject::from_raw(raw as jobject))
}
/// Unwrap to the raw jni type.
pub fn into_raw(self) -> jstring {
self.0.into_raw() as jstring
}
}

View File

@@ -0,0 +1,75 @@
use crate::{
objects::JObject,
sys::{jobject, jthrowable},
};
/// Lifetime'd representation of a `jthrowable`. Just a `JObject` wrapped in a
/// new class.
#[repr(transparent)]
pub struct JThrowable<'local>(JObject<'local>);
impl<'local> AsRef<JThrowable<'local>> for JThrowable<'local> {
fn as_ref(&self) -> &JThrowable<'local> {
self
}
}
impl<'local> AsRef<JObject<'local>> for JThrowable<'local> {
fn as_ref(&self) -> &JObject<'local> {
self
}
}
impl<'local> ::std::ops::Deref for JThrowable<'local> {
type Target = JObject<'local>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'local> From<JThrowable<'local>> for JObject<'local> {
fn from(other: JThrowable) -> JObject {
other.0
}
}
impl<'local> From<JObject<'local>> for JThrowable<'local> {
fn from(other: JObject) -> Self {
unsafe { Self::from_raw(other.into_raw()) }
}
}
impl<'local, 'obj_ref> From<&'obj_ref JObject<'local>> for &'obj_ref JThrowable<'local> {
fn from(other: &'obj_ref JObject<'local>) -> Self {
// Safety: `JThrowable` is `repr(transparent)` around `JObject`.
unsafe { &*(other as *const JObject<'local> as *const JThrowable<'local>) }
}
}
impl<'local> std::default::Default for JThrowable<'local> {
fn default() -> Self {
Self(JObject::null())
}
}
impl<'local> JThrowable<'local> {
/// Creates a [`JThrowable`] that wraps the given `raw` [`jthrowable`]
///
/// # Safety
///
/// `raw` may be a null pointer. If `raw` is not a null pointer, then:
///
/// * `raw` must be a valid raw JNI local reference.
/// * There must not be any other `JObject` representing the same local reference.
/// * The lifetime `'local` must not outlive the local reference frame that the local reference
/// was created in.
pub unsafe fn from_raw(raw: jthrowable) -> Self {
Self(JObject::from_raw(raw as jobject))
}
/// Unwrap to the raw jni type.
pub fn into_raw(self) -> jthrowable {
self.0.into_raw() as jthrowable
}
}

417
vendor/jni/src/wrapper/objects/jvalue.rs vendored Normal file
View File

@@ -0,0 +1,417 @@
use std::convert::TryFrom;
use std::fmt::Debug;
use log::trace;
use crate::{errors::*, objects::JObject, signature::Primitive, sys::*};
/// Rusty version of the JNI C `jvalue` enum. Used in Java method call arguments
/// and returns.
///
/// `JValueGen` is a generic type, meant to represent both owned and borrowed
/// JNI values. The type parameter `O` refers to what kind of object reference
/// the `JValueGen` can hold, which is either:
///
/// * an owned [`JObject`], used for values returned from a Java method call,
/// or
/// * a borrowed `&JObject`, used for parameters passed to a Java method call.
///
/// These two cases are represented by the type aliases [`JValueOwned`] and
/// [`JValue`], respectively.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub enum JValueGen<O> {
Object(O),
Byte(jbyte),
Char(jchar),
Short(jshort),
Int(jint),
Long(jlong),
Bool(jboolean),
Float(jfloat),
Double(jdouble),
Void,
}
/// An <dfn>owned</dfn> [`JValueGen`].
///
/// This type is used for values returned from Java method calls. If the Java
/// method returns an object reference, it will take the form of an owned
/// [`JObject`].
pub type JValueOwned<'local> = JValueGen<JObject<'local>>;
/// A <dfn>reference</dfn> [`JValueGen`].
///
/// This type is used for parameters passed to Java method calls. If the Java
/// method is to be passed an object reference, it takes the form of a borrowed
/// <code>&[JObject]</code>.
pub type JValue<'local, 'obj_ref> = JValueGen<&'obj_ref JObject<'local>>;
impl<O> JValueGen<O> {
/// Convert the enum to its jni-compatible equivalent.
pub fn as_jni<'local>(&self) -> jvalue
where
O: AsRef<JObject<'local>> + Debug,
{
let val: jvalue = match self {
JValueGen::Object(obj) => jvalue {
l: obj.as_ref().as_raw(),
},
JValueGen::Byte(byte) => jvalue { b: *byte },
JValueGen::Char(char) => jvalue { c: *char },
JValueGen::Short(short) => jvalue { s: *short },
JValueGen::Int(int) => jvalue { i: *int },
JValueGen::Long(long) => jvalue { j: *long },
JValueGen::Bool(boolean) => jvalue { b: *boolean as i8 },
JValueGen::Float(float) => jvalue { f: *float },
JValueGen::Double(double) => jvalue { d: *double },
JValueGen::Void => jvalue {
l: ::std::ptr::null_mut(),
},
};
trace!("converted {:?} to jvalue {:?}", self, unsafe {
::std::mem::transmute::<_, u64>(val)
});
val
}
/// Convert the enum to its jni-compatible equivalent.
#[deprecated = "Use `as_jni` instead."]
pub fn to_jni<'local>(self) -> jvalue
where
O: AsRef<JObject<'local>> + Debug,
{
self.as_jni()
}
/// Get the type name for the enum variant.
pub fn type_name(&self) -> &'static str {
match *self {
JValueGen::Void => "void",
JValueGen::Object(_) => "object",
JValueGen::Byte(_) => "byte",
JValueGen::Char(_) => "char",
JValueGen::Short(_) => "short",
JValueGen::Int(_) => "int",
JValueGen::Long(_) => "long",
JValueGen::Bool(_) => "bool",
JValueGen::Float(_) => "float",
JValueGen::Double(_) => "double",
}
}
/// Get the primitive type for the enum variant. If it's not a primitive
/// (i.e. an Object), returns None.
pub fn primitive_type(&self) -> Option<Primitive> {
Some(match *self {
JValueGen::Object(_) => return None,
JValueGen::Void => Primitive::Void,
JValueGen::Byte(_) => Primitive::Byte,
JValueGen::Char(_) => Primitive::Char,
JValueGen::Short(_) => Primitive::Short,
JValueGen::Int(_) => Primitive::Int,
JValueGen::Long(_) => Primitive::Long,
JValueGen::Bool(_) => Primitive::Boolean,
JValueGen::Float(_) => Primitive::Float,
JValueGen::Double(_) => Primitive::Double,
})
}
/// Try to unwrap to an Object.
pub fn l(self) -> Result<O> {
match self {
JValueGen::Object(obj) => Ok(obj),
_ => Err(Error::WrongJValueType("object", self.type_name())),
}
}
/// Try to unwrap to a boolean.
pub fn z(self) -> Result<bool> {
match self {
JValueGen::Bool(b) => Ok(b == JNI_TRUE),
_ => Err(Error::WrongJValueType("bool", self.type_name())),
}
}
/// Try to unwrap to a byte.
pub fn b(self) -> Result<jbyte> {
match self {
JValueGen::Byte(b) => Ok(b),
_ => Err(Error::WrongJValueType("jbyte", self.type_name())),
}
}
/// Try to unwrap to a char.
pub fn c(self) -> Result<jchar> {
match self {
JValueGen::Char(b) => Ok(b),
_ => Err(Error::WrongJValueType("jchar", self.type_name())),
}
}
/// Try to unwrap to a double.
pub fn d(self) -> Result<jdouble> {
match self {
JValueGen::Double(b) => Ok(b),
_ => Err(Error::WrongJValueType("jdouble", self.type_name())),
}
}
/// Try to unwrap to a float.
pub fn f(self) -> Result<jfloat> {
match self {
JValueGen::Float(b) => Ok(b),
_ => Err(Error::WrongJValueType("jfloat", self.type_name())),
}
}
/// Try to unwrap to an int.
pub fn i(self) -> Result<jint> {
match self {
JValueGen::Int(b) => Ok(b),
_ => Err(Error::WrongJValueType("jint", self.type_name())),
}
}
/// Try to unwrap to a long.
pub fn j(self) -> Result<jlong> {
match self {
JValueGen::Long(b) => Ok(b),
_ => Err(Error::WrongJValueType("jlong", self.type_name())),
}
}
/// Try to unwrap to a short.
pub fn s(self) -> Result<jshort> {
match self {
JValueGen::Short(b) => Ok(b),
_ => Err(Error::WrongJValueType("jshort", self.type_name())),
}
}
/// Try to unwrap to a void.
pub fn v(self) -> Result<()> {
match self {
JValueGen::Void => Ok(()),
_ => Err(Error::WrongJValueType("void", self.type_name())),
}
}
/// Copies or borrows the value in this `JValue`.
///
/// If the value is a primitive type, it is copied. If the value is an
/// object reference, it is borrowed.
pub fn borrow(&self) -> JValueGen<&O> {
match self {
JValueGen::Object(o) => JValueGen::Object(o),
JValueGen::Byte(v) => JValueGen::Byte(*v),
JValueGen::Char(v) => JValueGen::Char(*v),
JValueGen::Short(v) => JValueGen::Short(*v),
JValueGen::Int(v) => JValueGen::Int(*v),
JValueGen::Long(v) => JValueGen::Long(*v),
JValueGen::Bool(v) => JValueGen::Bool(*v),
JValueGen::Float(v) => JValueGen::Float(*v),
JValueGen::Double(v) => JValueGen::Double(*v),
JValueGen::Void => JValueGen::Void,
}
}
}
impl<'obj_ref, O> From<&'obj_ref JValueGen<O>> for JValueGen<&'obj_ref O> {
fn from(other: &'obj_ref JValueGen<O>) -> Self {
other.borrow()
}
}
impl<'local, T: Into<JObject<'local>>> From<T> for JValueOwned<'local> {
fn from(other: T) -> Self {
Self::Object(other.into())
}
}
impl<'local: 'obj_ref, 'obj_ref, T: AsRef<JObject<'local>>> From<&'obj_ref T>
for JValue<'local, 'obj_ref>
{
fn from(other: &'obj_ref T) -> Self {
Self::Object(other.as_ref())
}
}
impl<'local> TryFrom<JValueOwned<'local>> for JObject<'local> {
type Error = Error;
fn try_from(value: JValueOwned<'local>) -> Result<Self> {
match value {
JValueGen::Object(o) => Ok(o),
_ => Err(Error::WrongJValueType("object", value.type_name())),
}
}
}
impl<O> From<bool> for JValueGen<O> {
fn from(other: bool) -> Self {
JValueGen::Bool(if other { JNI_TRUE } else { JNI_FALSE })
}
}
// jbool
impl<O> From<jboolean> for JValueGen<O> {
fn from(other: jboolean) -> Self {
JValueGen::Bool(other)
}
}
impl<O> TryFrom<JValueGen<O>> for jboolean {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Bool(b) => Ok(b),
_ => Err(Error::WrongJValueType("bool", value.type_name())),
}
}
}
// jchar
impl<O> From<jchar> for JValueGen<O> {
fn from(other: jchar) -> Self {
JValueGen::Char(other)
}
}
impl<O> TryFrom<JValueGen<O>> for jchar {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Char(c) => Ok(c),
_ => Err(Error::WrongJValueType("char", value.type_name())),
}
}
}
// jshort
impl<O> From<jshort> for JValueGen<O> {
fn from(other: jshort) -> Self {
JValueGen::Short(other)
}
}
impl<O> TryFrom<JValueGen<O>> for jshort {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Short(s) => Ok(s),
_ => Err(Error::WrongJValueType("short", value.type_name())),
}
}
}
// jfloat
impl<O> From<jfloat> for JValueGen<O> {
fn from(other: jfloat) -> Self {
JValueGen::Float(other)
}
}
impl<O> TryFrom<JValueGen<O>> for jfloat {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Float(f) => Ok(f),
_ => Err(Error::WrongJValueType("float", value.type_name())),
}
}
}
// jdouble
impl<O> From<jdouble> for JValueGen<O> {
fn from(other: jdouble) -> Self {
JValueGen::Double(other)
}
}
impl<O> TryFrom<JValueGen<O>> for jdouble {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Double(d) => Ok(d),
_ => Err(Error::WrongJValueType("double", value.type_name())),
}
}
}
// jint
impl<O> From<jint> for JValueGen<O> {
fn from(other: jint) -> Self {
JValueGen::Int(other)
}
}
impl<O> TryFrom<JValueGen<O>> for jint {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Int(i) => Ok(i),
_ => Err(Error::WrongJValueType("int", value.type_name())),
}
}
}
// jlong
impl<O> From<jlong> for JValueGen<O> {
fn from(other: jlong) -> Self {
JValueGen::Long(other)
}
}
impl<O> TryFrom<JValueGen<O>> for jlong {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Long(l) => Ok(l),
_ => Err(Error::WrongJValueType("long", value.type_name())),
}
}
}
// jbyte
impl<O> From<jbyte> for JValueGen<O> {
fn from(other: jbyte) -> Self {
JValueGen::Byte(other)
}
}
impl<O> TryFrom<JValueGen<O>> for jbyte {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Byte(b) => Ok(b),
_ => Err(Error::WrongJValueType("byte", value.type_name())),
}
}
}
// jvoid
impl<O> From<()> for JValueGen<O> {
fn from(_: ()) -> Self {
JValueGen::Void
}
}
impl<O> TryFrom<JValueGen<O>> for () {
type Error = Error;
fn try_from(value: JValueGen<O>) -> Result<Self> {
match value {
JValueGen::Void => Ok(()),
_ => Err(Error::WrongJValueType("void", value.type_name())),
}
}
}

66
vendor/jni/src/wrapper/objects/mod.rs vendored Normal file
View File

@@ -0,0 +1,66 @@
// wrappers arount jni pointer types that add lifetimes and other functionality.
mod jvalue;
pub use self::jvalue::*;
mod jmethodid;
pub use self::jmethodid::*;
mod jstaticmethodid;
pub use self::jstaticmethodid::*;
mod jfieldid;
pub use self::jfieldid::*;
mod jstaticfieldid;
pub use self::jstaticfieldid::*;
mod jobject;
pub use self::jobject::*;
mod jthrowable;
pub use self::jthrowable::*;
mod jclass;
pub use self::jclass::*;
mod jstring;
pub use self::jstring::*;
mod jmap;
pub use self::jmap::*;
mod jlist;
pub use self::jlist::*;
mod jbytebuffer;
pub use self::jbytebuffer::*;
// For storing a reference to a java object
mod global_ref;
pub use self::global_ref::*;
mod weak_ref;
pub use self::weak_ref::*;
// For automatic local ref deletion
mod auto_local;
pub use self::auto_local::*;
mod release_mode;
pub use self::release_mode::*;
/// Primitive Array types
mod jobject_array;
pub use self::jobject_array::*;
/// Primitive Array types
mod jprimitive_array;
pub use self::jprimitive_array::*;
// For automatic pointer-based generic array release
mod auto_elements;
pub use self::auto_elements::*;
// For automatic pointer-based primitive array release
mod auto_elements_critical;
pub use self::auto_elements_critical::*;

View File

@@ -0,0 +1,18 @@
use crate::sys::JNI_ABORT;
#[cfg(doc)]
use super::{AutoElements, AutoElementsCritical};
/// ReleaseMode
///
/// This defines the release mode of [`AutoElements`] (and [`AutoElementsCritical`]) resources, and
/// related release array functions.
#[derive(Clone, Copy, Debug)]
#[repr(i32)]
pub enum ReleaseMode {
/// Copy back the content and free the elems buffer. For read-only access, prefer
/// [`NoCopyBack`](ReleaseMode::NoCopyBack).
CopyBack = 0,
/// Free the buffer without copying back the possible changes.
NoCopyBack = JNI_ABORT,
}

View File

@@ -0,0 +1,176 @@
use std::sync::Arc;
use log::{debug, warn};
use crate::{
errors::Result,
objects::{GlobalRef, JObject},
sys, JNIEnv, JavaVM,
};
// Note: `WeakRef` must not implement `Into<JObject>`! If it did, then it would be possible to
// wrap it in `AutoLocal`, which would cause undefined behavior upon drop as a result of calling
// the wrong JNI function to delete the reference.
/// A *weak* global JVM reference. These are global in scope like
/// [`GlobalRef`], and may outlive the `JNIEnv` they came from, but are
/// *not* guaranteed to not get collected until released.
///
/// `WeakRef` can be cloned to use _the same_ weak reference in different
/// contexts. If you want to create yet another weak ref to the same java object, call
/// [`WeakRef::clone_in_jvm`].
///
/// Underlying weak reference will be dropped, when the last instance
/// of `WeakRef` leaves its scope.
///
/// It is _recommended_ that a native thread that drops the weak reference is attached
/// to the Java thread (i.e., has an instance of `JNIEnv`). If the native thread is *not* attached,
/// the `WeakRef#drop` will print a warning and implicitly `attach` and `detach` it, which
/// significantly affects performance.
#[derive(Clone)]
pub struct WeakRef {
inner: Arc<WeakRefGuard>,
}
struct WeakRefGuard {
raw: sys::jweak,
vm: JavaVM,
}
unsafe impl Send for WeakRef {}
unsafe impl Sync for WeakRef {}
impl WeakRef {
/// Creates a new wrapper for a global reference.
///
/// # Safety
///
/// Expects a valid raw weak global reference that should be created with `NewWeakGlobalRef`
/// JNI function.
pub(crate) unsafe fn from_raw(vm: JavaVM, raw: sys::jweak) -> Self {
WeakRef {
inner: Arc::new(WeakRefGuard { raw, vm }),
}
}
/// Returns the raw JNI weak reference.
pub fn as_raw(&self) -> sys::jweak {
self.inner.raw
}
/// Creates a new local reference to this object.
///
/// This object may have already been garbage collected by the time this method is called. If
/// so, this method returns `Ok(None)`. Otherwise, it returns `Ok(Some(r))` where `r` is the
/// new local reference.
///
/// If this method returns `Ok(Some(r))`, it is guaranteed that the object will not be garbage
/// collected at least until `r` is deleted or becomes invalid.
pub fn upgrade_local<'local>(&self, env: &JNIEnv<'local>) -> Result<Option<JObject<'local>>> {
let r = env.new_local_ref(unsafe { JObject::from_raw(self.as_raw()) })?;
// Per JNI spec, `NewLocalRef` will return a null pointer if the object was GC'd.
if r.is_null() {
Ok(None)
} else {
Ok(Some(r))
}
}
/// Creates a new strong global reference to this object.
///
/// This object may have already been garbage collected by the time this method is called. If
/// so, this method returns `Ok(None)`. Otherwise, it returns `Ok(Some(r))` where `r` is the
/// new strong global reference.
///
/// If this method returns `Ok(Some(r))`, it is guaranteed that the object will not be garbage
/// collected at least until `r` is dropped.
pub fn upgrade_global(&self, env: &JNIEnv) -> Result<Option<GlobalRef>> {
let r = env.new_global_ref(unsafe { JObject::from_raw(self.as_raw()) })?;
// Unlike `NewLocalRef`, the JNI spec does *not* guarantee that `NewGlobalRef` will return a
// null pointer if the object was GC'd, so we'll have to check.
if env.is_same_object(&r, JObject::null())? {
Ok(None)
} else {
Ok(Some(r))
}
}
/// Checks if the object referred to by this `WeakRef` has been garbage collected.
///
/// Note that garbage collection can happen at any moment, so a return of `Ok(true)` from this
/// method does not guarantee that [`WeakRef::upgrade_local`] or [`WeakRef::upgrade_global`]
/// will succeed.
///
/// This is equivalent to
/// <code>self.[is_same_object][WeakRef::is_same_object](env, [JObject::null]\())</code>.
pub fn is_garbage_collected(&self, env: &JNIEnv) -> Result<bool> {
self.is_same_object(env, JObject::null())
}
// The following methods are wrappers around those `JNIEnv` methods that make sense for a weak
// reference. These methods exist because they use `JObject::from_raw` on the raw pointer of a
// weak reference. Although this usage is sound, it is `unsafe`. It's also confusing because
// `JObject` normally represents a strong reference.
/// Returns true if this weak reference refers to the given object. Otherwise returns false.
///
/// If `object` is [null][JObject::null], then this method is equivalent to
/// [`WeakRef::is_garbage_collected`]: it returns true if the object referred to by this
/// `WeakRef` has been garbage collected, or false if the object has not yet been garbage
/// collected.
pub fn is_same_object<'local, O>(&self, env: &JNIEnv<'local>, object: O) -> Result<bool>
where
O: AsRef<JObject<'local>>,
{
env.is_same_object(unsafe { JObject::from_raw(self.as_raw()) }, object)
}
/// Returns true if this weak reference refers to the same object as another weak reference.
/// Otherwise returns false.
///
/// This method will also return true if both weak references refer to an object that has been
/// garbage collected.
pub fn is_weak_ref_to_same_object(&self, env: &JNIEnv, other: &WeakRef) -> Result<bool> {
self.is_same_object(env, unsafe { JObject::from_raw(other.as_raw()) })
}
/// Creates a new weak reference to the same object that this one refers to.
///
/// `WeakRef` implements [`Clone`], which should normally be used whenever a new `WeakRef` to
/// the same object is needed. However, that only increments an internal reference count and
/// does not actually create a new weak reference in the JVM. If you specifically need to have
/// the JVM create a new weak reference, use this method instead of `Clone`.
///
/// This method returns `Ok(None)` if the object has already been garbage collected.
pub fn clone_in_jvm(&self, env: &JNIEnv) -> Result<Option<WeakRef>> {
env.new_weak_ref(unsafe { JObject::from_raw(self.as_raw()) })
}
}
impl Drop for WeakRefGuard {
fn drop(&mut self) {
fn drop_impl(env: &JNIEnv, raw: sys::jweak) -> Result<()> {
let internal = env.get_native_interface();
// This method is safe to call in case of pending exceptions (see chapter 2 of the spec)
jni_unchecked!(internal, DeleteWeakGlobalRef, raw);
Ok(())
}
let res = match self.vm.get_env() {
Ok(env) => drop_impl(&env, self.raw),
Err(_) => {
warn!("Dropping a WeakRef in a detached thread. Fix your code if this message appears frequently (see the WeakRef docs).");
self.vm
.attach_current_thread()
.and_then(|env| drop_impl(&env, self.raw))
}
};
if let Err(err) = res {
debug!("error dropping weak ref: {:#?}", err);
}
}
}