1use crate::JavascriptValue;
4use std::collections::BTreeMap;
5
6#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
8pub struct JavascriptSymbol {
9 id: u64,
10 description: Option<String>,
11}
12impl JavascriptSymbol {
13 pub fn id(&self) -> u64 {
15 self.id
16 }
17 pub fn description(&self) -> Option<&str> {
19 self.description.as_deref()
20 }
21}
22
23#[derive(Clone, Debug, Default)]
25pub struct JavascriptSymbolRegistry {
26 next: u64,
27 globals: BTreeMap<String, JavascriptSymbol>,
28}
29impl JavascriptSymbolRegistry {
30 pub fn symbol(&mut self, description: Option<String>) -> JavascriptSymbol {
32 let symbol = JavascriptSymbol {
33 id: self.next,
34 description,
35 };
36 self.next += 1;
37 symbol
38 }
39 pub fn symbol_for(&mut self, key: impl Into<String>) -> JavascriptSymbol {
41 let key = key.into();
42 if let Some(symbol) = self.globals.get(&key) {
43 return symbol.clone();
44 }
45 let symbol = self.symbol(Some(key.clone()));
46 self.globals.insert(key, symbol.clone());
47 symbol
48 }
49 pub fn key_for(&self, symbol: &JavascriptSymbol) -> Option<&str> {
51 self.globals
52 .iter()
53 .find_map(|(key, value)| (value == symbol).then_some(key.as_str()))
54 }
55}
56
57#[derive(Clone, Debug, Eq, PartialEq)]
59pub enum JavascriptCollectionError {
60 Index,
62 Limit,
64}
65
66#[derive(Clone, Debug, Default, PartialEq)]
68pub struct JavascriptArray {
69 elements: Vec<Option<JavascriptValue>>,
70}
71impl JavascriptArray {
72 pub fn dense(values: Vec<JavascriptValue>) -> Self {
74 Self {
75 elements: values.into_iter().map(Some).collect(),
76 }
77 }
78 pub fn sparse(length: usize) -> Self {
80 Self {
81 elements: vec![None; length],
82 }
83 }
84 pub fn len(&self) -> usize {
86 self.elements.len()
87 }
88 pub fn is_empty(&self) -> bool {
90 self.elements.is_empty()
91 }
92 pub fn get(&self, index: usize) -> Option<&JavascriptValue> {
94 self.elements.get(index).and_then(Option::as_ref)
95 }
96 pub fn set(&mut self, index: usize, value: JavascriptValue) {
98 if index >= self.len() {
99 self.elements.resize(index + 1, None);
100 }
101 self.elements[index] = Some(value);
102 }
103 pub fn push(&mut self, value: JavascriptValue) -> usize {
105 self.elements.push(Some(value));
106 self.len()
107 }
108 pub fn pop(&mut self) -> Option<JavascriptValue> {
110 self.elements.pop().flatten()
111 }
112 pub fn values(&self) -> JavascriptIterator {
114 JavascriptIterator::new(
115 self.elements
116 .iter()
117 .map(|v| v.clone().unwrap_or(JavascriptValue::Undefined))
118 .collect(),
119 )
120 }
121 pub fn map(
123 &self,
124 max_visits: usize,
125 mut f: impl FnMut(&JavascriptValue, usize) -> JavascriptValue,
126 ) -> Result<Self, JavascriptCollectionError> {
127 let visits = self.elements.iter().filter(|v| v.is_some()).count();
128 if visits > max_visits {
129 return Err(JavascriptCollectionError::Limit);
130 }
131 Ok(Self {
132 elements: self
133 .elements
134 .iter()
135 .enumerate()
136 .map(|(i, v)| v.as_ref().map(|v| f(v, i)))
137 .collect(),
138 })
139 }
140 pub fn filter(
142 &self,
143 max_visits: usize,
144 mut f: impl FnMut(&JavascriptValue, usize) -> bool,
145 ) -> Result<Self, JavascriptCollectionError> {
146 let mut out = Vec::new();
147 let mut visits = 0;
148 for (i, value) in self.elements.iter().enumerate() {
149 if let Some(value) = value {
150 visits += 1;
151 if visits > max_visits {
152 return Err(JavascriptCollectionError::Limit);
153 }
154 if f(value, i) {
155 out.push(Some(value.clone()));
156 }
157 }
158 }
159 Ok(Self { elements: out })
160 }
161}
162
163#[derive(Clone, Debug, Default, PartialEq)]
165pub struct JavascriptMap {
166 entries: Vec<(JavascriptValue, JavascriptValue)>,
167}
168impl JavascriptMap {
169 pub fn set(&mut self, key: JavascriptValue, value: JavascriptValue) {
171 if let Some(e) = self
172 .entries
173 .iter_mut()
174 .find(|(k, _)| same_value_zero(k, &key))
175 {
176 e.1 = value;
177 } else {
178 self.entries.push((key, value));
179 }
180 }
181 pub fn get(&self, key: &JavascriptValue) -> Option<&JavascriptValue> {
183 self.entries
184 .iter()
185 .find(|(k, _)| same_value_zero(k, key))
186 .map(|e| &e.1)
187 }
188 pub fn delete(&mut self, key: &JavascriptValue) -> bool {
190 if let Some(i) = self
191 .entries
192 .iter()
193 .position(|(k, _)| same_value_zero(k, key))
194 {
195 self.entries.remove(i);
196 true
197 } else {
198 false
199 }
200 }
201 pub fn len(&self) -> usize {
203 self.entries.len()
204 }
205 pub fn is_empty(&self) -> bool {
207 self.entries.is_empty()
208 }
209 pub fn entries(&self) -> impl Iterator<Item = (&JavascriptValue, &JavascriptValue)> {
211 self.entries.iter().map(|(k, v)| (k, v))
212 }
213}
214
215#[derive(Clone, Debug, Default, PartialEq)]
217pub struct JavascriptSet {
218 values: Vec<JavascriptValue>,
219}
220impl JavascriptSet {
221 pub fn add(&mut self, value: JavascriptValue) {
223 if !self.has(&value) {
224 self.values.push(value);
225 }
226 }
227 pub fn has(&self, value: &JavascriptValue) -> bool {
229 self.values.iter().any(|v| same_value_zero(v, value))
230 }
231 pub fn delete(&mut self, value: &JavascriptValue) -> bool {
233 if let Some(i) = self.values.iter().position(|v| same_value_zero(v, value)) {
234 self.values.remove(i);
235 true
236 } else {
237 false
238 }
239 }
240 pub fn len(&self) -> usize {
242 self.values.len()
243 }
244 pub fn is_empty(&self) -> bool {
246 self.values.is_empty()
247 }
248 pub fn values(&self) -> JavascriptIterator {
250 JavascriptIterator::new(self.values.clone())
251 }
252}
253
254#[derive(Clone, Debug, PartialEq)]
256pub struct JavascriptIteratorResult {
257 pub value: Option<JavascriptValue>,
259 pub done: bool,
261}
262#[derive(Clone, Debug)]
264pub struct JavascriptIterator {
265 values: Vec<JavascriptValue>,
266 at: usize,
267}
268impl JavascriptIterator {
269 pub fn new(values: Vec<JavascriptValue>) -> Self {
271 Self { values, at: 0 }
272 }
273 pub fn next_result(&mut self) -> JavascriptIteratorResult {
275 if let Some(value) = self.values.get(self.at).cloned() {
276 self.at += 1;
277 JavascriptIteratorResult {
278 value: Some(value),
279 done: false,
280 }
281 } else {
282 JavascriptIteratorResult {
283 value: None,
284 done: true,
285 }
286 }
287 }
288}
289fn same_value_zero(a: &JavascriptValue, b: &JavascriptValue) -> bool {
290 match (a, b) {
291 (JavascriptValue::Number(a), JavascriptValue::Number(b)) => {
292 a == b || (a.is_nan() && b.is_nan())
293 }
294 _ => a == b,
295 }
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301 #[test]
302 fn arrays_preserve_holes_and_iterators_materialize_undefined() {
303 let mut a = JavascriptArray::sparse(2);
304 a.set(1, JavascriptValue::Number(2.));
305 assert_eq!(a.map(1, |v, _| v.clone()).unwrap().get(0), None);
306 let mut it = a.values();
307 assert_eq!(it.next_result().value, Some(JavascriptValue::Undefined));
308 assert!(!it.next_result().done);
309 assert!(it.next_result().done);
310 }
311 #[test]
312 fn map_set_use_same_value_zero_and_insertion_order() {
313 let mut m = JavascriptMap::default();
314 m.set(
315 JavascriptValue::Number(f64::NAN),
316 JavascriptValue::Number(1.),
317 );
318 m.set(
319 JavascriptValue::Number(f64::NAN),
320 JavascriptValue::Number(2.),
321 );
322 assert_eq!(m.len(), 1);
323 let mut s = JavascriptSet::default();
324 s.add(JavascriptValue::Number(-0.));
325 s.add(JavascriptValue::Number(0.));
326 assert_eq!(s.len(), 1);
327 }
328 #[test]
329 fn symbols_have_identity_and_registry_keys() {
330 let mut r = JavascriptSymbolRegistry::default();
331 assert_ne!(r.symbol(Some("x".into())), r.symbol(Some("x".into())));
332 let s = r.symbol_for("x");
333 assert_eq!(s, r.symbol_for("x"));
334 assert_eq!(r.key_for(&s), Some("x"));
335 }
336}