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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use super::Stack;
use std::{
future::Future,
ops::{Deref, DerefMut},
task::Context,
};
#[repr(C)]
pub struct AsyncStack<'a, 'b> {
stack: Stack,
context: Option<&'a mut Context<'b>>,
suspended: bool,
}
impl<'a, 'b> AsyncStack<'a, 'b> {
pub fn new(capacity: usize) -> Self {
Self {
stack: Stack::new(capacity),
context: None,
suspended: false,
}
}
pub fn context(&mut self) -> Option<&mut Context<'b>> {
self.context.as_deref_mut()
}
pub fn set_context(&mut self, context: &'a mut Context<'b>) {
self.context = Some(context);
}
pub fn suspend(&mut self, future: impl Future) {
self.stack.push(future);
self.suspended = true;
}
pub fn resume<F: Future>(&mut self) -> Option<F> {
if self.suspended {
self.suspended = false;
Some(self.stack.pop())
} else {
None
}
}
}
impl<'a, 'b> Deref for AsyncStack<'a, 'b> {
type Target = Stack;
fn deref(&self) -> &Stack {
&self.stack
}
}
impl<'a, 'b> DerefMut for AsyncStack<'a, 'b> {
fn deref_mut(&mut self) -> &mut Stack {
&mut self.stack
}
}
#[allow(dead_code)]
extern "C" {
fn _test_async_stack_ffi_safety(_: *mut AsyncStack<'_, '_>);
}
#[cfg(test)]
mod tests {
use super::*;
use std::{
ptr::null,
task::{RawWaker, RawWakerVTable, Waker},
};
const TEST_CAPACITY: usize = 1;
const RAW_WAKER_DATA: () = ();
const RAW_WAKER_V_TABLE: RawWakerVTable =
RawWakerVTable::new(clone_waker, do_nothing, do_nothing, do_nothing);
fn create_waker() -> Waker {
unsafe { Waker::from_raw(RawWaker::new(&RAW_WAKER_DATA, &RAW_WAKER_V_TABLE)) }
}
fn clone_waker(_: *const ()) -> RawWaker {
RawWaker::new(null(), &RAW_WAKER_V_TABLE)
}
fn do_nothing(_: *const ()) {}
#[test]
fn push_f64() {
let mut stack = AsyncStack::new(TEST_CAPACITY);
stack.push(42.0f64);
assert_eq!(stack.pop::<f64>(), 42.0);
}
#[test]
fn wake() {
let waker = create_waker();
let mut stack = AsyncStack::new(TEST_CAPACITY);
let mut context = Context::from_waker(&waker);
stack.set_context(&mut context);
stack.context().unwrap().waker().wake_by_ref();
}
}