use jni_sys::{jboolean, JNI_TRUE};
use std::{borrow::Cow, os::raw::c_char};
use log::warn;
use crate::{errors::*, objects::JString, strings::JNIStr, JNIEnv};
pub struct JavaStr<'local, 'other_local: 'obj_ref, 'obj_ref> {
internal: *const c_char,
obj: &'obj_ref JString<'other_local>,
env: JNIEnv<'local>,
}
impl<'local, 'other_local: 'obj_ref, 'obj_ref> JavaStr<'local, 'other_local, 'obj_ref> {
unsafe fn get_string_utf_chars(
env: &JNIEnv<'_>,
obj: &JString<'_>,
) -> Result<(*const c_char, bool)> {
non_null!(obj, "get_string_utf_chars obj argument");
let mut is_copy: jboolean = 0;
let ptr: *const c_char = jni_non_null_call!(
env.get_raw(),
GetStringUTFChars,
obj.as_raw(),
&mut is_copy as *mut _
);
let is_copy = is_copy == JNI_TRUE;
Ok((ptr, is_copy))
}
unsafe fn release_string_utf_chars(&mut self) -> Result<()> {
non_null!(self.obj, "release_string_utf_chars obj argument");
jni_unchecked!(
self.env.get_raw(),
ReleaseStringUTFChars,
self.obj.as_raw(),
self.internal
);
Ok(())
}
pub fn from_env(env: &JNIEnv<'local>, obj: &'obj_ref JString<'other_local>) -> Result<Self> {
Ok(unsafe {
let (ptr, _) = Self::get_string_utf_chars(env, obj)?;
Self::from_raw(env, obj, ptr)
})
}
pub fn get_raw(&self) -> *const c_char {
self.internal
}
pub fn into_raw(self) -> *const c_char {
let mut _dont_call_drop = std::mem::ManuallyDrop::new(self);
unsafe {
std::ptr::drop_in_place(&mut _dont_call_drop.env);
}
_dont_call_drop.internal
}
pub unsafe fn from_raw(
env: &JNIEnv<'local>,
obj: &'obj_ref JString<'other_local>,
ptr: *const c_char,
) -> Self {
Self {
internal: ptr,
obj,
env: env.unsafe_clone(),
}
}
}
impl<'local, 'other_local: 'obj_ref, 'obj_ref> ::std::ops::Deref
for JavaStr<'local, 'other_local, 'obj_ref>
{
type Target = JNIStr;
fn deref(&self) -> &Self::Target {
self.into()
}
}
impl<'local, 'other_local: 'obj_ref, 'obj_ref: 'java_str, 'java_str>
From<&'java_str JavaStr<'local, 'other_local, 'obj_ref>> for &'java_str JNIStr
{
fn from(other: &'java_str JavaStr) -> &'java_str JNIStr {
unsafe { JNIStr::from_ptr(other.internal) }
}
}
impl<'local, 'other_local: 'obj_ref, 'obj_ref: 'java_str, 'java_str>
From<&'java_str JavaStr<'local, 'other_local, 'obj_ref>> for Cow<'java_str, str>
{
fn from(other: &'java_str JavaStr) -> Cow<'java_str, str> {
let jni_str: &JNIStr = other;
jni_str.into()
}
}
impl<'local, 'other_local: 'obj_ref, 'obj_ref> From<JavaStr<'local, 'other_local, 'obj_ref>>
for String
{
fn from(other: JavaStr) -> String {
let cow: Cow<str> = (&other).into();
cow.into_owned()
}
}
impl<'local, 'other_local: 'obj_ref, 'obj_ref> Drop for JavaStr<'local, 'other_local, 'obj_ref> {
fn drop(&mut self) {
match unsafe { self.release_string_utf_chars() } {
Ok(()) => {}
Err(e) => warn!("error dropping java str: {}", e),
}
}
}