jni/descriptors/desc.rs
1use crate::{
2 Env,
3 errors::*,
4 objects::{Auto, Global, JObject, Reference},
5};
6
7#[cfg(doc)]
8use 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>`.
23pub 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::{jni_str, descriptors::Desc, errors::Result, Env, objects::JClass};
35 /// #
36 /// # fn example(env: &mut Env) -> Result<()> {
37 /// // The value returned by `lookup` is not exactly `JClass`.
38 /// let class/*: impl AsRef<JClass> */ =
39 /// Desc::<JClass>::lookup(jni_str!("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 /// [`Auto`] 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][Env::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::{jni_str, descriptors::Desc, errors::Result, Env, objects::JClass};
57 /// #
58 /// # fn some_function<T>(ptr: *mut T) {}
59 /// #
60 /// # fn example(env: &mut Env) -> Result<()> {
61 /// // Undefined behavior: the `JClass` is dropped before the raw pointer
62 /// // is passed to `some_function`!
63 /// some_function(Desc::<JClass>::lookup(jni_str!("java/lang/Object"), env)?.as_raw());
64 /// # Ok(())
65 /// # }
66 /// ```
67 ///
68 /// Instead, do this:
69 ///
70 /// ```rust,no_run
71 /// # use jni::{jni_str, descriptors::Desc, errors::Result, Env, objects::JClass};
72 /// #
73 /// # fn some_function<T>(ptr: *mut T) {}
74 /// #
75 /// # fn example(env: &mut Env) -> Result<()> {
76 /// let class = Desc::<JClass>::lookup(jni_str!("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.
88 fn lookup(self, _: &mut Env<'local>) -> Result<Self::Output>;
89}
90
91unsafe impl<'local, T> Desc<'local, T> for T
92where
93 T: AsRef<T>,
94{
95 type Output = Self;
96
97 fn lookup(self, _: &mut Env<'local>) -> Result<T> {
98 Ok(self)
99 }
100}
101
102unsafe impl<'local, T> Desc<'local, T> for &T
103where
104 T: AsRef<T>,
105{
106 type Output = Self;
107
108 fn lookup(self, _: &mut Env<'local>) -> Result<Self::Output> {
109 Ok(self)
110 }
111}
112
113unsafe impl<'local, 'other_local, T> Desc<'local, T> for Auto<'other_local, T>
114where
115 T: AsRef<T> + Into<JObject<'other_local>>,
116{
117 type Output = Self;
118
119 fn lookup(self, _: &mut Env<'local>) -> Result<Self::Output> {
120 Ok(self)
121 }
122}
123
124unsafe impl<'local, 'other_local, T> Desc<'local, T> for &Auto<'other_local, T>
125where
126 T: AsRef<T> + Into<JObject<'other_local>>,
127{
128 type Output = Self;
129
130 fn lookup(self, _: &mut Env<'local>) -> Result<Self::Output> {
131 Ok(self)
132 }
133}
134
135unsafe impl<'local, 'obj_ref, T> Desc<'local, T> for &'obj_ref Global<T>
136where
137 T: Reference
138 + AsRef<T>
139 + AsRef<JObject<'static>>
140 + Into<JObject<'static>>
141 + Default
142 + Send
143 + Sync
144 + 'static,
145{
146 type Output = &'obj_ref T;
147
148 fn lookup(self, _: &mut Env<'local>) -> Result<Self::Output> {
149 Ok(self.as_ref())
150 }
151}