1use crate::vm::{
2 Any, IVm, ObjectSpread, ToAny, ToArray, Unpacked, member_access::non_nullish_receiver,
3};
4
5impl<A: IVm> Any<A> {
6 pub fn object_spread(self) -> ObjectSpread<A> {
20 match self.into() {
21 Unpacked::Object(object) => ObjectSpread::Object(object.own_entries().into_iter()),
22 Unpacked::Array(array) => ObjectSpread::Array(array.into_iter().enumerate()),
23 Unpacked::String(string) => ObjectSpread::String(string.into_iter().enumerate()),
24 _ => ObjectSpread::Empty,
25 }
26 }
27
28 pub fn entries(self) -> Result<Self, Self> {
40 non_nullish_receiver(self.clone())?;
41 Ok(self
42 .object_spread()
43 .map(|(key, value)| [key.to_any(), value].to_array().to_any())
44 .to_array()
45 .to_any())
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use crate::{
52 naive::Naive,
53 vm::{
54 Any, IVm, Nullish, String, ToAny, ToArray, ToObject, ToString,
55 unstable::{bigint_any, f64_any},
56 },
57 };
58
59 type A = Naive;
60
61 fn s(x: &str) -> Any<A> {
62 x.into()
63 }
64
65 fn key(x: &str) -> String<A> {
66 x.into()
67 }
68
69 fn units(u: &[u16]) -> Any<A> {
70 let s: String<A> = u.iter().copied().to_string();
71 s.to_any()
72 }
73
74 fn spread(v: Any<A>) -> Vec<(String<A>, Any<A>)> {
75 v.object_spread().collect()
76 }
77
78 #[test]
82 fn object_entries_in_own_property_order() {
83 let o: Any<A> = [
84 (key("b"), s("1")),
85 (key("10"), s("2")),
86 (key("2"), s("3")),
87 (key("b"), s("4")),
88 ]
89 .to_object()
90 .to_any();
91 assert_eq!(
92 spread(o),
93 [(key("2"), s("3")), (key("10"), s("2")), (key("b"), s("4"))]
94 );
95 }
96
97 #[test]
98 fn array_elements_by_index() {
99 let a: Any<A> = [s("x"), s("y")].to_array().to_any();
100 assert_eq!(spread(a), [(key("0"), s("x")), (key("1"), s("y"))]);
101 }
102
103 #[test]
106 fn string_code_units() {
107 assert_eq!(
108 spread(s("๐")),
109 [(key("0"), units(&[0xD83D])), (key("1"), units(&[0xDE00]))]
110 );
111 assert!(spread(s("")).is_empty());
112 }
113
114 #[test]
116 fn no_own_properties() {
117 let values: [Any<A>; 7] = [
118 Nullish::Null.to_any(),
119 Any::undefined(),
120 true.to_any(),
121 f64_any(0x3ff0_0000_0000_0000),
122 bigint_any(1),
123 [].to_object().to_any(),
124 A::static_function(|_, _| Ok(Any::undefined()), 0, [].to_array(), None).to_any(),
125 ];
126 for v in values {
127 assert!(spread(v).is_empty());
128 }
129 }
130
131 fn entries(v: Any<A>) -> std::string::String {
132 v.entries().unwrap().to_json().unwrap()
133 }
134
135 #[test]
139 fn entries_pairs() {
140 let o: Any<A> = [(key("b"), s("1")), (key("1"), s("2")), (key("b"), s("3"))]
141 .to_object()
142 .to_any();
143 assert_eq!(entries(o), r#"[["1","2"],["b","3"]]"#);
144 assert_eq!(entries([s("x")].to_array().to_any()), r#"[["0","x"]]"#);
145 assert_eq!(entries(s("ab")), r#"[["0","a"],["1","b"]]"#);
146 let f: Any<A> =
147 A::static_function(|_, _| Ok(Any::undefined()), 0, [].to_array(), None).to_any();
148 for v in [true.to_any(), bigint_any(1), [].to_object().to_any(), f] {
149 assert_eq!(entries(v), "[]");
150 }
151 }
152
153 #[test]
156 fn entries_fresh_and_nullish() {
157 let a: Any<A> = [s("x")].to_array().to_any();
158 assert_ne!(a.clone().entries(), a.entries());
159 assert!(Nullish::Null.to_any::<A>().entries().is_err());
160 assert!(Any::<A>::undefined().entries().is_err());
161 }
162
163 #[test]
164 fn exact_size_hints() {
165 let mut a = [s("x"), s("y")].to_array().to_any::<A>().object_spread();
166 assert_eq!(a.size_hint(), (2, Some(2)));
167 a.next();
168 assert_eq!(a.len(), 1);
169 assert_eq!(s("๐").object_spread().len(), 2);
170 let o: Any<A> = [(key("a"), s("1")), (key("a"), s("2"))]
171 .to_object()
172 .to_any();
173 assert_eq!(o.object_spread().len(), 1);
174 let mut e = Nullish::Null.to_any::<A>().object_spread();
175 assert_eq!(e.size_hint(), (0, Some(0)));
176 assert!(e.next().is_none());
177 }
178}