scheme_rs/
futures.rs

1use crate::{continuation::Continuation, error::RuntimeError, gc::Gc, num::Number, value::Value};
2use futures::{future::try_join_all, FutureExt};
3use scheme_rs_macros::builtin;
4use std::{sync::Arc, time::Duration};
5
6#[builtin("spawn")]
7pub async fn spawn(
8    _cont: &Option<Arc<Continuation>>,
9    arg: &Gc<Value>,
10) -> Result<Vec<Gc<Value>>, RuntimeError> {
11    let value = arg.read().await;
12    let callable = value
13        .as_callable()
14        .ok_or_else(|| RuntimeError::invalid_type("callable", value.type_name()))?;
15    /*
16    let Some(0) = callable.max_args() else {
17        todo!();
18    };
19     */
20    let task = tokio::task::spawn(async move {
21        let val = callable.call(Vec::new(), &None).await?;
22        val.eval(&None).await
23    });
24    let future = async move { task.await.unwrap() }.boxed().shared();
25    Ok(vec![Gc::new(Value::Future(future))])
26}
27
28#[builtin("sleep")]
29pub async fn sleep(
30    _cont: &Option<Arc<Continuation>>,
31    arg: &Gc<Value>,
32) -> Result<Vec<Gc<Value>>, RuntimeError> {
33    let value = arg.read().await;
34    let time: &Number = value.as_ref().try_into()?;
35    let millis = time.to_u64();
36    let future = async move {
37        tokio::time::sleep(Duration::from_millis(millis)).await;
38        Ok(vec![Gc::new(Value::Null)])
39    }
40    .boxed()
41    .shared();
42    Ok(vec![Gc::new(Value::Future(future))])
43}
44
45#[builtin("await")]
46pub async fn await_value(
47    _cont: &Option<Arc<Continuation>>,
48    arg: &Gc<Value>,
49) -> Result<Vec<Gc<Value>>, RuntimeError> {
50    let value = arg.read().await;
51    match &*value {
52        Value::Future(fut) => fut.clone().await,
53        _ => Ok(vec![arg.clone()]),
54    }
55}
56
57#[builtin("join")]
58pub async fn join(
59    _cont: &Option<Arc<Continuation>>,
60    args: Vec<Gc<Value>>,
61) -> Result<Vec<Gc<Value>>, RuntimeError> {
62    let mut futs = Vec::new();
63    for arg in args.into_iter() {
64        let value = arg.read().await;
65        let fut = match &*value {
66            Value::Future(fut) => fut.clone(),
67            _ => {
68                // I can't figure out a way to get rid of this clone
69                // at the current moment without writing annoying code
70                let arg = arg.clone();
71                async move { Ok(vec![arg]) }.boxed().shared()
72            }
73        };
74        futs.push(fut);
75    }
76    let future = async move {
77        let results = try_join_all(futs)
78            .await?
79            .into_iter()
80            .flatten()
81            .collect::<Vec<_>>();
82        Ok(vec![Gc::new(Value::from(results))])
83    }
84    .boxed()
85    .shared();
86    Ok(vec![Gc::new(Value::Future(future))])
87}