1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Traits used to implement tasks for the async runtime.

use crate::error::JlrsResult;
use crate::frame::AsyncFrame;
use crate::global::Global;
use async_std::sync::Sender as AsyncStdSender;
use async_trait::async_trait;
use crossbeam_channel::Sender as CrossbeamSender;

/// The `JuliaTask` trait is used to create tasks that the async runtime can execute.
/// Implementations of this trait take the place of the closures used with the sync runtime.
#[async_trait(?Send)]
pub trait JuliaTask: Send + Sync + 'static {
    /// The type of the result of this task. Must be the same across all implementations.
    type T: 'static + Send + Sync;

    /// The type of the sender that is used to send the result of this task back to the original
    /// caller. Must be the same across all implementations.
    type R: ReturnChannel<T = Self::T>;

    /// The entrypoint of a task. You can use the `Global` and `AsyncFrame` to call arbitrary
    /// functions from Julia. Additionally, [`Value::call_async`] can be used to call a function
    /// on another thread and allow other tasks to progress while awaiting the result.
    /// Implementations that don't use [`Value::call_async`] will block the runtime during
    /// execution.
    ///
    /// [`Value::call_async`]: ../../value/struct.Value.html#method.call_async
    async fn run<'base>(
        &mut self,
        global: Global<'base>,
        frame: &mut AsyncFrame<'base>,
    ) -> JlrsResult<Self::T>;

    /// The return channel for this task, or `None` if the result doesn't need to be returned.
    /// Returns `None` by default.
    fn return_channel(&self) -> Option<&Self::R> {
        None
    }
}

/// The `ReturnChannel` trait is implemented by types that can send a result back to a caller. It
/// is implemented for both `async_std::sync::Sender` and `crossbeam_channel::Sender`.
#[async_trait]
pub trait ReturnChannel: 'static {
    type T: Send + Sync + 'static;

    /// Send the result.
    async fn send(&self, response: JlrsResult<Self::T>);
}

#[async_trait]
impl<T: Send + Sync + 'static> ReturnChannel for AsyncStdSender<JlrsResult<T>> {
    type T = T;
    async fn send(&self, response: JlrsResult<Self::T>) {
        self.send(response).await
    }
}

#[async_trait]
impl<T: Send + Sync + 'static> ReturnChannel for CrossbeamSender<JlrsResult<T>> {
    type T = T;
    async fn send(&self, response: JlrsResult<Self::T>) {
        self.send(response).ok();
    }
}