Skip to main content

nanvm_lib/vm/
object_spread.rs

1use core::iter::{Enumerate, FusedIterator};
2
3use crate::{
4    common::index_iter::IndexIter,
5    vm::{Any, Array, IVm, String, ToAny},
6};
7
8/// What [`Any::object_spread`] returns: the entries `{...v}` copies, each a
9/// key and its value, in `[[OwnPropertyKeys]]` order. The object side's
10/// counterpart of [`IteratorRecord`](crate::vm::IteratorRecord), and like
11/// it a Rust iterator, never a VM value.
12///
13/// Copying cannot fail, and neither can creating one: an object spread of
14/// any value is defined, a value with no own enumerable properties giving
15/// none.
16///
17/// ```
18/// use nanvm_lib::{vm::{Any, IVm, Nullish, ToAny, ToArray}, naive::Naive};
19/// fn spread<A: IVm>() {
20///     let a: Any<A> = [Any::from("x")].to_array().to_any();
21///     assert_eq!(a.object_spread().count(), 1);
22///     let s: Any<A> = "๐Ÿ˜€".into();
23///     assert_eq!(s.object_spread().count(), 2);
24///     assert_eq!(Nullish::Null.to_any::<A>().object_spread().count(), 0);
25/// }
26/// spread::<Naive>();
27/// ```
28pub enum ObjectSpread<A: IVm> {
29    /// An object's entries, the deduplicated, ordered view
30    /// [`Object::own_entries`](crate::vm::Object::own_entries) computes
31    /// when the spread is created.
32    Object(std::vec::IntoIter<(String<A>, Any<A>)>),
33    /// An array's elements keyed by index: `"0"`, `"1"`, โ€ฆ `length` is not
34    /// enumerable.
35    Array(Enumerate<IndexIter<u32, Array<A>>>),
36    /// A string's code units keyed by index, each a one-unit string: a
37    /// surrogate pair is two entries, as `{...'๐Ÿ˜€'}` is in JavaScript.
38    String(Enumerate<IndexIter<u32, String<A>>>),
39    /// Every other value: no own enumerable properties.
40    Empty,
41}
42
43/// The key of index `i`, as JavaScript's `ToString(i)` spells it.
44fn index_key<A: IVm>(i: usize) -> String<A> {
45    i.to_string().as_str().into()
46}
47
48impl<A: IVm> Iterator for ObjectSpread<A> {
49    type Item = (String<A>, Any<A>);
50
51    fn next(&mut self) -> Option<(String<A>, Any<A>)> {
52        match self {
53            ObjectSpread::Object(entries) => entries.next(),
54            ObjectSpread::Array(elements) => elements.next().map(|(i, v)| (index_key(i), v)),
55            ObjectSpread::String(units) => units
56                .next()
57                .map(|(i, u)| (index_key(i), String::of_unit(u).to_any())),
58            ObjectSpread::Empty => None,
59        }
60    }
61
62    /// Exact for every variant.
63    fn size_hint(&self) -> (usize, Option<usize>) {
64        let left = match self {
65            ObjectSpread::Object(entries) => entries.len(),
66            ObjectSpread::Array(elements) => elements.len(),
67            ObjectSpread::String(units) => units.len(),
68            ObjectSpread::Empty => 0,
69        };
70        (left, Some(left))
71    }
72}
73
74impl<A: IVm> ExactSizeIterator for ObjectSpread<A> {}
75
76impl<A: IVm> FusedIterator for ObjectSpread<A> {}