nexus_async_rt/
context.rs1use std::cell::Cell;
21use std::sync::Arc;
22use std::sync::atomic::AtomicBool;
23use std::time::{Duration, Instant};
24
25use crate::io::{IoDriver, IoHandle};
26use crate::timer::{TimerDriver, TimerHandle};
27
28thread_local! {
33 static CTX_WORLD: Cell<*mut nexus_rt::World> =
34 const { Cell::new(std::ptr::null_mut()) };
35 static CTX_IO: Cell<*mut IoDriver> =
36 const { Cell::new(std::ptr::null_mut()) };
37 static CTX_TIMER: Cell<*mut TimerDriver> =
38 const { Cell::new(std::ptr::null_mut()) };
39 static CTX_EVENT_TIME: Cell<*const Cell<Instant>> =
40 const { Cell::new(std::ptr::null()) };
41 static CTX_SHUTDOWN: Cell<*const AtomicBool> =
42 const { Cell::new(std::ptr::null()) };
43 static CTX_SHUTDOWN_WAKER: Cell<*const Arc<std::sync::Mutex<Option<std::task::Waker>>>> =
44 const { Cell::new(std::ptr::null()) };
45}
46
47pub(crate) fn install(
54 world: *mut nexus_rt::World,
55 io: *mut IoDriver,
56 timer: *mut TimerDriver,
57 event_time: *const Cell<Instant>,
58 shutdown_flag: *const AtomicBool,
59 shutdown_waker: *const Arc<std::sync::Mutex<Option<std::task::Waker>>>,
60) -> ContextGuard {
61 let prev = PrevContext {
62 world: CTX_WORLD.with(|c| c.replace(world)),
63 io: CTX_IO.with(|c| c.replace(io)),
64 timer: CTX_TIMER.with(|c| c.replace(timer)),
65 event_time: CTX_EVENT_TIME.with(|c| c.replace(event_time)),
66 shutdown: CTX_SHUTDOWN.with(|c| c.replace(shutdown_flag)),
67 shutdown_waker: CTX_SHUTDOWN_WAKER.with(|c| c.replace(shutdown_waker)),
68 };
69 ContextGuard { prev }
70}
71
72struct PrevContext {
73 world: *mut nexus_rt::World,
74 io: *mut IoDriver,
75 timer: *mut TimerDriver,
76 event_time: *const Cell<Instant>,
77 shutdown: *const AtomicBool,
78 shutdown_waker: *const Arc<std::sync::Mutex<Option<std::task::Waker>>>,
79}
80
81pub(crate) struct ContextGuard {
82 prev: PrevContext,
83}
84
85impl Drop for ContextGuard {
86 fn drop(&mut self) {
87 CTX_WORLD.with(|c| c.set(self.prev.world));
88 CTX_IO.with(|c| c.set(self.prev.io));
89 CTX_TIMER.with(|c| c.set(self.prev.timer));
90 CTX_EVENT_TIME.with(|c| c.set(self.prev.event_time));
91 CTX_SHUTDOWN.with(|c| c.set(self.prev.shutdown));
92 CTX_SHUTDOWN_WAKER.with(|c| c.set(self.prev.shutdown_waker));
93 }
94}
95
96pub(crate) fn assert_in_runtime(msg: &str) {
98 let ptr = CTX_WORLD.with(Cell::get);
99 assert!(!ptr.is_null(), "{msg}");
100}
101
102pub fn with_world<R>(f: impl FnOnce(&mut nexus_rt::World) -> R) -> R {
115 let ptr = CTX_WORLD.with(Cell::get);
116 assert!(
117 !ptr.is_null(),
118 "with_world() called outside Runtime::block_on"
119 );
120 let world = unsafe { &mut *ptr };
123 f(world)
124}
125
126pub fn with_world_ref<R>(f: impl FnOnce(&nexus_rt::World) -> R) -> R {
132 let ptr = CTX_WORLD.with(Cell::get);
133 assert!(
134 !ptr.is_null(),
135 "with_world_ref() called outside Runtime::block_on"
136 );
137 let world = unsafe { &*ptr };
138 f(world)
139}
140
141pub fn io() -> IoHandle {
147 let ptr = CTX_IO.with(Cell::get);
148 assert!(!ptr.is_null(), "io() called outside Runtime::block_on");
149 IoHandle::new(unsafe { &mut *ptr })
151}
152
153pub fn sleep(duration: Duration) -> crate::Sleep {
159 let ptr = CTX_TIMER.with(Cell::get);
160 assert!(!ptr.is_null(), "sleep() called outside Runtime::block_on");
161 let handle = TimerHandle::new(unsafe { &mut *ptr });
163 handle.sleep(duration)
164}
165
166pub fn sleep_until(deadline: Instant) -> crate::Sleep {
168 let ptr = CTX_TIMER.with(Cell::get);
169 assert!(
170 !ptr.is_null(),
171 "sleep_until() called outside Runtime::block_on"
172 );
173 let handle = TimerHandle::new(unsafe { &mut *ptr });
174 handle.sleep_until(deadline)
175}
176
177pub fn event_time() -> Instant {
182 let ptr = CTX_EVENT_TIME.with(Cell::get);
183 assert!(
184 !ptr.is_null(),
185 "event_time() called outside Runtime::block_on"
186 );
187 unsafe { &*ptr }.get()
189}
190
191pub fn timeout<F: std::future::Future>(duration: Duration, future: F) -> crate::timer::Timeout<F> {
198 crate::timer::Timeout::new(future, sleep(duration))
199}
200
201pub fn interval(period: Duration) -> crate::timer::Interval {
212 crate::timer::Interval::new(period)
213}
214
215pub async fn after<F: std::future::Future>(deadline: Instant, future: F) -> F::Output {
222 sleep_until(deadline).await;
223 future.await
224}
225
226pub async fn after_delay<F: std::future::Future>(duration: Duration, future: F) -> F::Output {
232 sleep(duration).await;
233 future.await
234}
235
236pub fn timeout_at<F: std::future::Future>(
245 deadline: Instant,
246 future: F,
247) -> crate::timer::Timeout<F> {
248 crate::timer::Timeout::new(future, sleep_until(deadline))
249}
250
251pub fn interval_at(start: Instant, period: Duration) -> crate::timer::Interval {
260 crate::timer::Interval::new_at(start, period)
261}
262
263pub fn yield_now() -> crate::timer::YieldNow {
268 crate::timer::YieldNow(false)
269}
270
271pub fn shutdown_signal() -> crate::ShutdownSignal {
273 let ptr = CTX_SHUTDOWN.with(Cell::get);
274 assert!(
275 !ptr.is_null(),
276 "shutdown_signal() called outside Runtime::block_on"
277 );
278 let waker_ptr = CTX_SHUTDOWN_WAKER.with(Cell::get);
279 let task_waker = unsafe { (*waker_ptr).clone() };
281 crate::ShutdownSignal {
282 flag: ptr,
283 task_waker,
284 }
285}