use std::char::{CharTryFromError, DecodeUtf16Error};
use std::convert::{TryFrom, TryInto};
use std::fmt::Debug;
use log::trace;
use crate::signature::JavaType;
use crate::{errors::*, objects::JObject, signature::Primitive, sys::*};
#[cfg(doc)]
use crate::env::Env;
#[allow(missing_docs)]
#[derive(Debug)]
pub enum JValueOwned<'local> {
Object(JObject<'local>),
Byte(jbyte),
Char(jchar),
Short(jshort),
Int(jint),
Long(jlong),
Bool(jboolean),
Float(jfloat),
Double(jdouble),
Void,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub enum JValue<'obj_ref> {
Object(&'obj_ref JObject<'obj_ref>),
Byte(jbyte),
Char(jchar),
Short(jshort),
Int(jint),
Long(jlong),
Bool(jboolean),
Float(jfloat),
Double(jdouble),
Void,
}
impl<'local> JValueOwned<'local> {
pub fn as_jni(&self) -> jvalue {
self.borrow().as_jni()
}
pub fn type_name(&self) -> &'static str {
self.borrow().type_name()
}
pub fn primitive_type(&self) -> Option<Primitive> {
self.borrow().primitive_type()
}
pub fn is_null(&self) -> bool {
matches!(self, Self::Object(obj) if obj.as_raw().is_null())
}
pub fn check_null(self) -> Result<Self> {
match self {
Self::Object(obj) => {
if obj.as_raw().is_null() {
Err(Error::NullPtr("Null Object"))
} else {
Ok(Self::Object(obj))
}
}
_ => Ok(self),
}
}
pub fn l(self) -> Result<JObject<'local>> {
match self {
Self::Object(obj) => Ok(obj),
_ => Err(Error::WrongJValueType("object", self.type_name())),
}
}
#[doc(alias = "l")]
pub fn into_object(self) -> Result<JObject<'local>> {
self.l()
}
pub fn z(self) -> Result<bool> {
self.borrow().z()
}
#[doc(alias = "z")]
pub fn into_bool(self) -> Result<bool> {
self.borrow().z()
}
pub fn b(self) -> Result<jbyte> {
self.borrow().b()
}
#[doc(alias = "b")]
pub fn into_byte(self) -> Result<jbyte> {
self.borrow().b()
}
pub fn c(self) -> Result<jchar> {
self.borrow().c()
}
#[doc(alias = "c")]
pub fn into_char(self) -> Result<jchar> {
self.borrow().c()
}
#[deprecated = "Use `into_char` to get the raw Java jchar, and then (attempt to) convert it to a Rust char using `char_from_java` if needed. This method is likely to fail and is not recommended."]
pub fn c_char(self) -> Result<char> {
let char = self.c()?;
char_from_java(char).map_err(|source| Error::InvalidUtf16 { source })
}
pub fn d(self) -> Result<jdouble> {
self.borrow().d()
}
#[doc(alias = "d")]
pub fn into_double(self) -> Result<jdouble> {
self.borrow().d()
}
pub fn f(self) -> Result<jfloat> {
self.borrow().f()
}
#[doc(alias = "f")]
pub fn into_float(self) -> Result<jfloat> {
self.borrow().f()
}
pub fn i(self) -> Result<jint> {
self.borrow().i()
}
#[doc(alias = "i")]
pub fn into_int(self) -> Result<jint> {
self.borrow().i()
}
pub fn i_char(self) -> Result<char> {
self.i_into_char()
}
#[doc(alias = "i_char")]
pub fn i_into_char(self) -> Result<char> {
let char = self.i()?;
char_from_java_int(char).map_err(|source| Error::InvalidUtf32 { char, source })
}
pub fn j(self) -> Result<jlong> {
self.borrow().j()
}
#[doc(alias = "j")]
pub fn into_long(self) -> Result<jlong> {
self.borrow().j()
}
pub fn s(self) -> Result<jshort> {
self.borrow().s()
}
#[doc(alias = "s")]
pub fn into_short(self) -> Result<jshort> {
self.borrow().s()
}
pub fn v(self) -> Result<()> {
self.borrow().v()
}
#[doc(alias = "v")]
pub fn into_void(self) -> Result<()> {
self.borrow().v()
}
#[inline]
pub fn borrow(&'_ self) -> JValue<'_> {
match self {
Self::Object(o) => JValue::Object(o),
Self::Byte(v) => JValue::Byte(*v),
Self::Char(v) => JValue::Char(*v),
Self::Short(v) => JValue::Short(*v),
Self::Int(v) => JValue::Int(*v),
Self::Long(v) => JValue::Long(*v),
Self::Bool(v) => JValue::Bool(*v),
Self::Float(v) => JValue::Float(*v),
Self::Double(v) => JValue::Double(*v),
Self::Void => JValue::Void,
}
}
}
impl<'obj_ref> JValue<'obj_ref> {
pub fn as_jni(&self) -> jvalue {
let val: jvalue = match self {
Self::Object(obj) => jvalue { l: obj.as_raw() },
Self::Byte(byte) => jvalue { b: *byte },
Self::Char(char) => jvalue { c: *char },
Self::Short(short) => jvalue { s: *short },
Self::Int(int) => jvalue { i: *int },
Self::Long(long) => jvalue { j: *long },
Self::Bool(boolean) => jvalue { b: *boolean as i8 },
Self::Float(float) => jvalue { f: *float },
Self::Double(double) => jvalue { d: *double },
Self::Void => jvalue {
l: ::std::ptr::null_mut(),
},
};
trace!("converted {:?} to jvalue {:?}", self, unsafe {
::std::mem::transmute::<jvalue, u64>(val)
});
val
}
#[deprecated = "Use `as_jni` instead."]
pub fn to_jni(self) -> jvalue {
self.as_jni()
}
pub fn type_name(&self) -> &'static str {
match *self {
Self::Void => "void",
Self::Object(_) => "object",
Self::Byte(_) => "byte",
Self::Char(_) => "char",
Self::Short(_) => "short",
Self::Int(_) => "int",
Self::Long(_) => "long",
Self::Bool(_) => "bool",
Self::Float(_) => "float",
Self::Double(_) => "double",
}
}
pub fn java_type(&self) -> JavaType {
match *self {
Self::Object(_) => JavaType::Object,
Self::Void => JavaType::Primitive(Primitive::Void),
Self::Byte(_) => JavaType::Primitive(Primitive::Byte),
Self::Char(_) => JavaType::Primitive(Primitive::Char),
Self::Short(_) => JavaType::Primitive(Primitive::Short),
Self::Int(_) => JavaType::Primitive(Primitive::Int),
Self::Long(_) => JavaType::Primitive(Primitive::Long),
Self::Bool(_) => JavaType::Primitive(Primitive::Boolean),
Self::Float(_) => JavaType::Primitive(Primitive::Float),
Self::Double(_) => JavaType::Primitive(Primitive::Double),
}
}
pub fn primitive_type(&self) -> Option<Primitive> {
Some(match *self {
Self::Object(_) => return None,
Self::Void => Primitive::Void,
Self::Byte(_) => Primitive::Byte,
Self::Char(_) => Primitive::Char,
Self::Short(_) => Primitive::Short,
Self::Int(_) => Primitive::Int,
Self::Long(_) => Primitive::Long,
Self::Bool(_) => Primitive::Boolean,
Self::Float(_) => Primitive::Float,
Self::Double(_) => Primitive::Double,
})
}
pub fn l(self) -> Result<&'obj_ref JObject<'obj_ref>> {
match self {
Self::Object(obj) => Ok(obj),
_ => Err(Error::WrongJValueType("object", self.type_name())),
}
}
pub fn z(self) -> Result<bool> {
match self {
Self::Bool(b) => Ok(b == JNI_TRUE),
_ => Err(Error::WrongJValueType("bool", self.type_name())),
}
}
pub fn b(self) -> Result<jbyte> {
match self {
Self::Byte(b) => Ok(b),
_ => Err(Error::WrongJValueType("jbyte", self.type_name())),
}
}
pub fn c(self) -> Result<jchar> {
match self {
Self::Char(b) => Ok(b),
_ => Err(Error::WrongJValueType("jchar", self.type_name())),
}
}
pub fn c_char(self) -> Result<char> {
let char = self.c()?;
char_from_java(char).map_err(|source| Error::InvalidUtf16 { source })
}
pub fn d(self) -> Result<jdouble> {
match self {
Self::Double(b) => Ok(b),
_ => Err(Error::WrongJValueType("jdouble", self.type_name())),
}
}
pub fn f(self) -> Result<jfloat> {
match self {
Self::Float(b) => Ok(b),
_ => Err(Error::WrongJValueType("jfloat", self.type_name())),
}
}
pub fn i(self) -> Result<jint> {
match self {
Self::Int(b) => Ok(b),
_ => Err(Error::WrongJValueType("jint", self.type_name())),
}
}
pub fn i_char(self) -> Result<char> {
let char = self.i()?;
char_from_java_int(char).map_err(|source| Error::InvalidUtf32 { char, source })
}
pub fn j(self) -> Result<jlong> {
match self {
Self::Long(b) => Ok(b),
_ => Err(Error::WrongJValueType("jlong", self.type_name())),
}
}
pub fn s(self) -> Result<jshort> {
match self {
Self::Short(b) => Ok(b),
_ => Err(Error::WrongJValueType("jshort", self.type_name())),
}
}
pub fn v(self) -> Result<()> {
match self {
Self::Void => Ok(()),
_ => Err(Error::WrongJValueType("void", self.type_name())),
}
}
pub fn int_from_char(char: char) -> Self {
Self::Int(char_to_java_int(char))
}
}
impl<'obj_ref> From<&'obj_ref JValueOwned<'obj_ref>> for JValue<'obj_ref> {
fn from(other: &'obj_ref JValueOwned) -> Self {
other.borrow()
}
}
impl<'local, T: Into<JObject<'local>>> From<T> for JValueOwned<'local> {
fn from(other: T) -> Self {
Self::Object(other.into())
}
}
impl<'obj_ref, T: AsRef<JObject<'obj_ref>>> From<&'obj_ref T> for JValue<'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> {
value.l()
}
}
impl From<jboolean> for JValueOwned<'_> {
fn from(other: jboolean) -> Self {
Self::Bool(other)
}
}
impl TryFrom<JValueOwned<'_>> for jboolean {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.borrow().try_into()
}
}
impl From<jboolean> for JValue<'_> {
fn from(other: jboolean) -> Self {
Self::Bool(other)
}
}
impl TryFrom<JValue<'_>> for jboolean {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
match value {
JValue::Bool(b) => Ok(b),
_ => Err(Error::WrongJValueType("bool", value.type_name())),
}
}
}
impl From<jchar> for JValueOwned<'_> {
fn from(other: jchar) -> Self {
Self::Char(other)
}
}
impl TryFrom<JValueOwned<'_>> for jchar {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.c()
}
}
impl From<jchar> for JValue<'_> {
fn from(other: jchar) -> Self {
Self::Char(other)
}
}
impl TryFrom<JValue<'_>> for jchar {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
value.c()
}
}
impl TryFrom<char> for JValueOwned<'_> {
type Error = CharToJavaError;
fn try_from(value: char) -> std::result::Result<Self, Self::Error> {
Ok(Self::Char(char_to_java(value)?))
}
}
impl TryFrom<char> for JValue<'_> {
type Error = CharToJavaError;
fn try_from(value: char) -> std::result::Result<Self, Self::Error> {
Ok(Self::Char(char_to_java(value)?))
}
}
pub fn char_from_java(char: jchar) -> std::result::Result<char, DecodeUtf16Error> {
char::decode_utf16([char]).next().unwrap()
}
pub fn char_to_java(char: char) -> std::result::Result<jchar, CharToJavaError> {
if char.len_utf16() != 1 {
return Err(CharToJavaError { char });
}
let mut buf = [0u16; 1];
let buf: &mut [u16] = char.encode_utf16(&mut buf);
Ok(buf[0])
}
impl From<jshort> for JValueOwned<'_> {
fn from(other: jshort) -> Self {
Self::Short(other)
}
}
impl TryFrom<JValueOwned<'_>> for jshort {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.s()
}
}
impl From<jshort> for JValue<'_> {
fn from(other: jshort) -> Self {
Self::Short(other)
}
}
impl TryFrom<JValue<'_>> for jshort {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
value.s()
}
}
impl From<jfloat> for JValueOwned<'_> {
fn from(other: jfloat) -> Self {
Self::Float(other)
}
}
impl TryFrom<JValueOwned<'_>> for jfloat {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.f()
}
}
impl From<jfloat> for JValue<'_> {
fn from(other: jfloat) -> Self {
Self::Float(other)
}
}
impl TryFrom<JValue<'_>> for jfloat {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
value.f()
}
}
impl From<jdouble> for JValueOwned<'_> {
fn from(other: jdouble) -> Self {
Self::Double(other)
}
}
impl TryFrom<JValueOwned<'_>> for jdouble {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.d()
}
}
impl From<jdouble> for JValue<'_> {
fn from(other: jdouble) -> Self {
Self::Double(other)
}
}
impl TryFrom<JValue<'_>> for jdouble {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
value.d()
}
}
impl From<jint> for JValueOwned<'_> {
fn from(other: jint) -> Self {
Self::Int(other)
}
}
impl TryFrom<JValueOwned<'_>> for jint {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.i()
}
}
impl From<jint> for JValue<'_> {
fn from(other: jint) -> Self {
Self::Int(other)
}
}
impl TryFrom<JValue<'_>> for jint {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
value.i()
}
}
pub fn char_to_java_int(char: char) -> jint {
u32::from(char) as jint
}
pub fn char_from_java_int(jint: jint) -> std::result::Result<char, CharTryFromError> {
char::try_from(jint as u32)
}
impl From<jlong> for JValueOwned<'_> {
fn from(other: jlong) -> Self {
Self::Long(other)
}
}
impl TryFrom<JValueOwned<'_>> for jlong {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.j()
}
}
impl From<jlong> for JValue<'_> {
fn from(other: jlong) -> Self {
Self::Long(other)
}
}
impl TryFrom<JValue<'_>> for jlong {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
value.j()
}
}
impl From<jbyte> for JValueOwned<'_> {
fn from(other: jbyte) -> Self {
Self::Byte(other)
}
}
impl TryFrom<JValueOwned<'_>> for jbyte {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.b()
}
}
impl From<jbyte> for JValue<'_> {
fn from(other: jbyte) -> Self {
Self::Byte(other)
}
}
impl TryFrom<JValue<'_>> for jbyte {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
value.b()
}
}
impl From<()> for JValueOwned<'_> {
fn from(_: ()) -> Self {
Self::Void
}
}
impl TryFrom<JValueOwned<'_>> for () {
type Error = Error;
fn try_from(value: JValueOwned) -> Result<Self> {
value.v()
}
}
impl From<()> for JValue<'_> {
fn from(_: ()) -> Self {
Self::Void
}
}
impl TryFrom<JValue<'_>> for () {
type Error = Error;
fn try_from(value: JValue) -> Result<Self> {
value.v()
}
}