Skip to main content

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}