1 use std::mem; 2 3 use log::debug; 4 5 use crate::{objects::JObject, JNIEnv}; 6 7 /// Auto-delete wrapper for local refs. 8 /// 9 /// Anything passed to a foreign method _and_ returned from JNI methods is considered a local ref 10 /// unless it is specified otherwise. 11 /// These refs are automatically deleted once the foreign method exits, but it's possible that 12 /// they may reach the JVM-imposed limit before that happens. 13 /// 14 /// This wrapper provides automatic local ref deletion when it goes out of 15 /// scope. 16 /// 17 /// NOTE: This comes with some potential safety risks. DO NOT use this to wrap 18 /// something unless you're SURE it won't be used after this wrapper gets 19 /// dropped. Otherwise, you'll get a nasty JVM crash. 20 /// 21 /// See also the [JNI specification][spec-references] for details on referencing Java objects 22 /// and some [extra information][android-jni-references]. 23 /// 24 /// [spec-references]: https://docs.oracle.com/en/java/javase/12/docs/specs/jni/design.html#referencing-java-objects 25 /// [android-jni-references]: https://developer.android.com/training/articles/perf-jni#local-and-global-references 26 pub struct AutoLocal<'a: 'b, 'b> { 27 obj: JObject<'a>, 28 env: &'b JNIEnv<'a>, 29 } 30 31 impl<'a, 'b> AutoLocal<'a, 'b> { 32 /// Creates a new auto-delete wrapper for a local ref. 33 /// 34 /// Once this wrapper goes out of scope, the `delete_local_ref` will be 35 /// called on the object. While wrapped, the object can be accessed via 36 /// the `Deref` impl. new(env: &'b JNIEnv<'a>, obj: JObject<'a>) -> Self37 pub fn new(env: &'b JNIEnv<'a>, obj: JObject<'a>) -> Self { 38 AutoLocal { obj, env } 39 } 40 41 /// Forget the wrapper, returning the original object. 42 /// 43 /// This prevents `delete_local_ref` from being called when the `AutoLocal` 44 /// gets 45 /// dropped. You must either remember to delete the local ref manually, or 46 /// be 47 /// ok with it getting deleted once the foreign method returns. forget(self) -> JObject<'a>48 pub fn forget(self) -> JObject<'a> { 49 let obj = self.obj; 50 mem::forget(self); 51 obj 52 } 53 54 /// Get a reference to the wrapped object 55 /// 56 /// Unlike `forget`, this ensures the wrapper from being dropped while the 57 /// returned `JObject` is still live. as_obj<'c>(&self) -> JObject<'c> where 'a: 'c,58 pub fn as_obj<'c>(&self) -> JObject<'c> 59 where 60 'a: 'c, 61 { 62 self.obj 63 } 64 } 65 66 impl<'a, 'b> Drop for AutoLocal<'a, 'b> { drop(&mut self)67 fn drop(&mut self) { 68 let res = self.env.delete_local_ref(self.obj); 69 match res { 70 Ok(()) => {} 71 Err(e) => debug!("error dropping global ref: {:#?}", e), 72 } 73 } 74 } 75 76 impl<'a> From<&'a AutoLocal<'a, '_>> for JObject<'a> { from(other: &'a AutoLocal) -> JObject<'a>77 fn from(other: &'a AutoLocal) -> JObject<'a> { 78 other.as_obj() 79 } 80 } 81