1use core_mumu::{Interpreter, Value, FunctionValue};
18use std::{
19 ffi::{c_void, CStr},
20 sync::{Arc, Mutex},
21};
22use std::time::Instant;
23
24mod timeout;
25mod interval;
26mod r#loop; pub use timeout::event_timeout_bridge;
30pub use interval::{event_interval_bridge, event_stop_bridge};
31pub use r#loop::event_loop_bridge;
32
33use lazy_static::lazy_static;
34
35lazy_static! {
36 static ref TIMEOUT_TASKS: Mutex<Vec<timeout::TimeoutTask>> = Mutex::new(vec![]);
38}
39
40fn poller_fn(interp: &mut Interpreter) -> usize {
43 let now = Instant::now();
44
45 {
47 let mut tasks = TIMEOUT_TASKS.lock().unwrap();
48 let mut expired = Vec::new();
49 for (i, t) in tasks.iter().enumerate() {
50 if now >= t.deadline {
51 let _ = timeout::execute_callback(interp, &t.callback);
52 expired.push(i);
53 }
54 }
55 for &i in expired.iter().rev() {
56 tasks.remove(i);
57 }
58 }
59 let remaining_timeouts = TIMEOUT_TASKS.lock().unwrap().len();
60
61 {
63 let mut iv = interval::INTERVAL_TASKS.lock().unwrap();
64 for i in (0..iv.len()).rev() {
65 let task = &mut iv[i];
66 if now >= task.next_tick {
67 let _ = interval::execute_interval_callback(interp, &task.callback);
68 if !task.canceled {
69 task.next_tick = now + task.period;
70 } else {
71 iv.remove(i);
72 }
73 }
74 }
75 }
76 let remaining_intervals = interval::INTERVAL_TASKS.lock().unwrap().len();
77
78 let remaining_loops = r#loop::execute_loop_callbacks(interp);
80
81 remaining_timeouts + remaining_intervals + remaining_loops
82}
83
84pub fn push_timeout_task(task: timeout::TimeoutTask, _interp: &mut Interpreter) {
86 TIMEOUT_TASKS.lock().unwrap().push(task);
87}
88
89pub fn register_all(interp: &mut Interpreter) {
93 {
95 let f = Arc::new(Mutex::new(event_timeout_bridge));
96 interp.register_dynamic_function("event:timeout", f.clone());
97 interp.set_variable(
98 "event:timeout",
99 Value::Function(Box::new(FunctionValue::Named("event:timeout".into()))),
100 );
101 }
102
103 {
105 let f = Arc::new(Mutex::new(event_interval_bridge));
106 interp.register_dynamic_function("event:interval", f.clone());
107 interp.set_variable(
108 "event:interval",
109 Value::Function(Box::new(FunctionValue::Named("event:interval".into()))),
110 );
111 }
112
113 {
115 let f = Arc::new(Mutex::new(event_stop_bridge));
116 interp.register_dynamic_function("event:stop", f.clone());
117 interp.set_variable(
118 "event:stop",
119 Value::Function(Box::new(FunctionValue::Named("event:stop".into()))),
120 );
121 }
122
123 {
125 let f = Arc::new(Mutex::new(event_loop_bridge));
126 interp.register_dynamic_function("event:loop", f.clone());
127 interp.set_variable(
128 "event:loop",
129 Value::Function(Box::new(FunctionValue::Named("event:loop".into()))),
130 );
131 }
132
133 interp.add_poller(Arc::new(Mutex::new(|intrp: &mut Interpreter| {
135 poller_fn(intrp)
136 })));
137}
138
139#[cfg(not(target_arch = "wasm32"))]
145#[no_mangle]
146pub unsafe extern "C" fn Cargo_lock(
147 interp_ptr: *mut c_void,
148 extra_str: *const c_void,
149) -> i32 {
150 if interp_ptr.is_null() {
151 return 1;
152 }
153 let interp = &mut *(interp_ptr as *mut Interpreter);
154
155 if interp.is_verbose() {
156 eprintln!("[event] Cargo_lock ⇒ initialising plugin");
157 if !extra_str.is_null() {
158 let c = CStr::from_ptr(extra_str as *const i8);
159 eprintln!("[event] extra arg = '{}'", c.to_string_lossy());
160 }
161 }
162
163 register_all(interp);
164
165 if interp.is_verbose() {
166 eprintln!("[event] Cargo_lock ⇒ registration complete");
167 }
168 0
169}