jni_glue/
string_chars.rs

1use super::{*, jchar};
2use std::{char, slice, iter, mem::transmute};
3
4
5
6/// Represents an env.GetStringChars + env.GetStringLength query.
7/// Will automatically env.ReleaseStringChars when dropped.
8pub struct StringChars<'env> {
9    env:    &'env Env,
10    string: jstring,
11    chars:  *const jchar,
12    length: jsize, // in characters
13}
14
15impl<'env> StringChars<'env> {
16    /// Construct a StringChars from an Env + jstring.
17    pub unsafe fn from_env_jstring(env: &'env Env, string: jstring) -> Self {
18        debug_assert!(!string.is_null());
19
20        let chars  = env.get_string_chars(string);
21        let length = env.get_string_length(string);
22
23        Self {
24            env,
25            string,
26            chars,
27            length,
28        }
29    }
30
31    /// Get an array of [jchar]s.  Generally UTF16, but not guaranteed to be valid UTF16.
32    /// 
33    /// [jchar]:                    struct.jchar.html
34    pub fn chars(&self) -> &[jchar] {
35        unsafe { slice::from_raw_parts(self.chars, self.length as usize) }
36    }
37
38    /// Get an array of [u16]s.  Generally UTF16, but not guaranteed to be valid UTF16.
39    pub fn as_u16_slice(&self) -> &[u16] {
40        unsafe { transmute::<&[jchar], &[u16]>(self.chars()) }
41    }
42
43    /// std::char::[decode_utf16]\(...\)s these string characters.
44    /// 
45    /// [decode_utf16]:             https://doc.rust-lang.org/std/char/fn.decode_utf16.html
46    pub fn decode(&self) -> char::DecodeUtf16<iter::Cloned<slice::Iter<u16>>> {
47        char::decode_utf16(self.as_u16_slice().iter().cloned())
48    }
49
50    /// Returns a new [Ok]\([String]\), or an [Err]\([DecodeUtf16Error]\) if if it contained any invalid UTF16.
51    /// 
52    /// [Ok]:                       https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
53    /// [Err]:                      https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
54    /// [DecodeUtf16Error]:         https://doc.rust-lang.org/std/char/struct.DecodeUtf16Error.html
55    /// [String]:                   https://doc.rust-lang.org/std/string/struct.String.html
56    /// [REPLACEMENT_CHARACTER]:    https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
57    pub fn to_string(&self) -> Result<String, char::DecodeUtf16Error> {
58        self.decode().collect()
59    }
60
61    /// Returns a new [String] with any invalid UTF16 characters replaced with [REPLACEMENT_CHARACTER]s (`'\u{FFFD}'`.)
62    /// 
63    /// [String]:                   https://doc.rust-lang.org/std/string/struct.String.html
64    /// [REPLACEMENT_CHARACTER]:    https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
65    pub fn to_string_lossy(&self) -> String {
66        self.decode().map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER)).collect()
67    }
68}
69
70impl<'env> Drop for StringChars<'env> {
71    fn drop(&mut self) {
72        unsafe { self.env.release_string_chars(self.string, self.chars) };
73    }
74}