jnix 0.5.3

High-level extensions to help with the usage of JNI in Rust code
Documentation
use crate::{FromJava, JnixEnv};
use jni::{
    objects::JObject,
    signature::{JavaType, Primitive},
};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

fn read_inet_address_octets<'env, 'o>(env: &JnixEnv<'env>, source: JObject<'o>) -> JObject<'env>
where
    'o: 'env,
{
    let class = env.get_class("java/net/InetAddress");
    let method_id = env
        .get_method_id(&class, "getAddress", "()[B")
        .expect("Failed to get method ID for InetAddress.getAddress()");
    let return_type = JavaType::Array(Box::new(JavaType::Primitive(Primitive::Byte)));

    env.call_method_unchecked(source, method_id, return_type, &[])
        .expect("Failed to call InetAddress.getAddress()")
        .l()
        .expect("Call to InetAddress.getAddress() did not return an object")
}

fn address_from_octets<'env, 'o, A, B>(env: &JnixEnv<'env>, octets: JObject<'o>, mut buffer: B) -> A
where
    'o: 'env,
    A: From<B>,
    B: AsMut<[u8]>,
{
    let mut signed_octets = [0i8; 16];
    let buffer_octets = buffer.as_mut();
    let buffer_size = buffer_octets.len();

    env.get_byte_array_region(octets.into_inner(), 0, &mut signed_octets[..buffer_size])
        .expect("Failed to read octets returned by InetAddress.getAddress()");

    for index in 0..buffer_size {
        buffer_octets[index] = signed_octets[index] as u8;
    }

    A::from(buffer)
}

impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for Ipv4Addr
where
    'env: 'sub_env,
{
    const JNI_SIGNATURE: &'static str = "Ljava/net/Inet4Address;";

    fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
        let octets = read_inet_address_octets(env, source);

        address_from_octets(env, octets, [0u8; 4])
    }
}

impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for Ipv6Addr
where
    'env: 'sub_env,
{
    const JNI_SIGNATURE: &'static str = "Ljava/net/Inet6Address;";

    fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
        let octets = read_inet_address_octets(env, source);

        address_from_octets(env, octets, [0u8; 16])
    }
}

impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for IpAddr
where
    'env: 'sub_env,
{
    const JNI_SIGNATURE: &'static str = "Ljava/net/InetAddress;";

    fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
        let octets = read_inet_address_octets(env, source);
        let octet_count = env
            .get_array_length(octets.into_inner())
            .expect("Failed to get length of byte array returned by InetAddress.getAddress()");

        match octet_count {
            4 => address_from_octets(env, octets, [0u8; 4]),
            16 => address_from_octets(env, octets, [0u8; 16]),
            count => panic!(
                "Invalid number of octets returned by InetAddress.getAddress(): {}",
                count
            ),
        }
    }
}