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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! Schedulers remain usable when stored in application and thread-local state.
#![cfg(all(feature = "rt", feature = "macros"))]
testing_aids::init_tracing!();
use std::cell::RefCell;
use arty::task::{Builtins, Scheduler};
#[arty::test]
#[expect(
clippy::float_cmp,
reason = "fake logic for tests, no computation involved - direct comparison is fine"
)]
async fn stash_scheduler(cx: Builtins) {
// We store a scheduler in some object that can schedule tasks without having knowledge of the
// exact type of the task or task context.
struct Thingy {
scheduler: Scheduler,
}
impl Thingy {
async fn calculate_pi(&self) -> f64 {
self.scheduler.spawn(async move |_| 3.0).await.unwrap()
}
}
cx.scheduler()
.spawn(async move |cx| {
// We store the scheduler in a thingy and try to use it from the thingy
// without having direct access to the task context.
let thingy = Thingy {
scheduler: cx.scheduler().clone(),
};
let pi = thingy.calculate_pi().await;
assert_eq!(pi, 3.0);
// The stored worker-bound scheduler also works from a different task.
let thingy = Thingy {
scheduler: cx.scheduler().clone(),
};
cx.scheduler()
.spawn(async move |_| {
let pi = thingy.calculate_pi().await;
assert_eq!(pi, 3.0);
})
.await
.unwrap();
})
.await
.unwrap();
cx.scheduler()
.spawn(async move |cx| {
// We store the scheduler in a thread-local variable.
THREAD_LOCAL_STASH.with_borrow_mut(|stash| {
*stash = Some(cx.scheduler().clone());
});
// And we try to use it from another task on the same thread.
let result = cx
.scheduler()
.spawn(async move |_| {
let scheduler = THREAD_LOCAL_STASH.with_borrow(|stash| stash.clone().unwrap());
// It works, right? Right.
scheduler.spawn(async move |_| 49).await.unwrap()
})
.await
.unwrap();
assert_eq!(result, 49);
})
.await
.unwrap();
}
thread_local! {
static THREAD_LOCAL_STASH: RefCell<Option<Scheduler>> = const { RefCell::new(None) };
}