boa/object/
property_map.rs

1use super::{PropertyDescriptor, PropertyKey};
2use crate::{
3    gc::{custom_trace, Finalize, Trace},
4    JsString, JsSymbol,
5};
6use indexmap::IndexMap;
7use rustc_hash::{FxHashMap, FxHasher};
8use std::{collections::hash_map, hash::BuildHasherDefault, iter::FusedIterator};
9
10/// Wrapper around indexmap::IndexMap for usage in PropertyMap
11#[derive(Debug, Finalize)]
12struct OrderedHashMap<K: Trace>(IndexMap<K, PropertyDescriptor, BuildHasherDefault<FxHasher>>);
13
14impl<K: Trace> Default for OrderedHashMap<K> {
15    fn default() -> Self {
16        Self(IndexMap::with_hasher(BuildHasherDefault::default()))
17    }
18}
19
20unsafe impl<K: Trace> Trace for OrderedHashMap<K> {
21    custom_trace!(this, {
22        for (k, v) in this.0.iter() {
23            mark(k);
24            mark(v);
25        }
26    });
27}
28
29#[derive(Default, Debug, Trace, Finalize)]
30pub struct PropertyMap {
31    indexed_properties: FxHashMap<u32, PropertyDescriptor>,
32    /// Properties
33    string_properties: OrderedHashMap<JsString>,
34    /// Symbol Properties
35    symbol_properties: OrderedHashMap<JsSymbol>,
36}
37
38impl PropertyMap {
39    pub fn new() -> Self {
40        Self::default()
41    }
42    pub fn get(&self, key: &PropertyKey) -> Option<&PropertyDescriptor> {
43        match key {
44            PropertyKey::Index(index) => self.indexed_properties.get(index),
45            PropertyKey::String(string) => self.string_properties.0.get(string),
46            PropertyKey::Symbol(symbol) => self.symbol_properties.0.get(symbol),
47        }
48    }
49
50    pub fn insert(
51        &mut self,
52        key: PropertyKey,
53        property: PropertyDescriptor,
54    ) -> Option<PropertyDescriptor> {
55        match &key {
56            PropertyKey::Index(index) => self.indexed_properties.insert(*index, property),
57            PropertyKey::String(string) => {
58                self.string_properties.0.insert(string.clone(), property)
59            }
60            PropertyKey::Symbol(symbol) => {
61                self.symbol_properties.0.insert(symbol.clone(), property)
62            }
63        }
64    }
65
66    pub fn remove(&mut self, key: &PropertyKey) -> Option<PropertyDescriptor> {
67        match key {
68            PropertyKey::Index(index) => self.indexed_properties.remove(index),
69            PropertyKey::String(string) => self.string_properties.0.shift_remove(string),
70            PropertyKey::Symbol(symbol) => self.symbol_properties.0.shift_remove(symbol),
71        }
72    }
73
74    /// An iterator visiting all key-value pairs in arbitrary order. The iterator element type is `(PropertyKey, &'a Property)`.
75    ///
76    /// This iterator does not recurse down the prototype chain.
77    #[inline]
78    pub fn iter(&self) -> Iter<'_> {
79        Iter {
80            indexed_properties: self.indexed_properties.iter(),
81            string_properties: self.string_properties.0.iter(),
82            symbol_properties: self.symbol_properties.0.iter(),
83        }
84    }
85
86    /// An iterator visiting all keys in arbitrary order. The iterator element type is `PropertyKey`.
87    ///
88    /// This iterator does not recurse down the prototype chain.
89    #[inline]
90    pub fn keys(&self) -> Keys<'_> {
91        Keys(self.iter())
92    }
93
94    /// An iterator visiting all values in arbitrary order. The iterator element type is `&'a Property`.
95    ///
96    /// This iterator does not recurse down the prototype chain.
97    #[inline]
98    pub fn values(&self) -> Values<'_> {
99        Values(self.iter())
100    }
101
102    /// An iterator visiting all symbol key-value pairs in arbitrary order. The iterator element type is `(&'a RcSymbol, &'a Property)`.
103    ///
104    ///
105    /// This iterator does not recurse down the prototype chain.
106    #[inline]
107    pub fn symbol_properties(&self) -> SymbolProperties<'_> {
108        SymbolProperties(self.symbol_properties.0.iter())
109    }
110
111    /// An iterator visiting all symbol keys in arbitrary order. The iterator element type is `&'a RcSymbol`.
112    ///
113    /// This iterator does not recurse down the prototype chain.
114    #[inline]
115    pub fn symbol_property_keys(&self) -> SymbolPropertyKeys<'_> {
116        SymbolPropertyKeys(self.symbol_properties.0.keys())
117    }
118
119    /// An iterator visiting all symbol values in arbitrary order. The iterator element type is `&'a Property`.
120    ///
121    /// This iterator does not recurse down the prototype chain.
122    #[inline]
123    pub fn symbol_property_values(&self) -> SymbolPropertyValues<'_> {
124        SymbolPropertyValues(self.symbol_properties.0.values())
125    }
126
127    /// An iterator visiting all indexed key-value pairs in arbitrary order. The iterator element type is `(&'a u32, &'a Property)`.
128    ///
129    /// This iterator does not recurse down the prototype chain.
130    #[inline]
131    pub fn index_properties(&self) -> IndexProperties<'_> {
132        IndexProperties(self.indexed_properties.iter())
133    }
134
135    /// An iterator visiting all index keys in arbitrary order. The iterator element type is `&'a u32`.
136    ///
137    /// This iterator does not recurse down the prototype chain.
138    #[inline]
139    pub fn index_property_keys(&self) -> IndexPropertyKeys<'_> {
140        IndexPropertyKeys(self.indexed_properties.keys())
141    }
142
143    /// An iterator visiting all index values in arbitrary order. The iterator element type is `&'a Property`.
144    ///
145    /// This iterator does not recurse down the prototype chain.
146    #[inline]
147    pub fn index_property_values(&self) -> IndexPropertyValues<'_> {
148        IndexPropertyValues(self.indexed_properties.values())
149    }
150
151    /// An iterator visiting all string key-value pairs in arbitrary order. The iterator element type is `(&'a RcString, &'a Property)`.
152    ///
153    /// This iterator does not recurse down the prototype chain.
154    #[inline]
155    pub fn string_properties(&self) -> StringProperties<'_> {
156        StringProperties(self.string_properties.0.iter())
157    }
158
159    /// An iterator visiting all string keys in arbitrary order. The iterator element type is `&'a RcString`.
160    ///
161    /// This iterator does not recurse down the prototype chain.
162    #[inline]
163    pub fn string_property_keys(&self) -> StringPropertyKeys<'_> {
164        StringPropertyKeys(self.string_properties.0.keys())
165    }
166
167    /// An iterator visiting all string values in arbitrary order. The iterator element type is `&'a Property`.
168    ///
169    /// This iterator does not recurse down the prototype chain.
170    #[inline]
171    pub fn string_property_values(&self) -> StringPropertyValues<'_> {
172        StringPropertyValues(self.string_properties.0.values())
173    }
174
175    #[inline]
176    pub fn contains_key(&self, key: &PropertyKey) -> bool {
177        match key {
178            PropertyKey::Index(index) => self.indexed_properties.contains_key(index),
179            PropertyKey::String(string) => self.string_properties.0.contains_key(string),
180            PropertyKey::Symbol(symbol) => self.symbol_properties.0.contains_key(symbol),
181        }
182    }
183}
184
185/// An iterator over the property entries of an `Object`
186#[derive(Debug, Clone)]
187pub struct Iter<'a> {
188    indexed_properties: hash_map::Iter<'a, u32, PropertyDescriptor>,
189    string_properties: indexmap::map::Iter<'a, JsString, PropertyDescriptor>,
190    symbol_properties: indexmap::map::Iter<'a, JsSymbol, PropertyDescriptor>,
191}
192
193impl<'a> Iterator for Iter<'a> {
194    type Item = (PropertyKey, &'a PropertyDescriptor);
195    fn next(&mut self) -> Option<Self::Item> {
196        if let Some((key, value)) = self.indexed_properties.next() {
197            Some(((*key).into(), value))
198        } else if let Some((key, value)) = self.string_properties.next() {
199            Some((key.clone().into(), value))
200        } else {
201            let (key, value) = self.symbol_properties.next()?;
202            Some((key.clone().into(), value))
203        }
204    }
205}
206
207impl ExactSizeIterator for Iter<'_> {
208    #[inline]
209    fn len(&self) -> usize {
210        self.indexed_properties.len() + self.string_properties.len() + self.symbol_properties.len()
211    }
212}
213
214impl FusedIterator for Iter<'_> {}
215
216/// An iterator over the keys (`PropertyKey`) of an `Object`.
217#[derive(Debug, Clone)]
218pub struct Keys<'a>(Iter<'a>);
219
220impl<'a> Iterator for Keys<'a> {
221    type Item = PropertyKey;
222    fn next(&mut self) -> Option<Self::Item> {
223        let (key, _) = self.0.next()?;
224        Some(key)
225    }
226}
227
228impl ExactSizeIterator for Keys<'_> {
229    #[inline]
230    fn len(&self) -> usize {
231        self.0.len()
232    }
233}
234
235impl FusedIterator for Keys<'_> {}
236
237/// An iterator over the values (`Property`) of an `Object`.
238#[derive(Debug, Clone)]
239pub struct Values<'a>(Iter<'a>);
240
241impl<'a> Iterator for Values<'a> {
242    type Item = &'a PropertyDescriptor;
243    fn next(&mut self) -> Option<Self::Item> {
244        let (_, value) = self.0.next()?;
245        Some(value)
246    }
247}
248
249impl ExactSizeIterator for Values<'_> {
250    #[inline]
251    fn len(&self) -> usize {
252        self.0.len()
253    }
254}
255
256impl FusedIterator for Values<'_> {}
257
258/// An iterator over the `Symbol` property entries of an `Object`
259#[derive(Debug, Clone)]
260pub struct SymbolProperties<'a>(indexmap::map::Iter<'a, JsSymbol, PropertyDescriptor>);
261
262impl<'a> Iterator for SymbolProperties<'a> {
263    type Item = (&'a JsSymbol, &'a PropertyDescriptor);
264
265    #[inline]
266    fn next(&mut self) -> Option<Self::Item> {
267        self.0.next()
268    }
269
270    #[inline]
271    fn size_hint(&self) -> (usize, Option<usize>) {
272        self.0.size_hint()
273    }
274}
275
276impl ExactSizeIterator for SymbolProperties<'_> {
277    #[inline]
278    fn len(&self) -> usize {
279        self.0.len()
280    }
281}
282
283impl FusedIterator for SymbolProperties<'_> {}
284
285/// An iterator over the keys (`RcSymbol`) of an `Object`.
286#[derive(Debug, Clone)]
287pub struct SymbolPropertyKeys<'a>(indexmap::map::Keys<'a, JsSymbol, PropertyDescriptor>);
288
289impl<'a> Iterator for SymbolPropertyKeys<'a> {
290    type Item = &'a JsSymbol;
291
292    #[inline]
293    fn next(&mut self) -> Option<Self::Item> {
294        self.0.next()
295    }
296
297    #[inline]
298    fn size_hint(&self) -> (usize, Option<usize>) {
299        self.0.size_hint()
300    }
301}
302
303impl ExactSizeIterator for SymbolPropertyKeys<'_> {
304    #[inline]
305    fn len(&self) -> usize {
306        self.0.len()
307    }
308}
309
310impl FusedIterator for SymbolPropertyKeys<'_> {}
311
312/// An iterator over the `Symbol` values (`Property`) of an `Object`.
313#[derive(Debug, Clone)]
314pub struct SymbolPropertyValues<'a>(indexmap::map::Values<'a, JsSymbol, PropertyDescriptor>);
315
316impl<'a> Iterator for SymbolPropertyValues<'a> {
317    type Item = &'a PropertyDescriptor;
318
319    #[inline]
320    fn next(&mut self) -> Option<Self::Item> {
321        self.0.next()
322    }
323
324    #[inline]
325    fn size_hint(&self) -> (usize, Option<usize>) {
326        self.0.size_hint()
327    }
328}
329
330impl ExactSizeIterator for SymbolPropertyValues<'_> {
331    #[inline]
332    fn len(&self) -> usize {
333        self.0.len()
334    }
335}
336
337impl FusedIterator for SymbolPropertyValues<'_> {}
338
339/// An iterator over the indexed property entries of an `Object`
340#[derive(Debug, Clone)]
341pub struct IndexProperties<'a>(hash_map::Iter<'a, u32, PropertyDescriptor>);
342
343impl<'a> Iterator for IndexProperties<'a> {
344    type Item = (&'a u32, &'a PropertyDescriptor);
345
346    #[inline]
347    fn next(&mut self) -> Option<Self::Item> {
348        self.0.next()
349    }
350
351    #[inline]
352    fn size_hint(&self) -> (usize, Option<usize>) {
353        self.0.size_hint()
354    }
355}
356
357impl ExactSizeIterator for IndexProperties<'_> {
358    #[inline]
359    fn len(&self) -> usize {
360        self.0.len()
361    }
362}
363
364impl FusedIterator for IndexProperties<'_> {}
365
366/// An iterator over the index keys (`u32`) of an `Object`.
367#[derive(Debug, Clone)]
368pub struct IndexPropertyKeys<'a>(hash_map::Keys<'a, u32, PropertyDescriptor>);
369
370impl<'a> Iterator for IndexPropertyKeys<'a> {
371    type Item = &'a u32;
372
373    #[inline]
374    fn next(&mut self) -> Option<Self::Item> {
375        self.0.next()
376    }
377
378    #[inline]
379    fn size_hint(&self) -> (usize, Option<usize>) {
380        self.0.size_hint()
381    }
382}
383
384impl ExactSizeIterator for IndexPropertyKeys<'_> {
385    #[inline]
386    fn len(&self) -> usize {
387        self.0.len()
388    }
389}
390
391impl FusedIterator for IndexPropertyKeys<'_> {}
392
393/// An iterator over the index values (`Property`) of an `Object`.
394#[derive(Debug, Clone)]
395pub struct IndexPropertyValues<'a>(hash_map::Values<'a, u32, PropertyDescriptor>);
396
397impl<'a> Iterator for IndexPropertyValues<'a> {
398    type Item = &'a PropertyDescriptor;
399
400    #[inline]
401    fn next(&mut self) -> Option<Self::Item> {
402        self.0.next()
403    }
404
405    #[inline]
406    fn size_hint(&self) -> (usize, Option<usize>) {
407        self.0.size_hint()
408    }
409}
410
411impl ExactSizeIterator for IndexPropertyValues<'_> {
412    #[inline]
413    fn len(&self) -> usize {
414        self.0.len()
415    }
416}
417
418impl FusedIterator for IndexPropertyValues<'_> {}
419
420/// An iterator over the `String` property entries of an `Object`
421#[derive(Debug, Clone)]
422pub struct StringProperties<'a>(indexmap::map::Iter<'a, JsString, PropertyDescriptor>);
423
424impl<'a> Iterator for StringProperties<'a> {
425    type Item = (&'a JsString, &'a PropertyDescriptor);
426
427    #[inline]
428    fn next(&mut self) -> Option<Self::Item> {
429        self.0.next()
430    }
431
432    #[inline]
433    fn size_hint(&self) -> (usize, Option<usize>) {
434        self.0.size_hint()
435    }
436}
437
438impl ExactSizeIterator for StringProperties<'_> {
439    #[inline]
440    fn len(&self) -> usize {
441        self.0.len()
442    }
443}
444
445impl FusedIterator for StringProperties<'_> {}
446
447/// An iterator over the string keys (`RcString`) of an `Object`.
448#[derive(Debug, Clone)]
449pub struct StringPropertyKeys<'a>(indexmap::map::Keys<'a, JsString, PropertyDescriptor>);
450
451impl<'a> Iterator for StringPropertyKeys<'a> {
452    type Item = &'a JsString;
453
454    #[inline]
455    fn next(&mut self) -> Option<Self::Item> {
456        self.0.next()
457    }
458
459    #[inline]
460    fn size_hint(&self) -> (usize, Option<usize>) {
461        self.0.size_hint()
462    }
463}
464
465impl ExactSizeIterator for StringPropertyKeys<'_> {
466    #[inline]
467    fn len(&self) -> usize {
468        self.0.len()
469    }
470}
471
472impl FusedIterator for StringPropertyKeys<'_> {}
473
474/// An iterator over the string values (`Property`) of an `Object`.
475#[derive(Debug, Clone)]
476pub struct StringPropertyValues<'a>(indexmap::map::Values<'a, JsString, PropertyDescriptor>);
477
478impl<'a> Iterator for StringPropertyValues<'a> {
479    type Item = &'a PropertyDescriptor;
480
481    #[inline]
482    fn next(&mut self) -> Option<Self::Item> {
483        self.0.next()
484    }
485
486    #[inline]
487    fn size_hint(&self) -> (usize, Option<usize>) {
488        self.0.size_hint()
489    }
490}
491
492impl ExactSizeIterator for StringPropertyValues<'_> {
493    #[inline]
494    fn len(&self) -> usize {
495        self.0.len()
496    }
497}
498
499impl FusedIterator for StringPropertyValues<'_> {}