jni_utils/
task.rs

1use ::jni::{
2    errors::Result,
3    objects::{JMethodID, JObject, JClass},
4    signature::JavaType,
5    JNIEnv,
6};
7use std::task::Waker;
8
9/// Wraps the given waker in a `io.github.gedgygedgy.rust.task.Waker` object.
10///
11/// Calling this function is generally not necessary, since
12/// [`JFuture`](crate::future::JFuture) and [`JStream`](crate::stream::JStream)
13/// take care of it for you.
14///
15/// # Arguments
16///
17/// * `env` - Java environment in which to create the object.
18/// * `waker` - Waker to wrap in a Java object.
19pub fn waker<'a: 'b, 'b>(env: &'b JNIEnv<'a>, waker: Waker) -> Result<JObject<'a>> {
20    let runnable = crate::ops::fn_once_runnable(env, |_e, _o| waker.wake())?;
21
22    let obj = env.new_object(
23        JClass::from(crate::classcache::get_class("io/github/gedgygedgy/rust/task/Waker").unwrap().as_obj()),
24        "(Lio/github/gedgygedgy/rust/ops/FnRunnable;)V",
25        &[runnable.into()],
26    )?;
27    Ok(obj)
28}
29
30/// Wrapper for [`JObject`]s that implement
31/// `io.github.gedgygedgy.rust.task.PollResult`. Provides method to get the
32/// poll result.
33///
34/// Looks up the class and method IDs on creation rather than for every method
35/// call.
36pub struct JPollResult<'a: 'b, 'b> {
37    internal: JObject<'a>,
38    get: JMethodID<'a>,
39    env: &'b JNIEnv<'a>,
40}
41
42impl<'a: 'b, 'b> JPollResult<'a, 'b> {
43    /// Create a [`JPollResult`] from the environment and an object. This looks
44    /// up the necessary class and method IDs to call all of the methods on it
45    /// so that extra work doesn't need to be done on every method call.
46    ///
47    /// # Arguments
48    ///
49    /// * `env` - Java environment to use.
50    /// * `obj` - Object to wrap.
51    pub fn from_env(env: &'b JNIEnv<'a>, obj: JObject<'a>) -> Result<Self> {
52        let get = env.get_method_id(
53            JClass::from(crate::classcache::get_class("io/github/gedgygedgy/rust/task/PollResult").unwrap().as_obj()), 
54            "get", 
55            "()Ljava/lang/Object;")?;
56        Ok(Self {
57            internal: obj,
58            get,
59            env,
60        })
61    }
62
63    /// Gets the object associated with the [`JPollResult`] by calling
64    /// `io.github.gedgygedgy.rust.task.PollResult.get()`. Can throw an
65    /// exception.
66    pub fn get(&self) -> Result<JObject<'a>> {
67        self.env
68            .call_method_unchecked(
69                self.internal,
70                self.get,
71                JavaType::Object("java/lang/Object".into()),
72                &[],
73            )?
74            .l()
75    }
76}
77
78impl<'a: 'b, 'b> ::std::ops::Deref for JPollResult<'a, 'b> {
79    type Target = JObject<'a>;
80
81    fn deref(&self) -> &Self::Target {
82        &self.internal
83    }
84}
85
86impl<'a: 'b, 'b> From<JPollResult<'a, 'b>> for JObject<'a> {
87    fn from(other: JPollResult<'a, 'b>) -> JObject<'a> {
88        other.internal
89    }
90}
91
92#[cfg(test)]
93mod test {
94    use crate::test_utils;
95    use std::sync::Arc;
96
97    #[test]
98    fn test_waker_wake() {
99        test_utils::JVM_ENV.with(|env| {
100            let data = Arc::new(test_utils::TestWakerData::new());
101            assert_eq!(Arc::strong_count(&data), 1);
102            assert_eq!(data.value(), false);
103
104            let waker = crate::test_utils::test_waker(&data);
105            assert_eq!(Arc::strong_count(&data), 2);
106            assert_eq!(data.value(), false);
107
108            let jwaker = super::waker(env, waker).unwrap();
109            assert_eq!(Arc::strong_count(&data), 2);
110            assert_eq!(data.value(), false);
111
112            env.call_method(jwaker, "wake", "()V", &[]).unwrap();
113            assert_eq!(Arc::strong_count(&data), 1);
114            assert_eq!(data.value(), true);
115            data.set_value(false);
116
117            env.call_method(jwaker, "wake", "()V", &[]).unwrap();
118            assert_eq!(Arc::strong_count(&data), 1);
119            assert_eq!(data.value(), false);
120        });
121    }
122
123    #[test]
124    fn test_waker_close_wake() {
125        test_utils::JVM_ENV.with(|env| {
126            let data = Arc::new(test_utils::TestWakerData::new());
127            assert_eq!(Arc::strong_count(&data), 1);
128            assert_eq!(data.value(), false);
129
130            let waker = crate::test_utils::test_waker(&data);
131            assert_eq!(Arc::strong_count(&data), 2);
132            assert_eq!(data.value(), false);
133
134            let jwaker = super::waker(env, waker).unwrap();
135            assert_eq!(Arc::strong_count(&data), 2);
136            assert_eq!(data.value(), false);
137
138            env.call_method(jwaker, "close", "()V", &[]).unwrap();
139            assert_eq!(Arc::strong_count(&data), 1);
140            assert_eq!(data.value(), false);
141
142            env.call_method(jwaker, "wake", "()V", &[]).unwrap();
143            assert_eq!(Arc::strong_count(&data), 1);
144            assert_eq!(data.value(), false);
145        });
146    }
147}