• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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