1use js::*;
2use std::collections::HashMap;
3use std::sync::Mutex;
4
5use crate::{get_property_f64, get_property_i64};
6
7pub type TimerHandle = f64;
8
9static ANIMATION_FRAME_EVENT_HANDLERS: Mutex<
10 Option<HashMap<i64, Box<dyn FnMut() + Send + 'static>>>,
11> = Mutex::new(None);
12
13#[no_mangle]
14pub extern "C" fn web_one_time_empty_handler(id: i64) {
15 let mut c = None;
16 {
17 let mut handlers = ANIMATION_FRAME_EVENT_HANDLERS.lock().unwrap();
18 if let Some(h) = handlers.as_mut() {
19 if let Some(handler) = h.remove(&id) {
21 c = Some(handler);
22 }
23 }
24 }
25 if let Some(mut c) = c {
26 c();
27 }
28}
29
30pub fn request_animation_frame(handler: impl FnMut() + Send + Sync + 'static) {
31 let function_handle = js!(r#"
32 function(){
33 const handler = () => {
34 this.module.instance.exports.web_one_time_empty_handler(id);
35 this.releaseObject(id);
36 };
37 const id = this.storeObject(handler);
38 requestAnimationFrame(handler);
39 return id;
40 }"#)
41 .invoke_and_return_bigint(&[]);
42 let mut h = ANIMATION_FRAME_EVENT_HANDLERS.lock().unwrap();
43 if h.is_none() {
44 *h = Some(HashMap::new());
45 }
46 h.as_mut()
47 .unwrap()
48 .insert(function_handle, Box::new(handler));
49}
50
51pub fn set_timeout(
52 handler: impl FnMut() + 'static + Send + Sync,
53 ms: impl Into<f64>,
54) -> TimerHandle {
55 let obj_handle = js!(r#"
56 function(ms){
57 const handler = () => {
58 this.module.instance.exports.web_one_time_empty_handler(id);
59 this.releaseObject(id);
60 };
61 const id = this.storeObject(handler);
62 const handle = window.setTimeout(handler, ms);
63 return {id,handle};
64 }"#)
65 .invoke_and_return_object(&[ms.into().into()]);
66 let function_handle = get_property_i64(&obj_handle, "id");
67 let timer_handle = get_property_f64(&obj_handle, "handle");
68 let mut h = ANIMATION_FRAME_EVENT_HANDLERS.lock().unwrap();
69 if h.is_none() {
70 *h = Some(HashMap::new());
71 }
72 h.as_mut()
73 .unwrap()
74 .insert(function_handle, Box::new(handler));
75 timer_handle
76}
77
78pub fn clear_timeout(interval_id: impl Into<f64>) {
79 let clear_interval = js!(r#"
80 function(interval_id){
81 window.clearTimeout(interval_id);
82 }"#);
83 clear_interval.invoke(&[interval_id.into().into()]);
84}