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#[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 string_properties: OrderedHashMap<JsString>,
34 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 #[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 #[inline]
90 pub fn keys(&self) -> Keys<'_> {
91 Keys(self.iter())
92 }
93
94 #[inline]
98 pub fn values(&self) -> Values<'_> {
99 Values(self.iter())
100 }
101
102 #[inline]
107 pub fn symbol_properties(&self) -> SymbolProperties<'_> {
108 SymbolProperties(self.symbol_properties.0.iter())
109 }
110
111 #[inline]
115 pub fn symbol_property_keys(&self) -> SymbolPropertyKeys<'_> {
116 SymbolPropertyKeys(self.symbol_properties.0.keys())
117 }
118
119 #[inline]
123 pub fn symbol_property_values(&self) -> SymbolPropertyValues<'_> {
124 SymbolPropertyValues(self.symbol_properties.0.values())
125 }
126
127 #[inline]
131 pub fn index_properties(&self) -> IndexProperties<'_> {
132 IndexProperties(self.indexed_properties.iter())
133 }
134
135 #[inline]
139 pub fn index_property_keys(&self) -> IndexPropertyKeys<'_> {
140 IndexPropertyKeys(self.indexed_properties.keys())
141 }
142
143 #[inline]
147 pub fn index_property_values(&self) -> IndexPropertyValues<'_> {
148 IndexPropertyValues(self.indexed_properties.values())
149 }
150
151 #[inline]
155 pub fn string_properties(&self) -> StringProperties<'_> {
156 StringProperties(self.string_properties.0.iter())
157 }
158
159 #[inline]
163 pub fn string_property_keys(&self) -> StringPropertyKeys<'_> {
164 StringPropertyKeys(self.string_properties.0.keys())
165 }
166
167 #[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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<'_> {}