Skip to content

Commit

Permalink
Initial implementation of Java FFI traits for Option<T>
Browse files Browse the repository at this point in the history
This involves many hacky things including implementing some of the traits to the JOption enum instead!!

That's because there are some issues in the compiler like this one! rust-lang/rust#99940

Signed-off-by: Nefo Fortressia <nefothingy@hotmail.com>
  • Loading branch information
togetherwithasteria committed Jul 30, 2022
1 parent a1ac85b commit 3a465fb
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ robusta-codegen = { version = "0.2", path = "./robusta-codegen" }
jni = "0.19.0"
paste = "1.0.0"
static_assertions = "1.1.0"
libc = "0.2"
lazy_static = "1.4.0"

[dev-dependencies]
native = { path = "./tests/driver/native" }
Expand Down
61 changes: 60 additions & 1 deletion src/convert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,28 @@ impl<'env> JavaValue<'env> for JString<'env> {
}
}

impl<'env, T: JavaValue<'env> + Signature> JavaValue<'env> for Option<T>
where
JOption<T>: for<'borrow> FromJavaValue<'env, Source = JObject<'env>>,
{
fn autobox(self, env: JNIEnv<'env>) -> JObject<'env> {
IntoJavaValue::into(<JOption<T> as From<Self>>::from(self), env)
}

/// Convert [`JObject`] to the implementing type.
fn unbox(s: JObject<'env>, env: JNIEnv<'env>) -> Self {
let option = <JOption<T> as FromJavaValue>::from(s, env);
Into::into(option)
}
}
impl<T: Signature> Signature for jni::errors::Result<T> {
const SIG_TYPE: &'static str = <T as Signature>::SIG_TYPE;
}

impl<T: Signature> Signature for JOption<T> {
const SIG_TYPE: &'static str = <T as Signature>::SIG_TYPE;
}

pub struct JValueWrapper<'a>(pub JValue<'a>);

impl<'a> From<JValue<'a>> for JValueWrapper<'a> {
Expand Down Expand Up @@ -322,7 +340,48 @@ impl<'a> TryFrom<JValueWrapper<'a>> for JString<'a> {
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Object(o) => Ok(From::from(o)),
_ => Err(Error::WrongJValueType("string", value.0.type_name()).into()),
value => Err(Error::WrongJValueType("string", value.type_name()).into()),
}
}
}

pub enum JOption<T> {
Some(T),
None,
}

impl<T> Into<Option<T>> for JOption<T> {
fn into(self) -> Option<T> {
match self {
JOption::None => None,
JOption::Some(value) => Some(value),
}
}
}

impl<T> From<Option<T>> for JOption<T> {
fn from(option: Option<T>) -> Self {
match option {
None => JOption::None,
Some(value) => JOption::Some(value),
}
}
}

impl<'env, T> TryFrom<JValueWrapper<'env>> for JOption<T>
where
T: TryFromJavaValue<'env, Source = JObject<'env>>,
{
type Error = jni::errors::Error;

fn try_from(wrapper: JValueWrapper<'env>) -> Result<Self, Self::Error> {
match wrapper.0 {
JValue::Object(value) => Ok(JOption::Some(T::try_from(value, unsafe {
JNIEnv::from_raw(ENV.with(|env| env.get_native_interface())).unwrap()
})?)),

JValue::Void => Ok(JOption::None),
_ => unreachable!(),
}
}
}
10 changes: 10 additions & 0 deletions src/convert/safe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,13 @@ where
self.and_then(|s| TryIntoJavaValue::try_into(s, env))
}
}

impl<'env, T: Signature + IntoJavaValue<'env>> TryIntoJavaValue<'env> for JOption<T> {
type Target = <JOption<T> as IntoJavaValue<'env>>::Target;

const SIG_TYPE: &'static str = <Self as Signature>::SIG_TYPE;

fn try_into(self, env: JNIEnv<'env>) -> Result<Self::Target> {
Ok(IntoJavaValue::into(self, env))
}
}
47 changes: 47 additions & 0 deletions src/convert/unchecked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
//! **These functions *will* panic should any conversion fail.**
//!
use std::convert::TryFrom;

use jni::objects::{JList, JObject, JString, JValue};
use jni::sys::{jboolean, jbooleanArray, jchar, jobject, jstring};
use jni::JNIEnv;
Expand Down Expand Up @@ -243,3 +245,48 @@ where
self.map(|s| IntoJavaValue::into(s, env)).unwrap()
}
}

impl<'env, T> IntoJavaValue<'env> for JOption<T>
where
T: IntoJavaValue<'env>,
{
type Target = JObject<'env>;

fn into(self, env: JNIEnv<'env>) -> Self::Target {
use JOption::*;
match self {
Some(value) => IntoJavaValue::into(value, env).autobox(env),
None => JObject::null(),
}
}
}

impl<'env, T> FromJavaValue<'env> for JOption<T>
where
T: FromJavaValue<'env, Source = JObject<'env>>,
{
type Source = JObject<'env>;

fn from(s: Self::Source, env: JNIEnv<'env>) -> Self {
use JOption::*;
let s2 = s.clone();
if env.is_same_object(s, JObject::null()).unwrap() {
Some(<T as FromJavaValue>::from(s2, env))
} else {
None
}
}
}

impl<'env> FromJavaValue<'env> for Option<String> {
type Source = <String as FromJavaValue<'env>>::Source;

fn from(s: Self::Source, env: JNIEnv<'env>) -> Self {
let s2 = s.clone();
if env.is_same_object(s, JObject::null()).unwrap() {
Some(<String as FromJavaValue>::from(s2, env))
} else {
None
}
}
}

0 comments on commit 3a465fb

Please sign in to comment.