1extern crate alloc;
2
3use futures::{
4 channel::oneshot::{self, Sender},
5 executor::{LocalPool, LocalSpawner},
6 task::{LocalSpawnExt, SpawnError},
7 TryFutureExt,
8};
9
10use core::alloc::Layout;
11use std::future::Future;
12use std::{cell::RefCell, time::Instant};
13use std::{collections::BTreeMap, time::Duration};
14
15#[no_mangle]
16pub unsafe extern "C" fn __cfx_alloc(size: u32, align: u32) -> *mut u8 {
17 let layout = Layout::from_size_align_unchecked(size as _, align as _);
18 alloc::alloc::alloc(layout)
19}
20
21#[no_mangle]
22pub unsafe extern "C" fn __cfx_free(ptr: *mut u8, size: u32, align: u32) {
23 let layout = Layout::from_size_align_unchecked(size as _, align as _);
24 alloc::alloc::dealloc(ptr, layout);
25}
26
27thread_local! {
28 pub(crate) static LOCAL_POOL: RefCell<LocalPool> = RefCell::new(LocalPool::new());
29 static SPAWNER: RefCell<LocalSpawner> = LOCAL_POOL.with(|lp| RefCell::new(lp.borrow().spawner()));
30 static TIMERS: RefCell<BTreeMap<Instant, Vec<Sender<()>>>> = RefCell::new(BTreeMap::new());
31}
32
33pub fn spawn<Fut: Future<Output = ()> + 'static>(future: Fut) -> Result<(), SpawnError> {
35 SPAWNER.with(|sp| sp.borrow().spawn_local(future))
36}
37
38#[no_mangle]
39pub extern "C" fn __cfx_on_tick() {
40 fire_timers();
41
42 LOCAL_POOL.with(|lp| {
43 let mut lp = lp.borrow_mut();
44 lp.run_until_stalled();
45 });
46}
47
48fn fire_timers() {
49 let now = Instant::now();
50
51 TIMERS.with(|timers| {
52 let mut timers = timers.borrow_mut();
53 let expiered: Vec<Instant> = timers.range(..=now).map(|(time, _)| *time).collect();
54
55 for key in expiered {
56 if let Some(senders) = timers.remove(&key) {
57 for tx in senders {
58 let _ = tx.send(());
59 }
60 }
61 }
62 });
63}
64
65pub fn sleep_for(duration: Duration) -> impl Future<Output = ()> {
67 let instant = Instant::now().checked_add(duration).unwrap();
68 let (tx, rx) = oneshot::channel();
69
70 TIMERS.with(|timers| {
71 let mut timers = timers.borrow_mut();
72 let entry = timers.entry(instant).or_insert_with(Vec::new);
73 entry.push(tx);
74 });
75
76 rx.unwrap_or_else(|_| ())
77}