Skip to main content

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}