use std::convert::TryFrom;
use std::str::FromStr;
use jni::errors::Error;
use jni::objects::{JObject, JString, JValue};
use jni::signature::JavaType;
use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jobject, jshort};
use jni::JNIEnv;
use paste::paste;
pub use field::*;
pub use robusta_codegen::Signature;
pub use safe::*;
pub use unchecked::*;
pub mod field;
pub mod safe;
pub mod unchecked;
pub trait JavaValue<'env> {
fn autobox(self, env: &JNIEnv<'env>) -> JObject<'env>;
fn unbox(s: JObject<'env>, env: &JNIEnv<'env>) -> Self;
}
pub trait Signature {
const SIG_TYPE: &'static str;
}
macro_rules! jvalue_types {
($type:ty: $boxed:ident ($sig:ident) [$unbox_method:ident]) => {
impl Signature for $type {
const SIG_TYPE: &'static str = stringify!($sig);
}
impl<'env> JavaValue<'env> for $type {
fn autobox(self, env: &JNIEnv<'env>) -> JObject<'env> {
env.call_static_method_unchecked(concat!("java/lang/", stringify!($boxed)),
(concat!("java/lang/", stringify!($boxed)), "valueOf", concat!(stringify!(($sig)), "Ljava/lang/", stringify!($boxed), ";")),
JavaType::from_str(concat!("Ljava/lang/", stringify!($boxed), ";")).unwrap(),
&[Into::into(self)]).unwrap().l().unwrap()
}
fn unbox(s: JObject<'env>, env: &JNIEnv<'env>) -> Self {
paste!(Into::into(env.call_method_unchecked(s, (concat!("java/lang/", stringify!($boxed)), stringify!($unbox_method), concat!("()", stringify!($sig))), JavaType::from_str(stringify!($sig)).unwrap(), &[])
.unwrap().[<$sig:lower>]()
.unwrap()))
}
}
};
($type:ty: $boxed:ident ($sig:ident) [$unbox_method:ident], $($rest:ty: $rest_boxed:ident ($rest_sig:ident) [$unbox_method_rest:ident]),+) => {
jvalue_types!($type: $boxed ($sig) [$unbox_method]);
jvalue_types!($($rest: $rest_boxed ($rest_sig) [$unbox_method_rest]),+);
}
}
jvalue_types! {
jboolean: Boolean (Z) [booleanValue],
jbyte: Byte (B) [byteValue],
jchar: Character (C) [charValue],
jdouble: Double (D) [doubleValue],
jfloat: Float (F) [floatValue],
jint: Integer (I) [intValue],
jlong: Long (J) [longValue],
jshort: Short (S) [shortValue]
}
impl Signature for () {
const SIG_TYPE: &'static str = "V";
}
impl<'env> JavaValue<'env> for () {
fn autobox(self, _env: &JNIEnv<'env>) -> JObject<'env> {
panic!("called `JavaValue::autobox` on unit value")
}
fn unbox(_s: JObject<'env>, _env: &JNIEnv<'env>) -> Self {}
}
impl<'env> Signature for JObject<'env> {
const SIG_TYPE: &'static str = "Ljava/lang/Object;";
}
impl<'env> JavaValue<'env> for JObject<'env> {
fn autobox(self, _env: &JNIEnv<'env>) -> JObject<'env> {
self
}
fn unbox(s: JObject<'env>, _env: &JNIEnv<'env>) -> Self {
s
}
}
impl<'env> JavaValue<'env> for jobject {
fn autobox(self, _env: &JNIEnv<'env>) -> JObject<'env> {
From::from(self)
}
fn unbox(s: JObject<'env>, _env: &JNIEnv<'env>) -> Self {
s.into_inner()
}
}
impl<'env> Signature for JString<'env> {
const SIG_TYPE: &'static str = "Ljava/lang/String;";
}
impl<'env> JavaValue<'env> for JString<'env> {
fn autobox(self, _env: &JNIEnv<'env>) -> JObject<'env> {
Into::into(self)
}
fn unbox(s: JObject<'env>, _env: &JNIEnv<'env>) -> Self {
From::from(s)
}
}
impl<T: Signature> Signature for jni::errors::Result<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> {
fn from(v: JValue<'a>) -> Self {
JValueWrapper(v)
}
}
impl<'a> From<JValueWrapper<'a>> for JValue<'a> {
fn from(v: JValueWrapper<'a>) -> Self {
v.0
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for jboolean {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Bool(b) => Ok(b),
_ => Err(Error::WrongJValueType("bool", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for jbyte {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Byte(b) => Ok(b),
_ => Err(Error::WrongJValueType("byte", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for jchar {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Char(c) => Ok(c),
_ => Err(Error::WrongJValueType("char", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for jdouble {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Double(d) => Ok(d),
_ => Err(Error::WrongJValueType("double", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for jfloat {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Float(f) => Ok(f),
_ => Err(Error::WrongJValueType("float", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for jint {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Int(i) => Ok(i),
_ => Err(Error::WrongJValueType("int", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for jshort {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Short(s) => Ok(s),
_ => Err(Error::WrongJValueType("short", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for jlong {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Long(l) => Ok(l),
_ => Err(Error::WrongJValueType("long", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for () {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Void => Ok(()),
_ => Err(Error::WrongJValueType("void", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for JObject<'a> {
type Error = jni::errors::Error;
fn try_from(value: JValueWrapper<'a>) -> Result<Self, Self::Error> {
match value.0 {
JValue::Object(o) => Ok(o),
_ => Err(Error::WrongJValueType("object", value.0.type_name()).into()),
}
}
}
impl<'a> TryFrom<JValueWrapper<'a>> for JString<'a> {
type Error = jni::errors::Error;
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()),
}
}
}