1use java_string::*;
2use jni::method_calls::call_static_method;
3use jni::*;
4use jni_sys;
5use std;
6use std::fmt;
7use std::os::raw::c_char;
8use std::ptr;
9
10include!("call_jni_method.rs");
11include!("generate_class.rs");
12
13#[derive(Debug)]
18pub struct String<'env> {
19 object: Object<'env>,
20}
21
22impl<'env> String<'env> {
23 pub fn empty<'a>(env: &'a JniEnv<'a>, token: &NoException<'a>) -> JavaResult<'a, String<'a>> {
27 let raw_string = unsafe {
30 call_nullable_jni_method!(env, NewString, token, ptr::null(), 0 as jni_sys::jsize)?
31 };
32 Ok(unsafe { Self::from_raw(env, raw_string) })
34 }
35
36 pub fn new<'a>(
40 env: &'a JniEnv<'a>,
41 string: &str,
42 token: &NoException<'a>,
43 ) -> JavaResult<'a, String<'a>> {
44 if string.is_empty() {
45 return Self::empty(env, token);
46 }
47
48 let buffer = to_java_string(string);
49 let raw_string = unsafe {
52 call_nullable_jni_method!(env, NewStringUTF, token, buffer.as_ptr() as *const c_char)?
53 };
54 Ok(unsafe { Self::from_raw(env, raw_string) })
56 }
57
58 pub fn len(&self, _token: &NoException) -> usize {
62 let length = unsafe {
64 call_jni_method!(
65 self.env(),
66 GetStringLength,
67 self.raw_object() as jni_sys::jstring
68 )
69 };
70 length as usize
71 }
72
73 pub fn size(&self, _token: &NoException) -> usize {
77 let size = unsafe {
79 call_jni_method!(
80 self.env(),
81 GetStringUTFLength,
82 self.raw_object() as jni_sys::jstring
83 )
84 };
85 size as usize
86 }
87
88 pub fn as_string(&self, token: &NoException) -> std::string::String {
95 let length = self.len(token);
96 if length == 0 {
97 return "".to_owned();
98 }
99
100 let size = self.size(token) + 1; let mut buffer: Vec<u8> = Vec::with_capacity(size);
102 unsafe {
104 call_jni_method!(
105 self.env(),
106 GetStringUTFRegion,
107 self.raw_object() as jni_sys::jstring,
108 0 as jni_sys::jsize,
109 length as jni_sys::jsize,
110 buffer.as_mut_ptr() as *mut c_char
111 );
112 buffer.set_len(size);
113 }
114 from_java_string(buffer.as_slice()).unwrap().into_owned()
115 }
116
117 unsafe fn from_raw<'a>(env: &'a JniEnv<'a>, raw_string: jni_sys::jstring) -> String<'a> {
119 String {
120 object: Object::__from_jni(env, raw_string as jni_sys::jobject),
121 }
122 }
123}
124
125java_class!(
126 String,
127 "[`String`](struct.String.html)",
128 constructors = (),
129 methods = (),
130 static_methods = (
131 doc = "Get the string value of an integer.",
132 link = "[`String::valueOf(int)` javadoc](https://docs.oracle.com/javase/10/docs/api/java/lang/String.html#valueOf(int))",
133 java_name = "valueOf",
134 value_of_int(value: i32) -> String<'env>,
135 ),
136);
137
138#[cfg(test)]
139mod string_tests {
140 use super::*;
141 use jni::testing::*;
142 use std::mem;
143 use std::ops::Deref;
144
145 fn test_value<'env>(env: &'env JniEnv<'env>, raw_object: jni_sys::jobject) -> String<'env> {
146 String {
147 object: test_object(env, raw_object),
148 }
149 }
150
151 generate_tests!(String, "Ljava/lang/String;");
152
153 #[test]
154 fn empty() {
155 const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
156 let calls = test_raw_jni_env!(vec![JniCall::NewString(NewString {
157 name: ptr::null(),
158 size: 0,
159 result: RAW_STRING,
160 })]);
161 let vm = test_vm(ptr::null_mut());
162 let env = test_env(&vm, calls.env);
163 let string = String::empty(&env, &NoException::test()).unwrap();
164 calls.assert_eq(&string, RAW_STRING);
165 }
166
167 #[test]
168 fn empty_exception() {
169 const EXCEPTION: jni_sys::jobject = 0x2835 as jni_sys::jobject;
170 let calls = test_raw_jni_env!(vec![
171 JniCall::NewString(NewString {
172 name: ptr::null(),
173 size: 0,
174 result: ptr::null_mut(),
175 }),
176 JniCall::ExceptionOccurred(ExceptionOccurred { result: EXCEPTION }),
177 JniCall::ExceptionClear(ExceptionClear {}),
178 ]);
179 let vm = test_vm(ptr::null_mut());
180 let env = test_env(&vm, calls.env);
181 let exception = String::empty(&env, &NoException::test()).unwrap_err();
182 calls.assert_eq(&exception, EXCEPTION);
183 }
184
185 #[test]
186 fn new_empty() {
187 const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
188 let calls = test_raw_jni_env!(vec![JniCall::NewString(NewString {
189 name: ptr::null(),
190 size: 0,
191 result: RAW_STRING,
192 })]);
193 let vm = test_vm(ptr::null_mut());
194 let env = test_env(&vm, calls.env);
195 let string = String::new(&env, "", &NoException::test()).unwrap();
196 calls.assert_eq(&string, RAW_STRING);
197 }
198
199 #[test]
200 fn new_empty_exception() {
201 const EXCEPTION: jni_sys::jobject = 0x2835 as jni_sys::jobject;
202 let calls = test_raw_jni_env!(vec![
203 JniCall::NewString(NewString {
204 name: ptr::null(),
205 size: 0,
206 result: ptr::null_mut(),
207 }),
208 JniCall::ExceptionOccurred(ExceptionOccurred { result: EXCEPTION }),
209 JniCall::ExceptionClear(ExceptionClear {}),
210 ]);
211 let vm = test_vm(ptr::null_mut());
212 let env = test_env(&vm, calls.env);
213 let exception = String::new(&env, "", &NoException::test()).unwrap_err();
214 calls.assert_eq(&exception, EXCEPTION);
215 }
216
217 #[test]
218 fn new() {
219 const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
220 let calls = test_raw_jni_env!(vec![JniCall::NewStringUTF(NewStringUTF {
221 string: "test-string".to_owned(),
222 result: RAW_STRING,
223 })]);
224 let vm = test_vm(ptr::null_mut());
225 let env = test_env(&vm, calls.env);
226 let string = String::new(&env, "test-string", &NoException::test()).unwrap();
227 calls.assert_eq(&string, RAW_STRING);
228 }
229
230 #[test]
231 fn new_exception() {
232 const EXCEPTION: jni_sys::jobject = 0x2835 as jni_sys::jobject;
233 let calls = test_raw_jni_env!(vec![
234 JniCall::NewStringUTF(NewStringUTF {
235 string: "test-string".to_owned(),
236 result: ptr::null_mut(),
237 }),
238 JniCall::ExceptionOccurred(ExceptionOccurred { result: EXCEPTION }),
239 JniCall::ExceptionClear(ExceptionClear {}),
240 ]);
241 let vm = test_vm(ptr::null_mut());
242 let env = test_env(&vm, calls.env);
243 let exception = String::new(&env, "test-string", &NoException::test()).unwrap_err();
244 calls.assert_eq(&exception, EXCEPTION);
245 }
246
247 #[test]
248 fn len() {
249 const LENGTH: usize = 17;
250 const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
251 let calls = test_raw_jni_env!(vec![JniCall::GetStringLength(GetStringLength {
252 string: RAW_STRING,
253 result: 17 as jni_sys::jsize,
254 })]);
255 let vm = test_vm(ptr::null_mut());
256 let env = test_env(&vm, calls.env);
257 let string = unsafe { String::from_raw(&env, RAW_STRING) };
258 assert_eq!(string.len(&NoException::test()), LENGTH);
259 }
260
261 #[test]
262 fn size() {
263 const LENGTH: usize = 17;
264 const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
265 let calls = test_raw_jni_env!(vec![JniCall::GetStringUTFLength(GetStringUTFLength {
266 string: RAW_STRING,
267 result: 17 as jni_sys::jsize,
268 })]);
269 let vm = test_vm(ptr::null_mut());
270 let env = test_env(&vm, calls.env);
271 let string = unsafe { String::from_raw(&env, RAW_STRING) };
272 assert_eq!(string.size(&NoException::test()), LENGTH);
273 }
274
275 #[test]
276 fn as_string() {
277 const LENGTH: usize = 5;
278 const SIZE: usize = 11; const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
280 let calls = test_raw_jni_env!(vec![
281 JniCall::GetStringLength(GetStringLength {
282 string: RAW_STRING,
283 result: LENGTH as jni_sys::jsize,
284 }),
285 JniCall::GetStringUTFLength(GetStringUTFLength {
286 string: RAW_STRING,
287 result: SIZE as jni_sys::jsize,
288 }),
289 JniCall::GetStringUTFRegion(GetStringUTFRegion {
290 string: RAW_STRING,
291 start: 0,
292 len: LENGTH as jni_sys::jsize,
293 buffer: "test-string".to_owned(),
294 }),
295 ]);
296 let vm = test_vm(ptr::null_mut());
297 let env = test_env(&vm, calls.env);
298 let string = unsafe { String::from_raw(&env, RAW_STRING) };
299 assert_eq!(string.as_string(&NoException::test()), "test-string");
300 }
301
302 #[test]
303 fn as_string_empty() {
304 const RAW_STRING: jni_sys::jobject = 0x2835 as jni_sys::jobject;
305 let calls = test_raw_jni_env!(vec![JniCall::GetStringLength(GetStringLength {
306 string: RAW_STRING,
307 result: 0,
308 })]);
309 let vm = test_vm(ptr::null_mut());
310 let env = test_env(&vm, calls.env);
311 let string = unsafe { String::from_raw(&env, RAW_STRING) };
312 assert_eq!(string.as_string(&NoException::test()), "");
313 }
314}