jdbc 0.1.0

Rust bindings to the Java Jdbc.
Documentation
use jni::{
    errors::Error,
    objects::{JObject, JValueGen},
    signature::ReturnType,
    JNIEnv,
};
use log::error;

#[inline(always)]
pub fn delete_value<'a>(env: &mut JNIEnv<'a>, val: JValueGen<JObject<'_>>) -> Result<(), Error> {
    if let JValueGen::Object(obj) = val {
        env.delete_local_ref(obj)?
    }
    Ok(())
}

#[inline(always)]
pub fn auto_close<'a>(env: &mut JNIEnv<'a>, obj: &JObject<'a>) -> Result<(), Error> {
    let autoclose = env.find_class("java/lang/AutoCloseable")?;
    if !env.is_instance_of(obj, &autoclose)? {
        return Ok(());
    }
    let method = env.get_method_id(autoclose, "close", "()V")?;

    let data = unsafe { env.call_method_unchecked(obj, method, ReturnType::Object, &[]) };
    if let Err(err) = data {
        error!("Resource closing failed. {}", err);
    }
    Ok(())
}

#[inline(always)]
pub fn get_class_name<'a>(env: &mut JNIEnv<'a>, obj: &JObject<'a>) -> Result<String, Error> {
    let obj_class = JObject::from(env.get_object_class(obj)?);
    let class = env.find_class("java/lang/Class")?;
    let method = env.get_method_id(&class, "getName", "()Ljava.lang.String;")?;

    let name = unsafe { env.call_method_unchecked(&obj_class, method, ReturnType::Object, &[])? };

    env.delete_local_ref(obj_class)?;
    env.delete_local_ref(class)?;
    match name {
        JValueGen::Object(name) => cast::obj_cast_string(env, name),
        _ => Err(Error::JavaException),
    }
}

pub mod cast {
    use jni::errors::Error;
    use jni::objects::AutoLocal;
    use jni::signature::{Primitive, ReturnType};
    use jni::sys::{jvalue, JNI_TRUE};
    use jni::{
        objects::{JObject, JString, JValueGen},
        JNIEnv,
    };

    pub fn bool_to_jvalue(value: bool) -> jvalue {
        let value = match value {
            true => jni::sys::JNI_TRUE,
            false => jni::sys::JNI_FALSE,
        };
        jvalue { z: value }
    }

    pub fn jvalue_to_bool(value: jvalue) -> bool {
        unsafe {
            match value {
                jvalue { z } => z == jni::sys::JNI_TRUE,
            }
        }
    }

    pub fn value_cast_string<'a>(
        env: &mut JNIEnv<'a>,
        obj: JValueGen<JObject<'a>>,
    ) -> Result<String, Error> {
        if let JValueGen::Object(obj) = obj {
            if obj.is_null() {
                return Err(Error::NullPtr("java.lang.NullPointerException"));
            }
            return obj_cast_string(env, obj);
        }
        Err(Error::JavaException)
    }

    pub fn value_cast_timestamp_millis<'a>(
        env: &mut JNIEnv<'a>,
        obj: JValueGen<JObject<'a>>,
    ) -> Result<i64, Error> {
        if let JValueGen::Object(obj) = obj {
            if obj.is_null() {
                return Err(Error::NullPtr("java.lang.NullPointerException"));
            }
            let class = AutoLocal::new(env.find_class("java/util/Date")?, &env);
            let method = env.get_method_id(&class, "getTime", "()J")?;
            unsafe {
                let value = env.call_method_unchecked(
                    &obj,
                    method,
                    ReturnType::Primitive(Primitive::Long),
                    &[],
                )?;
                env.delete_local_ref(obj)?;
                return value_cast_i64(value);
            }
        }
        return Err(Error::JavaException);
    }

    use crate::value_cast;
    value_cast!(JValueGen::Char, u16, value_cast_char);
    value_cast!(JValueGen::Bool, bool, value_cast_bool);
    value_cast!(JValueGen::Short, i16, value_cast_i16);
    value_cast!(JValueGen::Int, i32, value_cast_i32);
    value_cast!(JValueGen::Long, i64, value_cast_i64);
    value_cast!(JValueGen::Float, f32, value_cast_f32);
    value_cast!(JValueGen::Double, f64, value_cast_f64);

    #[macro_export]
    macro_rules! value_cast {
        (JValueGen::Bool,$return_type:tt,$fun_name:ident) => {
            pub fn $fun_name<'a>(obj: JValueGen<JObject<'a>>) -> Result<$return_type, Error> {
                if let JValueGen::Bool(val) = obj {
                    return Ok(val == JNI_TRUE);
                }
                Err(Error::JavaException)
            }
        };
        ($type:path,$return_type:tt,$fun_name:ident) => {
            pub fn $fun_name<'a>(obj: JValueGen<JObject<'a>>) -> Result<$return_type, Error> {
                if let $type(val) = obj {
                    return Ok(val);
                }
                Err(Error::JavaException)
            }
        };
    }

    pub fn obj_cast_string<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Result<String, Error> {
        let name = JString::from(obj);
        let name_str = env.get_string(&name)?;
        let string = String::from(name_str);
        env.delete_local_ref(name)?;
        Ok(string)
    }
}

pub mod call {
    use jni::{
        objects::{JMethodID, JObject, JValueGen},
        signature::{Primitive, ReturnType},
        JNIEnv,
    };

    use crate::errors::Error;

    #[inline(always)]
    pub fn get_int<'a>(
        env: &mut JNIEnv<'a>,
        obj: &JObject<'a>,
        method: &JMethodID,
    ) -> Result<i32, Error> {
        let int = unsafe {
            env.call_method_unchecked(obj, method, ReturnType::Primitive(Primitive::Int), &[])?
        };
        if let JValueGen::Int(count) = int {
            return Ok(count);
        }
        return Err(Error::ImpossibleError);
    }

    #[inline(always)]
    pub fn get_bool<'a>(
        env: &mut JNIEnv<'a>,
        obj: &JObject<'a>,
        method: &JMethodID,
    ) -> Result<bool, Error> {
        let bool = unsafe {
            env.call_method_unchecked(obj, method, ReturnType::Primitive(Primitive::Boolean), &[])?
        };
        if let JValueGen::Bool(bool) = bool {
            return Ok(bool > 0);
        }
        return Err(Error::ImpossibleError);
    }
}