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