Skip to main content

ferrijs_std/node/
timers.rs

1//! `node:timers` and `node:timers/promises`.
2//!
3//! The callback forms are the runtime's own timer globals, re-exported —
4//! there is one scheduler, and it is the host's. The promise forms are
5//! built on those same globals.
6
7use rquickjs::function::{Func, Opt};
8use rquickjs::{Ctx, Function, Object, Promise, Result, Value};
9
10pub const TIMERS_MEMBERS: &[&str] = &[
11  "clearImmediate",
12  "clearInterval",
13  "clearTimeout",
14  "setImmediate",
15  "setInterval",
16  "setTimeout",
17];
18
19pub const TIMERS_PROMISES_MEMBERS: &[&str] = &["setImmediate", "setTimeout"];
20
21/// Re-export of the host's timer globals.
22///
23/// # Errors
24///
25/// Propagates the global reads and property writes.
26pub fn timers_object<'js>(ctx: &Ctx<'js>) -> Result<Object<'js>> {
27  let timers = Object::new(ctx.clone())?;
28  for name in TIMERS_MEMBERS {
29    if let Ok(value) = ctx.globals().get::<_, Value<'js>>(*name) {
30      if !value.is_undefined() {
31        timers.set(*name, value)?;
32      }
33    }
34  }
35  Ok(timers)
36}
37
38/// `timers/promises`' `setTimeout(delay, value)`: resolve after the host
39/// timer fires, with the value the caller passed.
40fn timeout_promise<'js>(ctx: Ctx<'js>, delay: Opt<f64>, value: Opt<Value<'js>>) -> Result<Promise<'js>> {
41  let (promise, resolve, _reject) = ctx.promise()?;
42  let set_timeout: Function<'js> = ctx.globals().get("setTimeout")?;
43  let carried = value.0.unwrap_or_else(|| Value::new_undefined(ctx.clone()));
44  // The host's `setTimeout` forwards trailing arguments to the callback,
45  // as Node's does, which is what carries the resolution value.
46  set_timeout.call::<_, Value<'js>>((resolve, delay.0.unwrap_or(0.0), carried))?;
47  Ok(promise)
48}
49
50/// `timers/promises`' `setImmediate(value)`.
51fn immediate_promise<'js>(ctx: Ctx<'js>, value: Opt<Value<'js>>) -> Result<Promise<'js>> {
52  let (promise, resolve, _reject) = ctx.promise()?;
53  let set_immediate: Function<'js> = ctx.globals().get("setImmediate")?;
54  let carried = value.0.unwrap_or_else(|| Value::new_undefined(ctx.clone()));
55  set_immediate.call::<_, Value<'js>>((resolve, carried))?;
56  Ok(promise)
57}
58
59/// The promise-returning timer surface.
60///
61/// # Errors
62///
63/// Propagates the property writes.
64pub fn timers_promises_object<'js>(ctx: &Ctx<'js>) -> Result<Object<'js>> {
65  let timers = Object::new(ctx.clone())?;
66  timers.set("setTimeout", Func::from(timeout_promise))?;
67  timers.set("setImmediate", Func::from(immediate_promise))?;
68  Ok(timers)
69}