bock_core/time.rs
1//! Core time module — registers the `sleep` prelude function.
2//!
3//! `sleep(duration)` spawns a tokio task that suspends for the given duration
4//! and returns `Value::Future` immediately, so concurrent sleeps run in
5//! parallel when driven by `await`. Uses `tokio::time::sleep` under the hood,
6//! which is the asynchronous sleep primitive (does not block an OS thread).
7
8use std::sync::{Arc, Mutex};
9
10use bock_interp::{BuiltinRegistry, RuntimeError, Value};
11
12/// Register the `sleep` global.
13pub fn register(registry: &mut BuiltinRegistry) {
14 registry.register_global("sleep", builtin_sleep);
15}
16
17/// `sleep(duration: Duration) -> Void with Clock` — prelude function.
18///
19/// Returns `Value::Future` immediately; the backing tokio task yields for the
20/// given duration. `await` resolves the future to `Void`.
21fn builtin_sleep(args: &[Value]) -> Result<Value, RuntimeError> {
22 let nanos = match args.first() {
23 Some(Value::Duration(n)) => *n,
24 Some(Value::Int(n)) => *n, // permissive: accept Int as nanoseconds
25 Some(other) => {
26 return Err(RuntimeError::TypeError(format!(
27 "sleep expects Duration, got {other}"
28 )));
29 }
30 None => {
31 return Err(RuntimeError::ArityMismatch {
32 expected: 1,
33 got: 0,
34 });
35 }
36 };
37 let handle = tokio::spawn(async move {
38 if nanos > 0 {
39 let dur = std::time::Duration::from_nanos(nanos as u64);
40 tokio::time::sleep(dur).await;
41 }
42 Ok(Value::Void)
43 });
44 Ok(Value::Future(Arc::new(Mutex::new(Some(handle)))))
45}