java-jni-extras 0.2.2

A collection of helper macros for use with jni
Documentation
use jni::Env;
use jni::objects::{JObject, JObjectArray, JPrimitiveArray, JString, Reference, TypeArray};
use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
pub use java_jni_extras_proc::java_class;

pub trait JavaTyped<'c> {
    type JType;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType>;
}

trait JavaObject {}
impl<'c> JavaObject for JObject<'c> {}
impl<'c> JavaObject for JObjectArray<'c> {}
impl<'c, T: TypeArray> JavaObject for JPrimitiveArray<'c, T> {}

pub trait JavaPrimitive: Sized {
    type P: Sized + TypeArray;
    fn as_java(&self) -> Self::P;
}
macro_rules! java_primitive {
    ( $T:ty, $j:ty ) => {
        const _: () = const {
            assert!(std::mem::size_of::<$T>() == std::mem::size_of::<<$T as JavaPrimitive>::P>());
        };
        impl JavaPrimitive for $T {
            type P = $j;
            fn as_java(&self) -> Self::P {
                *self
            }
        }
        impl<'c, 'r> JavaTyped<'c> for &[$T]
        {
            type JType = JPrimitiveArray<'c, <$T as JavaPrimitive>::P>;
            fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
                let arr = JPrimitiveArray::<<$T as JavaPrimitive>::P>::new(env, self.len())?;
                arr.set_region(env, 0, unsafe { std::mem::transmute(self) })?;
                Ok(arr)
            }
        }
        impl<'c, 'r, const N: usize> JavaTyped<'c> for &[$T; N]
        {
            type JType = JPrimitiveArray<'c, <$T as JavaPrimitive>::P>;
            fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
                let arr = JPrimitiveArray::<<$T as JavaPrimitive>::P>::new(env, self.len())?;
                arr.set_region(env, 0, unsafe { std::mem::transmute(self.as_slice()) })?;
                Ok(arr)
            }
        }
        impl<'c, 'r> JavaTyped<'c> for Vec<$T>
        {
            type JType = JPrimitiveArray<'c, <$T as JavaPrimitive>::P>;
            fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
                let arr = JPrimitiveArray::<<$T as JavaPrimitive>::P>::new(env, self.len())?;
                arr.set_region(env, 0, unsafe { std::mem::transmute(self.as_slice()) })?;
                Ok(arr)
            }
        }
    };
}

java_primitive! { i8, jbyte }
java_primitive! { u16, jchar }
java_primitive! { i16, jshort }
java_primitive! { i32, jint }
java_primitive! { i64, jlong }
java_primitive! { f32, jfloat }
java_primitive! { f64, jdouble }
java_primitive! { bool, jboolean }

impl<'c, T: Sized + JavaPrimitive> JavaTyped<'c> for T {
    type JType = T::P;
    fn into_java<'local>(self, _env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        Ok(self.as_java())
    }
}

impl<'c, 'r> JavaTyped<'c> for &str {
    type JType = JString<'c>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        env.new_string(self)
    }
}

impl<'c, 'r> JavaTyped<'c> for String {
    type JType = JString<'c>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        env.new_string(self)
    }
}

