mod net;
use crate::{FromJava, JnixEnv};
use jni::{
objects::{AutoLocal, JObject, JString, JValue},
signature::{JavaType, Primitive},
sys::{jboolean, jint, jlong, jshort, JNI_FALSE},
};
use std::collections::{HashMap, HashSet};
use std::iter::FromIterator;
impl<'env, 'sub_env, T> FromJava<'env, JValue<'sub_env>> for T
where
'env: 'sub_env,
T: FromJava<'env, JObject<'sub_env>>,
{
const JNI_SIGNATURE: &'static str = T::JNI_SIGNATURE;
fn from_java(env: &JnixEnv<'env>, source: JValue<'sub_env>) -> Self {
match source {
JValue::Object(object) => T::from_java(env, object),
_ => panic!(
"Can't convert non-object Java type. Expected type signature {}",
Self::JNI_SIGNATURE
),
}
}
}
impl<'env, 'sub_env, 'borrow, T> FromJava<'env, AutoLocal<'sub_env, 'borrow>> for T
where
'env: 'sub_env,
'sub_env: 'borrow,
T: for<'inner_borrow> FromJava<'env, JObject<'inner_borrow>>,
{
const JNI_SIGNATURE: &'static str = T::JNI_SIGNATURE;
fn from_java(env: &JnixEnv<'env>, source: AutoLocal<'sub_env, 'borrow>) -> Self {
T::from_java(env, source.as_obj())
}
}
impl<'env> FromJava<'env, jboolean> for bool {
const JNI_SIGNATURE: &'static str = "Z";
fn from_java(_: &JnixEnv<'env>, source: jboolean) -> Self {
source != JNI_FALSE
}
}
impl<'env, 'sub_env> FromJava<'env, JValue<'sub_env>> for bool
where
'env: 'sub_env,
{
const JNI_SIGNATURE: &'static str = "Z";
fn from_java(env: &JnixEnv<'env>, source: JValue<'sub_env>) -> Self {
match source {
JValue::Bool(boolean) => bool::from_java(env, boolean),
_ => panic!("Can't convert Java type, expected a boolean primitive"),
}
}
}
impl<'env> FromJava<'env, jlong> for i64 {
const JNI_SIGNATURE: &'static str = "J";
fn from_java(_: &JnixEnv<'env>, source: jlong) -> Self {
source as i64
}
}
impl<'env, 'sub_env> FromJava<'env, JValue<'sub_env>> for i64
where
'env: 'sub_env,
{
const JNI_SIGNATURE: &'static str = "J";
fn from_java(env: &JnixEnv<'env>, source: JValue<'sub_env>) -> Self {
match source {
JValue::Long(long) => i64::from_java(env, long),
_ => panic!("Can't convert Java type, expected a long primitive"),
}
}
}
impl<'env> FromJava<'env, jint> for i32 {
const JNI_SIGNATURE: &'static str = "I";
fn from_java(_: &JnixEnv<'env>, source: jint) -> Self {
source as i32
}
}
impl<'env, 'sub_env> FromJava<'env, JValue<'sub_env>> for i32
where
'env: 'sub_env,
{
const JNI_SIGNATURE: &'static str = "I";
fn from_java(env: &JnixEnv<'env>, source: JValue<'sub_env>) -> Self {
match source {
JValue::Int(integer) => i32::from_java(env, integer),
_ => panic!("Can't convert Java type, expected an integer primitive"),
}
}
}
impl<'env> FromJava<'env, jshort> for i16 {
const JNI_SIGNATURE: &'static str = "S";
fn from_java(_: &JnixEnv<'env>, source: jshort) -> Self {
source as i16
}
}
impl<'env, 'sub_env> FromJava<'env, JValue<'sub_env>> for i16
where
'env: 'sub_env,
{
const JNI_SIGNATURE: &'static str = "S";
fn from_java(env: &JnixEnv<'env>, source: JValue<'sub_env>) -> Self {
match source {
JValue::Short(short) => i16::from_java(env, short),
_ => panic!("Can't convert Java type, expected a short primitive"),
}
}
}
impl<'env, 'sub_env> FromJava<'env, JString<'sub_env>> for String
where
'env: 'sub_env,
{
const JNI_SIGNATURE: &'static str = "Ljava/lang/String;";
fn from_java(env: &JnixEnv<'env>, source: JString<'sub_env>) -> Self {
String::from(
env.get_string(source)
.expect("Failed to convert from Java String"),
)
}
}
impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for String
where
'env: 'sub_env,
{
const JNI_SIGNATURE: &'static str = "Ljava/lang/String;";
fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
String::from_java(env, JString::from(source))
}
}
impl<'env, 'sub_env, T> FromJava<'env, JObject<'sub_env>> for Option<T>
where
'env: 'sub_env,
T: FromJava<'env, JObject<'sub_env>>,
{
const JNI_SIGNATURE: &'static str = T::JNI_SIGNATURE;
fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
if source.is_null() {
None
} else {
Some(T::from_java(env, source))
}
}
}
impl<'env, 'sub_env, T> FromJava<'env, JString<'sub_env>> for Option<T>
where
'env: 'sub_env,
T: FromJava<'env, JString<'sub_env>>,
{
const JNI_SIGNATURE: &'static str = T::JNI_SIGNATURE;
fn from_java(env: &JnixEnv<'env>, source: JString<'sub_env>) -> Self {
if source.is_null() {
None
} else {
Some(T::from_java(env, source))
}
}
}
impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for Option<i32> {
const JNI_SIGNATURE: &'static str = "Ljava/lang/Integer;";
fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
if source.is_null() {
None
} else {
let class = env.get_class("java/lang/Integer");
let method_id = env
.get_method_id(&class, "intValue", "()I")
.expect("Failed to get method ID for Integer.intValue()");
let return_type = JavaType::Primitive(Primitive::Int);
let int_value = env
.call_method_unchecked(source, method_id, return_type, &[])
.expect("Failed to call Integer.intValue()")
.i()
.expect("Call to Integer.intValue() did not return an int primitive");
Some(int_value)
}
}
}
impl<'env, 'sub_env, T> FromJava<'env, JObject<'sub_env>> for Vec<T>
where
'env: 'sub_env,
T: FromJava<'env, JObject<'sub_env>>,
{
const JNI_SIGNATURE: &'static str = "Ljava/util/ArrayList;";
fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
let class = env.get_class("java/util/ArrayList");
let size_method_id = env
.get_method_id(&class, "size", "()I")
.expect("Failed to get method ID for ArrayList.size()");
let size_return_type = JavaType::Primitive(Primitive::Int);
let item_count = env
.call_method_unchecked(source, size_method_id, size_return_type, &[])
.expect("Failed to call ArrayList.size()")
.i()
.expect("Call to ArrayList.size() did not return an int primitive");
let mut target = Vec::with_capacity(item_count as usize);
let get_method_id = env
.get_method_id(&class, "get", "(I)Ljava/lang/Object;")
.expect("Failed to get method ID for ArrayList.get()");
let get_return_type = JavaType::Object("java/lang/Object".to_owned());
for index in 0..item_count {
let object = env
.call_method_unchecked(
source,
get_method_id,
get_return_type.clone(),
&[JValue::Int(index)],
)
.expect("Failed to call ArrayList.get()")
.l()
.expect("Call to ArrayList.get() did not return an object");
let item = T::from_java(env, object);
target.push(item);
}
target
}
}
impl<'env, 'sub_env, T: Eq + std::hash::Hash> FromJava<'env, JObject<'sub_env>> for HashSet<T>
where
'env: 'sub_env,
T: FromJava<'env, JObject<'sub_env>>,
{
const JNI_SIGNATURE: &'static str = "Ljava/util/HashSet;";
fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
let class = env.get_class("java/util/ArrayList");
let list_object = env
.new_object(&class, "(Ljava/util/Collection;)V", &[JValue::from(source)])
.expect("Failed to create ArrayList object from HashSet");
let vector = Vec::from_java(&env, list_object);
HashSet::from_iter(vector)
}
}
impl<'env, 'sub_env, K, V> FromJava<'env, JObject<'sub_env>> for HashMap<K, V>
where
'env: 'sub_env,
K: FromJava<'env, JObject<'sub_env>> + Eq + std::hash::Hash,
V: FromJava<'env, JObject<'sub_env>>,
{
const JNI_SIGNATURE: &'static str = "Ljava/util/Map;";
fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
let entry_set = env
.call_method(source, "entrySet", "()Ljava/util/Set;", &[])
.expect("Failed to call Map.entrySet()")
.l()
.expect("Entry set should be an object");
let iterator = env
.call_method(entry_set, "iterator", "()Ljava/util/Iterator;", &[])
.expect("Failed to get iterator")
.l()
.expect("Iterator should be an object");
let mut map = HashMap::new();
loop {
let has_next = env
.call_method(iterator, "hasNext", "()Z", &[])
.expect("Failed to call hasNext()")
.z()
.expect("hasNext should return boolean");
if !has_next {
break;
}
let entry = env
.call_method(iterator, "next", "()Ljava/lang/Object;", &[])
.expect("Failed to call next()")
.l()
.expect("next() should return Map.Entry");
let key = env
.call_method(entry, "getKey", "()Ljava/lang/Object;", &[])
.expect("Failed to call getKey()")
.l()
.expect("Key should be object");
let value = env
.call_method(entry, "getValue", "()Ljava/lang/Object;", &[])
.expect("Failed to call getValue()")
.l()
.expect("Value should be object");
let rust_key = K::from_java(env, key);
let rust_value = V::from_java(env, value);
map.insert(rust_key, rust_value);
}
map
}
}