1use std::collections::HashMap;
13use std::sync::Arc as Rc;
14
15use crate::nan_value::{Arena, NanIntExt, NanValue};
16use crate::value::{RuntimeError, Value};
17
18pub fn register(global: &mut HashMap<String, Value>) {
19 let mut members = HashMap::new();
20 for method in &["now", "unixMs", "sleep"] {
21 members.insert(
22 method.to_string(),
23 Value::Builtin(format!("Time.{}", method)),
24 );
25 }
26 global.insert(
27 "Time".to_string(),
28 Value::Namespace {
29 name: "Time".to_string(),
30 members,
31 },
32 );
33}
34
35pub const DECLARED_EFFECTS: &[&str] = &["Time.now", "Time.unixMs", "Time.sleep"];
36
37pub fn effects(name: &str) -> &'static [&'static str] {
38 match name {
39 "Time.now" => &["Time.now"],
40 "Time.unixMs" => &["Time.unixMs"],
41 "Time.sleep" => &["Time.sleep"],
42 _ => &[],
43 }
44}
45
46pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
47 match name {
48 "Time.now" => Some(now(args)),
49 "Time.unixMs" => Some(unix_ms(args)),
50 "Time.sleep" => Some(sleep(args)),
51 _ => None,
52 }
53}
54
55fn now(args: &[Value]) -> Result<Value, RuntimeError> {
56 if !args.is_empty() {
57 return Err(RuntimeError::Error(format!(
58 "Time.now() takes 0 arguments, got {}",
59 args.len()
60 )));
61 }
62 Ok(Value::Str(aver_rt::time_now()))
63}
64
65fn unix_ms(args: &[Value]) -> Result<Value, RuntimeError> {
66 if !args.is_empty() {
67 return Err(RuntimeError::Error(format!(
68 "Time.unixMs() takes 0 arguments, got {}",
69 args.len()
70 )));
71 }
72 Ok(Value::int(aver_rt::time_unix_ms()))
73}
74
75fn sleep(args: &[Value]) -> Result<Value, RuntimeError> {
76 let [ms] = args else {
77 return Err(RuntimeError::Error(format!(
78 "Time.sleep() takes 1 argument (ms), got {}",
79 args.len()
80 )));
81 };
82 let Value::Int(ms) = ms else {
83 return Err(RuntimeError::Error(
84 "Time.sleep: ms must be an Int".to_string(),
85 ));
86 };
87 let Some(ms) = ms.to_i64() else {
88 return Err(RuntimeError::Error(
89 "Time.sleep: ms must fit a 64-bit integer".to_string(),
90 ));
91 };
92 if ms < 0 {
93 return Err(RuntimeError::Error(
94 "Time.sleep: ms must be non-negative".to_string(),
95 ));
96 }
97 aver_rt::time_sleep(ms);
98 Ok(Value::Unit)
99}
100
101pub fn register_nv(global: &mut HashMap<String, NanValue>, arena: &mut Arena) {
104 let methods = &["now", "unixMs", "sleep"];
105 let mut members: Vec<(Rc<str>, NanValue)> = Vec::with_capacity(methods.len());
106 for method in methods {
107 let idx = arena.push_builtin(&format!("Time.{}", method));
108 members.push((Rc::from(*method), NanValue::new_builtin(idx)));
109 }
110 let ns_idx = arena.push(crate::nan_value::ArenaEntry::Namespace {
111 name: Rc::from("Time"),
112 members,
113 });
114 global.insert("Time".to_string(), NanValue::new_namespace(ns_idx));
115}
116
117pub fn call_nv(
118 name: &str,
119 args: &[NanValue],
120 arena: &mut Arena,
121) -> Option<Result<NanValue, RuntimeError>> {
122 match name {
123 "Time.now" => Some(now_nv(args, arena)),
124 "Time.unixMs" => Some(unix_ms_nv(args, arena)),
125 "Time.sleep" => Some(sleep_nv(args, arena)),
126 _ => None,
127 }
128}
129
130fn now_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
131 if !args.is_empty() {
132 return Err(RuntimeError::Error(format!(
133 "Time.now() takes 0 arguments, got {}",
134 args.len()
135 )));
136 }
137 let s = aver_rt::time_now();
138 Ok(NanValue::new_string_value(&s, arena))
139}
140
141fn unix_ms_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
142 if !args.is_empty() {
143 return Err(RuntimeError::Error(format!(
144 "Time.unixMs() takes 0 arguments, got {}",
145 args.len()
146 )));
147 }
148 Ok(NanValue::new_int(aver_rt::time_unix_ms(), arena))
149}
150
151fn sleep_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
152 if args.len() != 1 {
153 return Err(RuntimeError::Error(format!(
154 "Time.sleep() takes 1 argument (ms), got {}",
155 args.len()
156 )));
157 }
158 if !args[0].is_int() {
159 return Err(RuntimeError::Error(
160 "Time.sleep: ms must be an Int".to_string(),
161 ));
162 }
163 let Some(ms) = args[0].as_aver_int(arena).to_i64() else {
164 return Err(RuntimeError::Error(
165 "Time.sleep: ms must fit a 64-bit integer".to_string(),
166 ));
167 };
168 if ms < 0 {
169 return Err(RuntimeError::Error(
170 "Time.sleep: ms must be non-negative".to_string(),
171 ));
172 }
173 aver_rt::time_sleep(ms);
174 Ok(NanValue::UNIT)
175}