Skip to main content

pepl_stdlib/modules/
timer.rs

1//! `timer` stdlib module — timer management (host-delegated).
2//!
3//! Functions: start, start_once, stop, stop_all.
4//! All timer operations are host-delegated stubs — the runtime host
5//! implements actual scheduling. This module validates arguments and
6//! returns the expected types.
7
8use crate::error::StdlibError;
9use crate::module::StdlibModule;
10use crate::value::Value;
11
12/// The `timer` stdlib module.
13pub struct TimerModule;
14
15impl TimerModule {
16    pub fn new() -> Self {
17        Self
18    }
19}
20
21impl Default for TimerModule {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl StdlibModule for TimerModule {
28    fn name(&self) -> &'static str {
29        "timer"
30    }
31
32    fn has_function(&self, function: &str) -> bool {
33        matches!(function, "start" | "start_once" | "stop" | "stop_all")
34    }
35
36    fn call(&self, function: &str, args: Vec<Value>) -> Result<Value, StdlibError> {
37        match function {
38            "start" => self.start(args),
39            "start_once" => self.start_once(args),
40            "stop" => self.stop(args),
41            "stop_all" => self.stop_all(args),
42            _ => Err(StdlibError::unknown_function("timer", function)),
43        }
44    }
45}
46
47impl TimerModule {
48    /// timer.start(id, interval_ms) → string
49    /// Starts a repeating timer. Returns the timer ID.
50    /// In the stdlib, this is a stub that validates args and returns the ID.
51    fn start(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
52        if args.len() != 2 {
53            return Err(StdlibError::wrong_args("timer.start", 2, args.len()));
54        }
55        let id = extract_string("timer.start", &args[0], 1)?;
56        let _interval = extract_number("timer.start", &args[1], 2)?;
57        Ok(Value::String(id.to_string()))
58    }
59
60    /// timer.start_once(id, delay_ms) → string
61    /// Starts a one-shot timer. Returns the timer ID.
62    fn start_once(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
63        if args.len() != 2 {
64            return Err(StdlibError::wrong_args("timer.start_once", 2, args.len()));
65        }
66        let id = extract_string("timer.start_once", &args[0], 1)?;
67        let _delay = extract_number("timer.start_once", &args[1], 2)?;
68        Ok(Value::String(id.to_string()))
69    }
70
71    /// timer.stop(id) → nil
72    /// Stops a timer by ID. No-op if the timer doesn't exist.
73    fn stop(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
74        if args.len() != 1 {
75            return Err(StdlibError::wrong_args("timer.stop", 1, args.len()));
76        }
77        let _id = extract_string("timer.stop", &args[0], 1)?;
78        Ok(Value::Nil)
79    }
80
81    /// timer.stop_all() → nil
82    /// Stops all active timers.
83    fn stop_all(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
84        if !args.is_empty() {
85            return Err(StdlibError::wrong_args("timer.stop_all", 0, args.len()));
86        }
87        Ok(Value::Nil)
88    }
89}
90
91// ── Helpers ──────────────────────────────────────────────────────────────────
92
93fn extract_string<'a>(func: &str, val: &'a Value, pos: usize) -> Result<&'a str, StdlibError> {
94    match val {
95        Value::String(s) => Ok(s),
96        _ => Err(StdlibError::type_mismatch(
97            func,
98            pos,
99            "string",
100            val.type_name(),
101        )),
102    }
103}
104
105fn extract_number(func: &str, val: &Value, pos: usize) -> Result<f64, StdlibError> {
106    match val {
107        Value::Number(n) => Ok(*n),
108        _ => Err(StdlibError::type_mismatch(
109            func,
110            pos,
111            "number",
112            val.type_name(),
113        )),
114    }
115}