Trait jlrs::async_util::task::PersistentTask
source · pub trait PersistentTask: 'static + Send {
type State<'state>;
type Input: 'static + Send;
type Output: 'static + Send;
type Affinity: Affinity;
const CHANNEL_CAPACITY: usize = 0usize;
// Required methods
fn init<'frame, 'life0, 'async_trait>(
&'life0 mut self,
frame: AsyncGcFrame<'frame>
) -> Pin<Box<dyn Future<Output = JlrsResult<Self::State<'frame>>> + 'async_trait>>
where Self: 'async_trait,
'frame: 'async_trait,
'life0: 'async_trait;
fn run<'frame, 'state, 'life0, 'life1, 'async_trait>(
&'life0 mut self,
frame: AsyncGcFrame<'frame>,
state: &'life1 mut Self::State<'state>,
input: Self::Input
) -> Pin<Box<dyn Future<Output = JlrsResult<Self::Output>> + 'async_trait>>
where Self: 'async_trait,
'frame: 'async_trait,
'state: 'async_trait + 'frame,
'life0: 'async_trait,
'life1: 'async_trait;
// Provided methods
fn register<'frame, 'async_trait>(
_frame: AsyncGcFrame<'frame>
) -> Pin<Box<dyn Future<Output = JlrsResult<()>> + 'async_trait>>
where 'frame: 'async_trait { ... }
fn exit<'frame, 'life0, 'life1, 'async_trait>(
&'life0 mut self,
_frame: AsyncGcFrame<'frame>,
_state: &'life1 mut Self::State<'frame>
) -> Pin<Box<dyn Future<Output = ()> + 'async_trait>>
where Self: 'async_trait,
'frame: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
}
Expand description
A task that can be called multiple times.
In order to schedule the task you must use AsyncJulia::persistent
.
Example:
use jlrs::prelude::*;
struct AccumulatorTask {
n_values: usize,
}
struct AccumulatorTaskState<'state> {
array: TypedArray<'state, 'static, usize>,
offset: usize,
}
// Only the runtime thread can call the Julia C API, so the async trait
// methods of `PersistentTask` must not return a future that implements
// `Send` or `Sync`.
#[async_trait(?Send)]
impl PersistentTask for AccumulatorTask {
// The type of the result of the task if it succeeds.
type Output = usize;
// The type of the task's internal state.
type State<'state> = AccumulatorTaskState<'state>;
// The type of the additional data that the task must be called with.
type Input = usize;
// The thread-affinity of this task. This lets you control whether this kind of task is
// always dispatched to the main thread, to a worker thread if they're used, or to either.
// This task can be dispatched to either the main thread or a worker thread.
type Affinity = DispatchAny;
// This method is called before the handle is returned. Note that the
// lifetime of the frame is `'static`: the frame is not dropped until
// the task has completed, so the task's internal state can contain
// Julia data rooted in this frame.
async fn init<'frame>(
&mut self,
mut frame: AsyncGcFrame<'frame>,
) -> JlrsResult<Self::State<'frame>> {
// A `Vec` can be moved from Rust to Julia if the element type
// implements `IntoJulia`.
let data = vec![0usize; self.n_values];
let array =
TypedArray::from_vec(&mut frame, data, self.n_values)?.into_jlrs_result()?;
Ok(AccumulatorTaskState { array, offset: 0 })
}
// Whenever the task is called through its handle this method
// is called. Unlike `init`, the frame that this method can use
// is dropped after `run` returns.
async fn run<'frame, 'state: 'frame>(
&mut self,
mut frame: AsyncGcFrame<'frame>,
state: &mut Self::State<'state>,
input: Self::Input,
) -> JlrsResult<Self::Output> {
{
// Array data can be directly accessed from Rust.
// The data is tracked first to ensure it's not
// already borrowed from Rust.
unsafe {
let mut tracked = state.array.track_exclusive()?;
let mut data = tracked.bits_data_mut()?;
data[state.offset] = input;
};
state.offset += 1;
if (state.offset == self.n_values) {
state.offset = 0;
}
}
// Return the sum of the contents of `state.array`.
unsafe {
Module::base(&frame)
.function(&mut frame, "sum")?
.call1(&mut frame, state.array.as_value())
.into_jlrs_result()?
.unbox::<usize>()
}
}
}
Required Associated Types§
sourcetype State<'state>
type State<'state>
The type of the result which is returned if init
completes successfully.
This data is provided to every call of run
.
sourcetype Input: 'static + Send
type Input: 'static + Send
The type of the data that must be provided when calling this persistent through its handle.
sourcetype Output: 'static + Send
type Output: 'static + Send
The type of the result which is returned if run
completes successfully.
sourcetype Affinity: Affinity
type Affinity: Affinity
The thread-affinity of this task. Can be set to DispatchAny
, DispatchMain
, or
DispatchWorker
Provided Associated Constants§
const CHANNEL_CAPACITY: usize = 0usize
Required Methods§
sourcefn init<'frame, 'life0, 'async_trait>(
&'life0 mut self,
frame: AsyncGcFrame<'frame>
) -> Pin<Box<dyn Future<Output = JlrsResult<Self::State<'frame>>> + 'async_trait>>where
Self: 'async_trait,
'frame: 'async_trait,
'life0: 'async_trait,
fn init<'frame, 'life0, 'async_trait>(
&'life0 mut self,
frame: AsyncGcFrame<'frame>
) -> Pin<Box<dyn Future<Output = JlrsResult<Self::State<'frame>>> + 'async_trait>>where
Self: 'async_trait,
'frame: 'async_trait,
'life0: 'async_trait,
Initialize the task.
You can interact with Julia inside this method, the frame is not dropped until the task
itself is dropped. This means that State
can contain arbitrary Julia data rooted in this
frame. This data is provided to every call to run
.
sourcefn run<'frame, 'state, 'life0, 'life1, 'async_trait>(
&'life0 mut self,
frame: AsyncGcFrame<'frame>,
state: &'life1 mut Self::State<'state>,
input: Self::Input
) -> Pin<Box<dyn Future<Output = JlrsResult<Self::Output>> + 'async_trait>>where
Self: 'async_trait,
'frame: 'async_trait,
'state: 'async_trait + 'frame,
'life0: 'async_trait,
'life1: 'async_trait,
fn run<'frame, 'state, 'life0, 'life1, 'async_trait>(
&'life0 mut self,
frame: AsyncGcFrame<'frame>,
state: &'life1 mut Self::State<'state>,
input: Self::Input
) -> Pin<Box<dyn Future<Output = JlrsResult<Self::Output>> + 'async_trait>>where
Self: 'async_trait,
'frame: 'async_trait,
'state: 'async_trait + 'frame,
'life0: 'async_trait,
'life1: 'async_trait,
Run the task.
This method takes an AsyncGcFrame
, which lets you interact with Julia.
It’s also provided with a mutable reference to its state
and the input
provided by the
caller. While the state is mutable, it’s not possible to allocate a new Julia value in
run
and assign it to the state because the frame doesn’t live long enough.
See the trait docs for an example implementation.
Provided Methods§
sourcefn register<'frame, 'async_trait>(
_frame: AsyncGcFrame<'frame>
) -> Pin<Box<dyn Future<Output = JlrsResult<()>> + 'async_trait>>where
'frame: 'async_trait,
fn register<'frame, 'async_trait>(
_frame: AsyncGcFrame<'frame>
) -> Pin<Box<dyn Future<Output = JlrsResult<()>> + 'async_trait>>where
'frame: 'async_trait,
Register this persistent task.
Note that this method is not called automatically, but only if
AsyncJulia::register_persistent
is used.
This method can be implemented to take care of everything required to execute the task
successfully, like loading packages.
sourcefn exit<'frame, 'life0, 'life1, 'async_trait>(
&'life0 mut self,
_frame: AsyncGcFrame<'frame>,
_state: &'life1 mut Self::State<'frame>
) -> Pin<Box<dyn Future<Output = ()> + 'async_trait>>where
Self: 'async_trait,
'frame: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn exit<'frame, 'life0, 'life1, 'async_trait>(
&'life0 mut self,
_frame: AsyncGcFrame<'frame>,
_state: &'life1 mut Self::State<'frame>
) -> Pin<Box<dyn Future<Output = ()> + 'async_trait>>where
Self: 'async_trait,
'frame: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Method that is called when all handles to the task have been dropped.
This method is called with the same frame as init
.