Skip to main content

nanvm_lib/vm/array/
rest.rs

1use super::Array;
2use crate::{
3    common::sized_index::SizedIndex,
4    vm::{IVm, ToArray},
5};
6
7impl<A: IVm> Array<A> {
8    /// The arguments from the `i`-th on, as a rest parameter of a call
9    /// whose arguments this array holds reads them: the array itself for
10    /// `i == 0`, since nothing is skipped, and a new array of the items
11    /// from `i` otherwise — empty when `i` is past the end.
12    ///
13    /// The array is the call's own: a call step builds it from the
14    /// argument list, a spread iterated, so no program holds it but the
15    /// callee, and answering it as the rest shares nothing a program can
16    /// see (`fjs/edag/README.md`, "An engine may form the arguments the
17    /// way the callee reads them"). A host calling [`Any::call`](crate::vm::Any::call) with an
18    /// array it keeps is handing the callee that array, and reads it back
19    /// as the rest.
20    pub fn rest(&self, i: u32) -> Array<A> {
21        if i == 0 {
22            return self.clone();
23        }
24        (i..self.length().max(i))
25            .map(|k| self[k].clone())
26            .to_array()
27    }
28}
29
30#[cfg(test)]
31mod tests {
32    use super::Array;
33    use crate::{
34        naive::Naive,
35        vm::{Any, ToAny, ToArray},
36    };
37
38    type A = Naive;
39
40    /// From `0`, the arguments themselves, the one array; from `i`, a new
41    /// array of the items from `i`; from the end or past it, no items.
42    #[test]
43    fn rest() {
44        let args = [1.0.to_any(), 2.0.to_any(), "s".into()].to_array();
45        let items = |a: Array<A>| a.into_iter().collect::<Vec<_>>();
46        assert_eq!(args.rest(0), args);
47        assert_ne!(args.rest(1), args);
48        assert_eq!(items(args.rest(1)), vec![2.0.to_any(), "s".into()]);
49        assert_eq!(items(args.rest(2)), vec!["s".into()]);
50        assert_eq!(items(args.rest(3)), vec![]);
51        assert_eq!(items(args.rest(9)), vec![]);
52        assert_eq!(items(Array::<A>::default().rest(0)), vec![]);
53        let _: Any<A> = args.rest(1).to_any();
54    }
55}