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, VmErrorKind, VmResult};
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) -> VmResult<Value>
18where
19    I: IntoIterator<Item = &'a Value>,
20    F: FnOnce(Vec<Value>) -> VmResult<Value>,
21{
22    use futures_util::stream::StreamExt as _;
23
24    let mut futures = futures_util::stream::FuturesUnordered::new();
25    let mut results = vm_try!(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 VmResult::err([
31                    VmErrorKind::expected::<Future>(value.type_info()),
32                    VmErrorKind::bad_argument(index),
33                ]);
34            }
35            Repr::Dynamic(value) => {
36                return VmResult::err([
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 = vm_try!(Value::from(value.clone()).into_future());
44                    futures.push(SelectFuture::new(index, future));
45                    vm_try!(results.try_push(Value::empty()));
46                }
47                _ => {
48                    return VmResult::err([
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) = vm_try!(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) -> VmResult<Value> {
101    match value.as_ref() {
102        Repr::Inline(value) => match value {
103            Inline::Unit => VmResult::Ok(Value::unit()),
104            value => VmResult::err([
105                VmErrorKind::bad_argument(0),
106                VmErrorKind::expected::<runtime::Vec>(value.type_info()),
107            ]),
108        },
109        Repr::Dynamic(value) => VmResult::err([
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 = vm_try!(value.borrow_ref::<runtime::Vec>());
116                let result = try_join_impl(vec.iter(), vec.len(), |vec| {
117                    VmResult::Ok(vm_try!(Value::vec(vec)))
118                })
119                .await;
120                VmResult::Ok(vm_try!(result))
121            }
122            runtime::OwnedTuple::HASH => {
123                let tuple = vm_try!(value.borrow_ref::<runtime::OwnedTuple>());
124
125                let result = try_join_impl(tuple.iter(), tuple.len(), |vec| {
126                    VmResult::Ok(vm_try!(Value::tuple(vec)))
127                })
128                .await;
129
130                VmResult::Ok(vm_try!(result))
131            }
132            _ => VmResult::err([
133                VmErrorKind::bad_argument(0),
134                VmErrorKind::expected::<runtime::Vec>(value.type_info()),
135            ]),
136        },
137    }
138}