java_oxide/string_chars.rs
1use crate::Env;
2use jni_sys::*;
3use std::{char, iter, slice};
4
5/// Represents a JNI `GetStringChars` + `GetStringLength` query.
6/// It will call `ReleaseStringChars` automatically when dropped.
7pub struct StringChars<'env> {
8 env: Env<'env>,
9 string: jstring,
10 chars: *const jchar,
11 length: jsize, // in characters
12}
13
14impl<'env> StringChars<'env> {
15 /// Construct a `StringChars` from an [Env] + [jstring].
16 ///
17 /// # Safety
18 ///
19 /// The Java string object referenced by `string` must remain available before the created
20 /// `StringChars` is dropped. This should be true if the JNI reference `string` is not deleted.
21 ///
22 /// This function is supposed to be used in generated bindings.
23 pub unsafe fn from_env_jstring(env: Env<'env>, string: jstring) -> Self {
24 debug_assert!(!string.is_null());
25
26 let chars = unsafe { env.get_string_chars(string) };
27 let length = unsafe { env.get_string_length(string) };
28
29 Self {
30 env,
31 string,
32 chars,
33 length,
34 }
35 }
36
37 /// Get an array of [jchar]s. Generally UTF16, but not guaranteed to be valid UTF16.
38 pub fn chars(&self) -> &[jchar] {
39 unsafe { slice::from_raw_parts(self.chars, self.length as usize) }
40 }
41
42 /// [std::char::decode_utf16]\(...\)s these string characters.
43 pub fn decode(&self) -> char::DecodeUtf16<iter::Cloned<slice::Iter<'_, u16>>> {
44 char::decode_utf16(self.chars().iter().cloned())
45 }
46
47 /// Returns a new [Ok]\([String]\), or an [Err]\([DecodeUtf16Error](char::DecodeUtf16Error)\) if if it contained any invalid UTF16.
48 pub fn to_string(&self) -> Result<String, char::DecodeUtf16Error> {
49 self.decode().collect()
50 }
51
52 /// Returns a new [String] with any invalid UTF16 characters replaced with [REPLACEMENT_CHARACTER](char::REPLACEMENT_CHARACTER)s (`'\u{FFFD}'`.)
53 pub fn to_string_lossy(&self) -> String {
54 self.decode()
55 .map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
56 .collect()
57 }
58}
59
60impl<'env> Drop for StringChars<'env> {
61 fn drop(&mut self) {
62 unsafe { self.env.release_string_chars(self.string, self.chars) };
63 }
64}