use std::collections::BTreeMap;
use bamts_bytecode::EcmaString;
use bamts_native::Value;
use super::install_function;
use crate::intrinsics::{BuiltinOutcome, BuiltinTable};
use crate::{EvalFailure, HeapEntry, Host, Machine, ThrowOrigin};
pub(crate) fn install<H: Host>(
heap: &mut Vec<HeapEntry>,
globals: &mut BTreeMap<EcmaString, Value>,
builtins: &mut BuiltinTable<H>,
) {
let set_timeout = install_function(heap, builtins, "setTimeout", 2, set_timeout::<H>);
globals.insert(EcmaString::from_utf8("setTimeout"), set_timeout);
let clear_timeout = install_function(heap, builtins, "clearTimeout", 1, clear_timeout::<H>);
globals.insert(EcmaString::from_utf8("clearTimeout"), clear_timeout);
}
fn set_timeout<H: Host>(
machine: &mut Machine<'_, H>,
_this: Value,
args: &[Value],
constructing: bool,
) -> Result<BuiltinOutcome, EvalFailure> {
if constructing {
return Err(EvalFailure::Throw(ThrowOrigin::TypeError {
operation: "setTimeout is not a constructor",
}));
}
let callback = args.first().copied().unwrap_or(Value::UNDEFINED);
if !machine.is_callable(callback)? {
return Err(EvalFailure::Throw(ThrowOrigin::TypeError {
operation: "setTimeout callback is not a function",
}));
}
let delay_arg = args.get(1).copied().unwrap_or(Value::UNDEFINED);
let delay_number = super::value_number(machine.to_number_observable(delay_arg)?);
let delay_ms = clamp_delay(delay_number);
let forwarded = args.get(2..).unwrap_or(&[]).to_vec();
let handle = machine.schedule_timeout(callback, delay_ms, forwarded)?;
Ok(BuiltinOutcome::Value(handle))
}
fn clear_timeout<H: Host>(
machine: &mut Machine<'_, H>,
_this: Value,
args: &[Value],
constructing: bool,
) -> Result<BuiltinOutcome, EvalFailure> {
if constructing {
return Err(EvalFailure::Throw(ThrowOrigin::TypeError {
operation: "clearTimeout is not a constructor",
}));
}
let handle = args.first().copied().unwrap_or(Value::UNDEFINED);
machine.clear_timeout(handle)?;
Ok(BuiltinOutcome::Value(Value::UNDEFINED))
}
fn clamp_delay(delay: f64) -> u32 {
if !(1.0..=2_147_483_647.0).contains(&delay) {
1
} else {
delay.trunc() as u32
}
}