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 108
use std::{ future::Future, pin::Pin, task::{Context, Poll, Waker}, time::Duration, collections::HashMap, rc::Rc, cell::RefCell, }; type Listeners = HashMap<u32, Box<dyn Fn() + 'static>>; static mut LISTENERS: Option<Listeners> = None; fn get_free_listener_key() -> u32 { let listeners = get_listeners(); for i in 0..u32::max_value() { if listeners.contains_key(&i) { continue; } return i; } return 0; } fn get_listeners() -> &'static mut Listeners { unsafe { if LISTENERS.is_none() { LISTENERS = Some(HashMap::new()); } LISTENERS.as_mut().unwrap() } } fn insert_listener(listener_id: u32, callback: Box<dyn Fn() + 'static>) { let listeners = get_listeners(); listeners.insert(listener_id, callback); } #[no_mangle] fn trigger_timeout(listener_id: u32) { let wake = get_listeners().get(&listener_id).unwrap(); wake(); } #[no_mangle] extern "C" { pub fn request_timeout(listener_id: u32, millis: u32); } pub struct TimerFuture { state: Rc<RefCell<State>>, } struct State { completed: bool, waker: Option<Waker>, } impl Future for TimerFuture { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let mut state = self.state.borrow_mut(); if state.completed { Poll::Ready(()) } else { state.waker = Some(cx.waker().clone()); Poll::Pending } } } unsafe impl Send for TimerFuture { } impl TimerFuture { pub fn new(duration: Duration) -> Self { let listener_id = get_free_listener_key(); let timer = TimerFuture { state: Rc::new(RefCell::new(State { completed: false, waker: None })), }; let listener_state = timer.state.clone(); insert_listener(listener_id, Box::new(move || { let mut state = listener_state.borrow_mut(); state.completed = true; if let Some(waker) = state.waker.take() { std::mem::drop(state); waker.wake(); } })); unsafe { request_timeout(listener_id, duration.as_millis() as u32); } timer } }