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}