• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{
2     errors::*,
3     objects::{AutoLocal, JObject},
4     JNIEnv,
5 };
6 
7 #[cfg(doc)]
8 use crate::objects::{JClass, JMethodID};
9 
10 /// Trait for things that can be looked up through the JNI via a descriptor.
11 /// This will be something like the fully-qualified class name
12 /// `java/lang/String` or a tuple containing a class descriptor, method name,
13 /// and method signature. For convenience, this is also implemented for the
14 /// concrete types themselves in addition to their descriptors.
15 ///
16 /// # Safety
17 ///
18 /// Implementations of this trait must return the correct value from the
19 /// `lookup` method. It must not, for example, return a random [`JMethodID`] or
20 /// the [`JClass`] of a class other than the one requested. Returning such an
21 /// incorrect value results in undefined behavior. This requirement also
22 /// applies to the returned value's implementation of `AsRef<T>`.
23 pub unsafe trait Desc<'local, T> {
24     /// The type that this `Desc` returns.
25     type Output: AsRef<T>;
26 
27     /// Look up the concrete type from the JVM.
28     ///
29     /// Note that this method does not return exactly `T`. Instead, it returns
30     /// some type that implements `AsRef<T>`. For this reason, it is often
31     /// necessary to use turbofish syntax when calling this method:
32     ///
33     /// ```rust,no_run
34     /// # use jni::{descriptors::Desc, errors::Result, JNIEnv, objects::JClass};
35     /// #
36     /// # fn example(env: &mut JNIEnv) -> Result<()> {
37     /// // The value returned by `lookup` is not exactly `JClass`.
38     /// let class/*: impl AsRef<JClass> */ =
39     ///     Desc::<JClass>::lookup("java/lang/Object", env)?;
40     ///
41     /// // But `&JClass` can be borrowed from it.
42     /// let class: &JClass = class.as_ref();
43     /// # Ok(())
44     /// # }
45     /// ```
46     ///
47     /// **Warning:** Many built-in implementations of this trait return
48     /// [`AutoLocal`] from this method. If you then call [`JObject::as_raw`] on
49     /// the returned object reference, this may result in the reference being
50     /// [deleted][JNIEnv::delete_local_ref] before it is used, causing
51     /// undefined behavior.
52     ///
53     /// For example, don't do this:
54     ///
55     /// ```rust,no_run
56     /// # use jni::{descriptors::Desc, errors::Result, JNIEnv, objects::JClass};
57     /// #
58     /// # fn some_function<T>(ptr: *mut T) {}
59     /// #
60     /// # fn example(env: &mut JNIEnv) -> Result<()> {
61     /// // Undefined behavior: the `JClass` is dropped before the raw pointer
62     /// // is passed to `some_function`!
63     /// some_function(Desc::<JClass>::lookup("java/lang/Object", env)?.as_raw());
64     /// # Ok(())
65     /// # }
66     /// ```
67     ///
68     /// Instead, do this:
69     ///
70     /// ```rust,no_run
71     /// # use jni::{descriptors::Desc, errors::Result, JNIEnv, objects::JClass};
72     /// #
73     /// # fn some_function<T>(ptr: *mut T) {}
74     /// #
75     /// # fn example(env: &mut JNIEnv) -> Result<()> {
76     /// let class = Desc::<JClass>::lookup("java/lang/Object", env)?;
77     ///
78     /// some_function(class.as_raw());
79     ///
80     /// drop(class);
81     /// # Ok(())
82     /// # }
83     /// ```
84     ///
85     /// This will still work without the call to `drop` at the end, but calling
86     /// `drop` ensures that the reference is not accidentally dropped earlier
87     /// than it should be.
lookup(self, _: &mut JNIEnv<'local>) -> Result<Self::Output>88     fn lookup(self, _: &mut JNIEnv<'local>) -> Result<Self::Output>;
89 }
90 
91 unsafe impl<'local, T> Desc<'local, T> for T
92 where
93     T: AsRef<T>,
94 {
95     type Output = Self;
96 
lookup(self, _: &mut JNIEnv<'local>) -> Result<T>97     fn lookup(self, _: &mut JNIEnv<'local>) -> Result<T> {
98         Ok(self)
99     }
100 }
101 
102 unsafe impl<'local, 't_ref, T> Desc<'local, T> for &'t_ref T
103 where
104     T: AsRef<T>,
105 {
106     type Output = Self;
107 
lookup(self, _: &mut JNIEnv<'local>) -> Result<Self::Output>108     fn lookup(self, _: &mut JNIEnv<'local>) -> Result<Self::Output> {
109         Ok(self)
110     }
111 }
112 
113 unsafe impl<'local, 'other_local, T> Desc<'local, T> for AutoLocal<'other_local, T>
114 where
115     T: AsRef<T> + Into<JObject<'other_local>>,
116 {
117     type Output = Self;
118 
lookup(self, _: &mut JNIEnv<'local>) -> Result<Self::Output>119     fn lookup(self, _: &mut JNIEnv<'local>) -> Result<Self::Output> {
120         Ok(self)
121     }
122 }
123 
124 unsafe impl<'local, 'other_local, 'obj_ref, T> Desc<'local, T>
125     for &'obj_ref AutoLocal<'other_local, T>
126 where
127     T: AsRef<T> + Into<JObject<'other_local>>,
128 {
129     type Output = Self;
130 
lookup(self, _: &mut JNIEnv<'local>) -> Result<Self::Output>131     fn lookup(self, _: &mut JNIEnv<'local>) -> Result<Self::Output> {
132         Ok(self)
133     }
134 }
135