impl<'c, 'r, T> JavaTyped<'c> for &[T]
where
    T: JavaObject + JavaTyped<'c> + Reference<Kind<'c> = T> + AsRef<JObject<'c>>,
    T::JType: 'c + Reference<Kind<'c> = T::JType> + AsRef<T::JType>,
{
    type JType = JObjectArray<'c, T::JType>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = T::JType::null();
        let arr: Self::JType = JObjectArray::<'c, T::JType>::new(env, self.len(), null)?;
        for (i, v) in self.iter().enumerate() {
            let v = env.new_local_ref(v)?;
            let v = JavaTyped::<'c>::into_java(v, env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c, 'r, T, const N: usize> JavaTyped<'c> for &[T; N]
where
    T: JavaObject + JavaTyped<'c> + Reference<Kind<'c> = T> + AsRef<JObject<'c>>,
    T::JType: 'c + Reference<Kind<'c> = T::JType> + AsRef<T::JType>,
{
    type JType = JObjectArray<'c, T::JType>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = T::JType::null();
        let arr: Self::JType = JObjectArray::<'c, T::JType>::new(env, self.len(), null)?;
        for (i, v) in self.iter().enumerate() {
            let v = env.new_local_ref(v)?;
            let v = JavaTyped::<'c>::into_java(v, env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c, 'r, T> JavaTyped<'c> for Vec<T>
where
    T: JavaObject + JavaTyped<'c> + Reference<Kind<'c> = T> + AsRef<JObject<'c>>,
    T::JType: 'c + Reference<Kind<'c> = T::JType> + AsRef<T::JType>,
{
    type JType = JObjectArray<'c, T::JType>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = T::JType::null();
        let arr: Self::JType = JObjectArray::<'c, T::JType>::new(env, self.len(), null)?;
        for (i, v) in self.into_iter().enumerate() {
            let v = JavaTyped::<'c>::into_java(v, env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c, 'r> JavaTyped<'c> for &[&str] {
    type JType = JObjectArray<'c, JString<'c>>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = JString::null();
        let arr: Self::JType = JObjectArray::<'c, JString>::new(env, self.len(), null)?;
        for (i, v) in self.iter().enumerate() {
            let v = v.into_java(env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c, 'r, const N: usize> JavaTyped<'c> for &[&str; N] {
    type JType = JObjectArray<'c, JString<'c>>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = JString::null();
        let arr: Self::JType = JObjectArray::<'c, JString>::new(env, self.len(), null)?;
        for (i, v) in self.iter().enumerate() {
            let v = v.into_java(env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c, 'r> JavaTyped<'c> for Vec<&str> {
    type JType = JObjectArray<'c, JString<'c>>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = JString::null();
        let arr: Self::JType = JObjectArray::<'c, JString>::new(env, self.len(), null)?;
        for (i, v) in self.into_iter().enumerate() {
            let v = v.into_java(env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c, 'r> JavaTyped<'c> for &[String] {
    type JType = JObjectArray<'c, JString<'c>>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = JString::null();
        let arr: Self::JType = JObjectArray::<'c, JString>::new(env, self.len(), null)?;
        for (i, v) in self.iter().enumerate() {
            let v = v.clone().into_java(env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c, 'r, const N: usize> JavaTyped<'c> for &[String; N] {
    type JType = JObjectArray<'c, JString<'c>>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = JString::null();
        let arr: Self::JType = JObjectArray::<'c, JString>::new(env, self.len(), null)?;
        for (i, v) in self.iter().enumerate() {
            let v = v.clone().into_java(env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c, 'r> JavaTyped<'c> for Vec<String> {
    type JType = JObjectArray<'c, JString<'c>>;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        let null = JString::null();
        let arr: Self::JType = JObjectArray::<'c, JString>::new(env, self.len(), null)?;
        for (i, v) in self.into_iter().enumerate() {
            let v = v.into_java(env)?;
            arr.set_element(env, i, v)?;
        }
        Ok(arr)
    }
}

impl<'c> JavaTyped<'c> for JObject<'c> {
    type JType = Self;
    fn into_java<'local>(self, _env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        Ok(self)
    }
}

impl<'c> JavaTyped<'c> for JObjectArray<'c> {
    type JType = Self;
    fn into_java<'local>(self, _env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        Ok(self)
    }
}

impl<'c, T: TypeArray> JavaTyped<'c> for JPrimitiveArray<'c, T> {
    type JType = Self;
    fn into_java<'local>(self, _env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        Ok(self)
    }
}

pub enum MaybeJavaTyped<'c, T>
where
    T: JavaTyped<'c>
{
    Java(T::JType),
    Rust(T),
}

impl<'c, T> JavaTyped<'c> for MaybeJavaTyped<'c, T>
where
    T: JavaTyped<'c>
{
    type JType = T::JType;
    fn into_java<'local>(self, env: &'local mut Env<'c>) -> jni::errors::Result<Self::JType> {
        match self {
            Self::Rust(r) => r.into_java(env),
            Self::Java(j) => Ok(j)
        }
    }
}