use jni_sys::{JNI_TRUE, jboolean};
use std::{borrow::Cow, marker::PhantomData, os::raw::c_char};
use log::warn;
use crate::{
Env, JavaVM,
errors::*,
objects::{JString, Reference},
strings::{JNIStr, JNIString},
};
#[cfg(doc)]
use ::{
std::ffi::{CStr, CString},
std::string::ToString as _,
};
pub struct MUTF8Chars<'local, StringRef>
where
StringRef: AsRef<JString<'local>> + Reference,
{
obj: StringRef,
chars: *const c_char,
is_copy: bool,
_lifetime: PhantomData<&'local ()>,
}
impl<'local, StringRef> std::fmt::Debug for MUTF8Chars<'local, StringRef>
where
StringRef: AsRef<JString<'local>> + Reference,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MUTF8Chars")
.field("obj", self.obj.as_ref())
.field("chars", &self.chars)
.field("is_copy", &self.is_copy)
.finish()
}
}
#[deprecated(note = "Renamed to MUTF8Chars, use JString::mutf8_chars() to get it")]
pub type JavaStr<'local, StringRef> = MUTF8Chars<'local, StringRef>;
impl<'local, StringRef> MUTF8Chars<'local, StringRef>
where
StringRef: AsRef<JString<'local>> + Reference,
{
pub(crate) fn from_get_string_utf_chars(env: &Env<'_>, obj: StringRef) -> Result<Self> {
let obj = null_check!(obj, "get_string_utf_chars obj argument")?;
unsafe {
let mut is_copy: jboolean = false;
let ptr: *const c_char = jni_call_only_check_null_ret!(
env,
v1_1,
GetStringUTFChars,
obj.as_raw(),
&mut is_copy as *mut _
)?;
let is_copy = is_copy == JNI_TRUE;
Ok(Self {
obj,
chars: ptr,
is_copy,
_lifetime: PhantomData,
})
}
}
pub fn into_raw(self) -> (*const c_char, bool) {
let _dont_call_drop = std::mem::ManuallyDrop::new(self);
(_dont_call_drop.chars, _dont_call_drop.is_copy)
}
pub unsafe fn from_raw(
_env: &Env<'_>,
obj: StringRef,
ptr: *const c_char,
is_copy: bool,
) -> Self {
Self {
obj,
chars: ptr,
is_copy,
_lifetime: PhantomData,
}
}
pub fn is_copy(&self) -> bool {
self.is_copy
}
}
impl<'local, StringRef> std::fmt::Display for MUTF8Chars<'local, StringRef>
where
StringRef: AsRef<JString<'local>> + Reference,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let jni_str: &JNIStr = self;
jni_str.fmt(f)
}
}
impl<'local, StringRef> ::std::ops::Deref for MUTF8Chars<'local, StringRef>
where
StringRef: AsRef<JString<'local>> + Reference,
{
type Target = JNIStr;
fn deref(&self) -> &Self::Target {
self.into()
}
}
impl<'local, 'java_str, StringRef> From<&'java_str MUTF8Chars<'local, StringRef>>
for &'java_str JNIStr
where
StringRef: AsRef<JString<'local>> + Reference,
{
fn from(other: &'java_str MUTF8Chars<'local, StringRef>) -> &'java_str JNIStr {
unsafe { JNIStr::from_ptr(other.chars) }
}
}
impl<'local, StringRef> From<MUTF8Chars<'local, StringRef>> for JNIString
where
StringRef: AsRef<JString<'local>> + Reference,
{
fn from(other: MUTF8Chars<'local, StringRef>) -> JNIString {
let jni_str: &JNIStr = &other;
jni_str.to_owned()
}
}
impl<'local, 'java_str, StringRef> From<&'java_str MUTF8Chars<'local, StringRef>>
for Cow<'java_str, str>
where
StringRef: AsRef<JString<'local>> + Reference,
{
fn from(other: &'java_str MUTF8Chars<'local, StringRef>) -> Cow<'java_str, str> {
let jni_str: &JNIStr = other;
jni_str.into()
}
}
impl<'local, StringRef> From<MUTF8Chars<'local, StringRef>> for String
where
StringRef: AsRef<JString<'local>> + Reference,
{
fn from(other: MUTF8Chars<'local, StringRef>) -> String {
let cow: Cow<str> = (&other).into();
cow.into_owned()
}
}
impl<'local, StringRef> Drop for MUTF8Chars<'local, StringRef>
where
StringRef: AsRef<JString<'local>> + Reference,
{
fn drop(&mut self) {
unsafe fn release_string_utf_chars(
obj: jni_sys::jobject,
chars: *const c_char,
) -> Result<()> {
JavaVM::singleton()?.with_top_local_frame(|env| {
unsafe {
ex_safe_jni_call_no_post_check_ex!(env, v1_1, ReleaseStringUTFChars, obj, chars)
};
Ok(())
})
}
match unsafe { release_string_utf_chars(self.obj.as_raw(), self.chars) } {
Ok(()) => {}
Err(e) => warn!("error dropping java str: {}", e),
}
}
}
impl<'local, StringRef> AsRef<JNIStr> for MUTF8Chars<'local, StringRef>
where
StringRef: AsRef<JString<'local>> + Reference,
{
fn as_ref(&self) -> &JNIStr {
self
}
}