rune/modules/
future.rs

1//! Asynchronous computations.
2
3use crate as rune;
4use crate::alloc::Vec;
5use crate::runtime::{self, Future, Inline, Repr, SelectFuture, Value, VmError, VmErrorKind};
6use crate::{ContextError, Module, TypeHash};
7
8/// Asynchronous computations.
9#[rune::module(::std::future)]
10pub fn module() -> Result<Module, ContextError> {
11    let mut module = Module::from_meta(self::module__meta)?;
12    module.ty::<Future>()?;
13    module.function_meta(join__meta)?;
14    Ok(module)
15}
16
17async fn try_join_impl<'a, I, F>(values: I, len: usize, factory: F) -> Result<Value, VmError>
18where
19    I: IntoIterator<Item = &'a Value>,
20    F: FnOnce(Vec<Value>) -> Result<Value, VmError>,
21{
22    use futures_util::stream::StreamExt as _;
23
24    let mut futures = futures_util::stream::FuturesUnordered::new();
25    let mut results = Vec::try_with_capacity(len)?;
26
27    for (index, value) in values.into_iter().enumerate() {
28        match value.as_ref() {
29            Repr::Inline(value) => {
30                return Err(VmError::from([
31                    VmErrorKind::expected::<Future>(value.type_info()),
32                    VmErrorKind::bad_argument(index),
33                ]));
34            }
35            Repr::Dynamic(value) => {
36                return Err(VmError::from([
37                    VmErrorKind::expected::<Future>(value.type_info()),
38                    VmErrorKind::bad_argument(index),
39                ]));
40            }
41            Repr::Any(value) => match value.type_hash() {
42                Future::HASH => {
43                    let future = Value::from(value.clone()).into_future()?;
44                    futures.push(SelectFuture::new(index, future));
45                    results.try_push(Value::empty())?;
46                }
47                _ => {
48                    return Err(VmError::from([
49                        VmErrorKind::expected::<Future>(value.type_info()),
50                        VmErrorKind::bad_argument(index),
51                    ]));
52                }
53            },
54        }
55    }
56
57    while !futures.is_empty() {
58        let (index, value) = futures.next().await.unwrap()?;
59        *results.get_mut(index).unwrap() = value;
60    }
61
62    factory(results)
63}
64
65/// Waits for a collection of futures to complete and joins their result.
66///
67/// # Examples
68///
69/// ```rune
70/// use std::future;
71///
72/// let a = async { 1 };
73/// let b = async { 2 };
74/// let (a, b) = future::join((a, b)).await;
75/// assert_eq!(1, a);
76/// assert_eq!(2, b);
77/// ```
78///
79/// Using a vector:
80///
81/// ```rune
82/// use std::future;
83///
84/// let a = async { 1 };
85/// let b = async { 2 };
86/// let [a, b] = future::join([a, b]).await;
87/// assert_eq!(1, a);
88/// assert_eq!(2, b);
89/// ```
90///
91/// Joining an empty collection:
92///
93/// ```rune
94/// use std::future;
95///
96/// let () = future::join(()).await;
97/// let [] = future::join([]).await;
98/// ```
99#[rune::function(keep)]
100async fn join(value: Value) -> Result<Value, VmError> {
101    match value.as_ref() {
102        Repr::Inline(value) => match value {
103            Inline::Unit => Ok(Value::unit()),
104            value => Err(VmError::from([
105                VmErrorKind::bad_argument(0),
106                VmErrorKind::expected::<runtime::Vec>(value.type_info()),
107            ])),
108        },
109        Repr::Dynamic(value) => Err(VmError::from([
110            VmErrorKind::bad_argument(0),
111            VmErrorKind::expected::<runtime::Vec>(value.type_info()),
112        ])),
113        Repr::Any(value) => match value.type_hash() {
114            runtime::Vec::HASH => {
115                let vec = value.borrow_ref::<runtime::Vec>()?;
116                let result = try_join_impl(vec.iter(), vec.len(), |vec| {
117                    Value::vec(vec).map_err(VmError::from)
118                })
119                .await;
120                Ok(result?)
121            }
122            runtime::OwnedTuple::HASH => {
123                let tuple = value.borrow_ref::<runtime::OwnedTuple>()?;
124
125                let result = try_join_impl(tuple.iter(), tuple.len(), |vec| {
126                    Value::tuple(vec).map_err(VmError::from)
127                })
128                .await;
129
130                Ok(result?)
131            }
132            _ => Err(VmError::from([
133                VmErrorKind::bad_argument(0),
134                VmErrorKind::expected::<runtime::Vec>(value.type_info()),
135            ])),
136        },
137    }
138}