use java_string::*;
use jni::method_calls::call_static_method;
use jni::*;
use jni_sys;
use std;
use std::fmt;
use std::os::raw::c_char;
use std::ptr;
include!("call_jni_method.rs");
include!("generate_class.rs");
#[derive(Debug)]
pub struct String<'env> {
object: Object<'env>,
}
impl<'env> String<'env> {
pub fn empty<'a>(env: &'a JniEnv<'a>, token: &NoException<'a>) -> JavaResult<'a, String<'a>> {
let raw_string = unsafe {
call_nullable_jni_method!(env, NewString, token, ptr::null(), 0 as jni_sys::jsize)?
};
Ok(unsafe { Self::from_raw(env, raw_string) })
}
pub fn new<'a>(
env: &'a JniEnv<'a>,
string: &str,
token: &NoException<'a>,
) -> JavaResult<'a, String<'a>> {
if string.is_empty() {
return Self::empty(env, token);
}
let buffer = to_java_string(string);
let raw_string = unsafe {
call_nullable_jni_method!(env, NewStringUTF, token, buffer.as_ptr() as *const c_char)?
};
Ok(unsafe { Self::from_raw(env, raw_string) })
}
pub fn len(&self, _token: &NoException) -> usize {
let length = unsafe {
call_jni_method!(
self.env(),
GetStringLength,
self.raw_object() as jni_sys::jstring
)
};
length as usize
}
pub fn size(&self, _token: &NoException) -> usize {
let size = unsafe {
call_jni_method!(
self.env(),
GetStringUTFLength,
self.raw_object() as jni_sys::jstring
)
};
size as usize
}
pub fn as_string(&self, token: &NoException) -> std::string::String {
let length = self.len(token);
if length == 0 {
return "".to_owned();
}
let size = self.size(token) + 1; let mut buffer: Vec<u8> = Vec::with_capacity(size);
unsafe {
call_jni_method!(
self.env(),
GetStringUTFRegion,
self.raw_object() as jni_sys::jstring,
0 as jni_sys::jsize,
length as jni_sys::jsize,
buffer.as_mut_ptr() as *mut c_char
);
buffer.set_len(size);
}
from_java_string(buffer.as_slice()).unwrap().into_owned()
}
unsafe fn from_raw<'a>(env: &'a JniEnv<'a>, raw_string: jni_sys::jstring) -> String<'a> {
String {
object: Object::__from_jni(env, raw_string as jni_sys::jobject),
}
}
}
java_class!(
String,
"[`String`](struct.String.html)",
constructors = (),
methods = (),
static_methods = (
doc = "Get the string value of an integer.",
link = "[`String::valueOf(int)` javadoc](https://docs.oracle.com/javase/10/docs/api/java/lang/String.html#valueOf(int))",
java_name = "valueOf",
value_of_int(value: i32) -> String<'env>,
),
);
#[cfg(test)]
mod string_tests {
use super::*;
use jni::testing::*;
use std::mem;
use std::ops::Deref;
fn test_value<'env>(env: &'env JniEnv<'env>, raw_object: jni_sys::jobject) -> String<'env> {
String {
object: test_object(env, raw_object),
}
}
generate_tests!(String, "Ljava/lang/String;");
#[test]
fn empty() {
const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![JniCall::NewString(NewString {
name: ptr::null(),
size: 0,
result: RAW_STRING,
})]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let string = String::empty(&env, &NoException::test()).unwrap();
calls.assert_eq(&string, RAW_STRING);
}
#[test]
fn empty_exception() {
const EXCEPTION: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![
JniCall::NewString(NewString {
name: ptr::null(),
size: 0,
result: ptr::null_mut(),
}),
JniCall::ExceptionOccurred(ExceptionOccurred { result: EXCEPTION }),
JniCall::ExceptionClear(ExceptionClear {}),
]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let exception = String::empty(&env, &NoException::test()).unwrap_err();
calls.assert_eq(&exception, EXCEPTION);
}
#[test]
fn new_empty() {
const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![JniCall::NewString(NewString {
name: ptr::null(),
size: 0,
result: RAW_STRING,
})]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let string = String::new(&env, "", &NoException::test()).unwrap();
calls.assert_eq(&string, RAW_STRING);
}
#[test]
fn new_empty_exception() {
const EXCEPTION: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![
JniCall::NewString(NewString {
name: ptr::null(),
size: 0,
result: ptr::null_mut(),
}),
JniCall::ExceptionOccurred(ExceptionOccurred { result: EXCEPTION }),
JniCall::ExceptionClear(ExceptionClear {}),
]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let exception = String::new(&env, "", &NoException::test()).unwrap_err();
calls.assert_eq(&exception, EXCEPTION);
}
#[test]
fn new() {
const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![JniCall::NewStringUTF(NewStringUTF {
string: "test-string".to_owned(),
result: RAW_STRING,
})]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let string = String::new(&env, "test-string", &NoException::test()).unwrap();
calls.assert_eq(&string, RAW_STRING);
}
#[test]
fn new_exception() {
const EXCEPTION: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![
JniCall::NewStringUTF(NewStringUTF {
string: "test-string".to_owned(),
result: ptr::null_mut(),
}),
JniCall::ExceptionOccurred(ExceptionOccurred { result: EXCEPTION }),
JniCall::ExceptionClear(ExceptionClear {}),
]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let exception = String::new(&env, "test-string", &NoException::test()).unwrap_err();
calls.assert_eq(&exception, EXCEPTION);
}
#[test]
fn len() {
const LENGTH: usize = 17;
const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![JniCall::GetStringLength(GetStringLength {
string: RAW_STRING,
result: 17 as jni_sys::jsize,
})]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let string = unsafe { String::from_raw(&env, RAW_STRING) };
assert_eq!(string.len(&NoException::test()), LENGTH);
}
#[test]
fn size() {
const LENGTH: usize = 17;
const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![JniCall::GetStringUTFLength(GetStringUTFLength {
string: RAW_STRING,
result: 17 as jni_sys::jsize,
})]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let string = unsafe { String::from_raw(&env, RAW_STRING) };
assert_eq!(string.size(&NoException::test()), LENGTH);
}
#[test]
fn as_string() {
const LENGTH: usize = 5;
const SIZE: usize = 11; const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![
JniCall::GetStringLength(GetStringLength {
string: RAW_STRING,
result: LENGTH as jni_sys::jsize,
}),
JniCall::GetStringUTFLength(GetStringUTFLength {
string: RAW_STRING,
result: SIZE as jni_sys::jsize,
}),
JniCall::GetStringUTFRegion(GetStringUTFRegion {
string: RAW_STRING,
start: 0,
len: LENGTH as jni_sys::jsize,
buffer: "test-string".to_owned(),
}),
]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let string = unsafe { String::from_raw(&env, RAW_STRING) };
assert_eq!(string.as_string(&NoException::test()), "test-string");
}
#[test]
fn as_string_empty() {
const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
let calls = test_raw_jni_env!(vec![JniCall::GetStringLength(GetStringLength {
string: RAW_STRING,
result: 0,
})]);
let vm = test_vm(ptr::null_mut());
let env = test_env(&vm, calls.env);
let string = unsafe { String::from_raw(&env, RAW_STRING) };
assert_eq!(string.as_string(&NoException::test()), "");
}
}