use core_mumu::{Interpreter, Value, FunctionValue};
use std::{
ffi::{c_void, CStr},
sync::{Arc, Mutex},
};
use std::time::Instant;
mod timeout;
mod interval;
mod r#loop;
pub use timeout::event_timeout_bridge;
pub use interval::{event_interval_bridge, event_stop_bridge};
pub use r#loop::event_loop_bridge;
use lazy_static::lazy_static;
lazy_static! {
static ref TIMEOUT_TASKS: Mutex<Vec<timeout::TimeoutTask>> = Mutex::new(vec![]);
}
fn poller_fn(interp: &mut Interpreter) -> usize {
let now = Instant::now();
{
let mut tasks = TIMEOUT_TASKS.lock().unwrap();
let mut expired = Vec::new();
for (i, t) in tasks.iter().enumerate() {
if now >= t.deadline {
let _ = timeout::execute_callback(interp, &t.callback);
expired.push(i);
}
}
for &i in expired.iter().rev() {
tasks.remove(i);
}
}
let remaining_timeouts = TIMEOUT_TASKS.lock().unwrap().len();
{
let mut iv = interval::INTERVAL_TASKS.lock().unwrap();
for i in (0..iv.len()).rev() {
let task = &mut iv[i];
if now >= task.next_tick {
let _ = interval::execute_interval_callback(interp, &task.callback);
if !task.canceled {
task.next_tick = now + task.period;
} else {
iv.remove(i);
}
}
}
}
let remaining_intervals = interval::INTERVAL_TASKS.lock().unwrap().len();
let remaining_loops = r#loop::execute_loop_callbacks(interp);
remaining_timeouts + remaining_intervals + remaining_loops
}
pub fn push_timeout_task(task: timeout::TimeoutTask, _interp: &mut Interpreter) {
TIMEOUT_TASKS.lock().unwrap().push(task);
}
pub fn register_all(interp: &mut Interpreter) {
{
let f = Arc::new(Mutex::new(event_timeout_bridge));
interp.register_dynamic_function("event:timeout", f.clone());
interp.set_variable(
"event:timeout",
Value::Function(Box::new(FunctionValue::Named("event:timeout".into()))),
);
}
{
let f = Arc::new(Mutex::new(event_interval_bridge));
interp.register_dynamic_function("event:interval", f.clone());
interp.set_variable(
"event:interval",
Value::Function(Box::new(FunctionValue::Named("event:interval".into()))),
);
}
{
let f = Arc::new(Mutex::new(event_stop_bridge));
interp.register_dynamic_function("event:stop", f.clone());
interp.set_variable(
"event:stop",
Value::Function(Box::new(FunctionValue::Named("event:stop".into()))),
);
}
{
let f = Arc::new(Mutex::new(event_loop_bridge));
interp.register_dynamic_function("event:loop", f.clone());
interp.set_variable(
"event:loop",
Value::Function(Box::new(FunctionValue::Named("event:loop".into()))),
);
}
interp.add_poller(Arc::new(Mutex::new(|intrp: &mut Interpreter| {
poller_fn(intrp)
})));
}
#[cfg(not(target_arch = "wasm32"))]
#[no_mangle]
pub unsafe extern "C" fn Cargo_lock(
interp_ptr: *mut c_void,
extra_str: *const c_void,
) -> i32 {
if interp_ptr.is_null() {
return 1;
}
let interp = &mut *(interp_ptr as *mut Interpreter);
if interp.is_verbose() {
eprintln!("[event] Cargo_lock ⇒ initialising plugin");
if !extra_str.is_null() {
let c = CStr::from_ptr(extra_str as *const i8);
eprintln!("[event] extra arg = '{}'", c.to_string_lossy());
}
}
register_all(interp);
if interp.is_verbose() {
eprintln!("[event] Cargo_lock ⇒ registration complete");
}
0
}