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
// //! Utilities for working with scoped tasks.
// use crate::pipeline::{elements::output::OutputContext, Output};
// /// Spawns a blocking function with the provided arguments, and waits for it to return.
// ///
// /// # Example
// /// ```ignore
// /// spawn_blocking_with_output(output, ctx, func).await
// /// ```
// ///
// /// The above is equivalent to:
// /// ```ignore
// /// tokio::task::spawn_blocking(move || {
// /// func(output, ctx)
// /// }).await
// /// ```
// /// but without requiring the lifetimes of the two arguments to be `'static`.
// pub async fn spawn_blocking_with_output<F, R>(
// output: &mut dyn Output,
// ctx: &mut OutputContext<'_>,
// func: F,
// ) -> Result<R, tokio::task::JoinError>
// where
// F: FnOnce(&mut dyn super::Output, &mut super::OutputContext) -> R + Send + 'static,
// R: Send + 'static,
// {
// struct SendThinPointer(*mut super::OutputContext);
// struct SendFatPointer(*mut dyn super::Output);
// unsafe impl Send for SendThinPointer {}
// unsafe impl Send for SendFatPointer {}
// let out_ptr = SendFatPointer(output as *mut _ as _);
// let ctx_ptr = SendThinPointer(ctx as *mut _ as _);
// let rt = tokio::runtime::Handle::current();
// rt.spawn_blocking(move || {
// // SAFETY: we wait for the task to finish, and tokio catches the panics,
// // therefore the pointers remain valid during the entire call to `func`.
// let (out_ptr, ctx_ptr) = (out_ptr, ctx_ptr); // We move the wrappers, not the pointers
// let out = unsafe { &mut *(out_ptr.0 as *mut _) };
// let ctx = unsafe { &mut *(ctx_ptr.0 as *mut _) };
// func(out, ctx)
// })
// .await
// }