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> {}