1use super::{
2 JsPrototype, ObjectStorage, PropertyDescriptor, PropertyKey,
3 shape::{
4 ChangeTransitionAction, RootShape, Shape, UniqueShape,
5 property_table::PropertyTableInner,
6 shared_shape::TransitionKey,
7 slot::{Slot, SlotAttributes},
8 },
9};
10use crate::value::JsVariant;
11use crate::{JsValue, property::PropertyDescriptorBuilder};
12use boa_gc::{Finalize, Trace};
13use rustc_hash::FxHashMap;
14use std::{collections::hash_map, iter::FusedIterator};
15use thin_vec::ThinVec;
16
17#[derive(Debug, Trace, Finalize)]
37pub enum IndexedProperties {
38 DenseI32(ThinVec<i32>),
40
41 DenseF64(ThinVec<f64>),
43
44 DenseElement(ThinVec<JsValue>),
46
47 SparseElement(Box<FxHashMap<u32, JsValue>>),
49
50 SparseProperty(Box<FxHashMap<u32, PropertyDescriptor>>),
52}
53
54impl Default for IndexedProperties {
55 #[inline]
56 fn default() -> Self {
57 Self::DenseI32(ThinVec::new())
58 }
59}
60
61impl IndexedProperties {
62 pub(crate) fn from_dense_js_value(elements: ThinVec<JsValue>) -> Self {
63 if elements.is_empty() {
64 return Self::default();
65 }
66 Self::DenseElement(elements)
67 }
68
69 #[inline]
70 fn property_simple_value(property: &PropertyDescriptor) -> Option<&JsValue> {
71 if property.writable().unwrap_or(false)
72 && property.enumerable().unwrap_or(false)
73 && property.configurable().unwrap_or(false)
74 {
75 property.value()
76 } else {
77 None
78 }
79 }
80
81 fn get(&self, key: u32) -> Option<PropertyDescriptor> {
83 let value = match self {
84 Self::DenseI32(vec) => vec.get(key as usize).copied()?.into(),
85 Self::DenseF64(vec) => vec.get(key as usize).copied()?.into(),
86 Self::DenseElement(vec) => vec.get(key as usize)?.clone(),
87 Self::SparseElement(map) => map.get(&key)?.clone(),
88 Self::SparseProperty(map) => return map.get(&key).cloned(),
89 };
90
91 Some(
92 PropertyDescriptorBuilder::new()
93 .writable(true)
94 .enumerable(true)
95 .configurable(true)
96 .value(value)
97 .build(),
98 )
99 }
100
101 fn convert_dense_to_sparse<T>(vec: &mut ThinVec<T>) -> FxHashMap<u32, PropertyDescriptor>
103 where
104 T: Into<JsValue>,
105 {
106 let data = std::mem::take(vec);
107
108 data.into_iter()
109 .enumerate()
110 .map(|(index, value)| {
111 (
112 index as u32,
113 PropertyDescriptorBuilder::new()
114 .writable(true)
115 .enumerable(true)
116 .configurable(true)
117 .value(value.into())
118 .build(),
119 )
120 })
121 .collect()
122 }
123
124 fn convert_dense_to_sparse_values<T>(vec: &mut ThinVec<T>) -> FxHashMap<u32, JsValue>
125 where
126 T: Into<JsValue>,
127 {
128 let data = std::mem::take(vec);
129
130 data.into_iter()
131 .enumerate()
132 .map(|(index, value)| (index as u32, value.into()))
133 .collect()
134 }
135
136 fn convert_to_sparse_and_insert(&mut self, key: u32, property: PropertyDescriptor) -> bool {
137 let mut descriptors = match self {
138 Self::DenseI32(vec) => Self::convert_dense_to_sparse(vec),
139 Self::DenseF64(vec) => Self::convert_dense_to_sparse(vec),
140 Self::DenseElement(vec) => Self::convert_dense_to_sparse(vec),
141 Self::SparseElement(map) => map
142 .iter()
143 .map(|(&index, value)| {
144 (
145 index,
146 PropertyDescriptorBuilder::new()
147 .writable(true)
148 .enumerable(true)
149 .configurable(true)
150 .value(value.clone())
151 .build(),
152 )
153 })
154 .collect(),
155 Self::SparseProperty(map) => {
156 return map.insert(key, property).is_some();
157 }
158 };
159
160 let replaced = descriptors.insert(key, property).is_some();
161 *self = Self::SparseProperty(Box::new(descriptors));
162 replaced
163 }
164
165 fn insert(&mut self, key: u32, property: PropertyDescriptor) -> bool {
167 let Some(value) = Self::property_simple_value(&property) else {
168 return self.convert_to_sparse_and_insert(key, property);
169 };
170
171 match self {
172 Self::DenseI32(vec) if key <= vec.len() as u32 => {
174 let len = vec.len() as u32;
175
176 if let Some(val) = value.as_i32() {
177 if key == len {
181 vec.push(val);
182 return false;
183 }
184
185 vec[key as usize] = val;
187 return true;
188 }
189
190 if let Some(num) = value.as_number() {
191 let mut vec = vec.iter().copied().map(f64::from).collect::<ThinVec<_>>();
192
193 if key == len {
197 vec.push(num);
198 *self = Self::DenseF64(vec);
199 return false;
200 }
201
202 vec[key as usize] = num;
204 *self = Self::DenseF64(vec);
205 return true;
206 }
207
208 let mut vec = vec
209 .iter()
210 .copied()
211 .map(JsValue::from)
212 .collect::<ThinVec<JsValue>>();
213
214 if key == len {
218 vec.push(value.clone());
219 *self = Self::DenseElement(vec);
220 return false;
221 }
222
223 vec[key as usize] = value.clone();
225 *self = Self::DenseElement(vec);
226 true
227 }
228 Self::DenseF64(vec) if key <= vec.len() as u32 => {
229 let len = vec.len() as u32;
230
231 if let Some(num) = value.as_number() {
232 if key == len {
236 vec.push(num);
237 return false;
238 }
239
240 vec[key as usize] = num;
242 return true;
243 }
244
245 let mut vec = vec
246 .iter()
247 .copied()
248 .map(JsValue::from)
249 .collect::<ThinVec<JsValue>>();
250
251 if key == len {
255 vec.push(value.clone());
256 *self = Self::DenseElement(vec);
257 return false;
258 }
259
260 vec[key as usize] = value.clone();
262 *self = Self::DenseElement(vec);
263 true
264 }
265 Self::DenseElement(vec) if key <= vec.len() as u32 => {
266 let len = vec.len() as u32;
267
268 if key == len {
272 vec.push(value.clone());
273 return false;
274 }
275
276 vec[key as usize] = value.clone();
278 true
279 }
280 Self::DenseI32(vec) => {
282 let mut values = Self::convert_dense_to_sparse_values(vec);
283 let replaced = values.insert(key, value.clone()).is_some();
284 *self = Self::SparseElement(Box::new(values));
285 replaced
286 }
287 Self::DenseF64(vec) => {
288 let mut values = Self::convert_dense_to_sparse_values(vec);
289 let replaced = values.insert(key, value.clone()).is_some();
290 *self = Self::SparseElement(Box::new(values));
291 replaced
292 }
293 Self::DenseElement(vec) => {
294 let mut values = Self::convert_dense_to_sparse_values(vec);
295 let replaced = values.insert(key, value.clone()).is_some();
296 *self = Self::SparseElement(Box::new(values));
297 replaced
298 }
299 Self::SparseElement(map) => map.insert(key, value.clone()).is_some(),
300 Self::SparseProperty(map) => {
301 let descriptor = PropertyDescriptorBuilder::new()
302 .value(value.clone())
303 .writable(true)
304 .enumerable(true)
305 .configurable(true)
306 .build();
307 map.insert(key, descriptor).is_some()
308 }
309 }
310 }
311
312 fn convert_to_sparse_and_remove(&mut self, key: u32) -> bool {
313 let mut descriptors = match self {
314 IndexedProperties::DenseI32(vec) => Self::convert_dense_to_sparse_values(vec),
315 IndexedProperties::DenseF64(vec) => Self::convert_dense_to_sparse_values(vec),
316 IndexedProperties::DenseElement(vec) => Self::convert_dense_to_sparse_values(vec),
317 IndexedProperties::SparseProperty(map) => return map.remove(&key).is_some(),
318 IndexedProperties::SparseElement(map) => {
319 return map.remove(&key).is_some();
320 }
321 };
322
323 let removed = descriptors.remove(&key).is_some();
324 *self = Self::SparseElement(Box::new(descriptors));
325 removed
326 }
327
328 fn remove(&mut self, key: u32) -> bool {
330 match self {
331 Self::DenseI32(vec) if (key + 1) == vec.len() as u32 => {
335 vec.pop();
336 true
337 }
338 Self::DenseI32(vec) if key >= vec.len() as u32 => false,
340 Self::DenseF64(vec) if (key + 1) == vec.len() as u32 => {
341 vec.pop();
342 true
343 }
344 Self::DenseF64(vec) if key >= vec.len() as u32 => false,
345 Self::DenseElement(vec) if (key + 1) == vec.len() as u32 => {
346 vec.pop();
347 true
348 }
349 Self::DenseElement(vec) if key >= vec.len() as u32 => false,
350 Self::SparseElement(map) => map.remove(&key).is_some(),
352 Self::SparseProperty(map) => map.remove(&key).is_some(),
353 _ => self.convert_to_sparse_and_remove(key),
354 }
355 }
356
357 fn contains_key(&self, key: u32) -> bool {
359 match self {
360 Self::DenseI32(vec) => (0..vec.len() as u32).contains(&key),
361 Self::DenseF64(vec) => (0..vec.len() as u32).contains(&key),
362 Self::DenseElement(vec) => (0..vec.len() as u32).contains(&key),
363 Self::SparseElement(map) => map.contains_key(&key),
364 Self::SparseProperty(map) => map.contains_key(&key),
365 }
366 }
367
368 pub(crate) fn push_dense(&mut self, value: &JsValue) -> bool {
375 match self {
376 Self::DenseI32(vec) => {
377 if let Some(i) = value.as_i32() {
378 vec.push(i);
379 } else if let Some(n) = value.as_number() {
380 let mut new_vec: ThinVec<f64> = vec.iter().copied().map(f64::from).collect();
381 new_vec.push(n);
382 *self = Self::DenseF64(new_vec);
383 } else {
384 let mut new_vec: ThinVec<JsValue> =
385 vec.iter().copied().map(JsValue::from).collect();
386 new_vec.push(value.clone());
387 *self = Self::DenseElement(new_vec);
388 }
389 true
390 }
391 Self::DenseF64(vec) => {
392 if let Some(n) = value.as_number() {
393 vec.push(n);
394 } else {
395 let mut new_vec: ThinVec<JsValue> =
396 vec.iter().copied().map(JsValue::from).collect();
397 new_vec.push(value.clone());
398 *self = Self::DenseElement(new_vec);
399 }
400 true
401 }
402 Self::DenseElement(vec) => {
403 vec.push(value.clone());
404 true
405 }
406 Self::SparseElement(_) | Self::SparseProperty(_) => false,
407 }
408 }
409
410 pub(crate) fn dense_len(&self) -> Option<usize> {
412 match self {
413 Self::DenseI32(vec) => Some(vec.len()),
414 Self::DenseF64(vec) => Some(vec.len()),
415 Self::DenseElement(vec) => Some(vec.len()),
416 Self::SparseElement(_) | Self::SparseProperty(_) => None,
417 }
418 }
419
420 pub(crate) fn transform_to_sparse(&mut self) {
422 match &*self {
423 Self::DenseI32(v) => {
424 *self = Self::SparseElement(Box::new(
425 v.into_iter()
426 .copied()
427 .enumerate()
428 .map(|(i, v)| (i as u32, JsValue::from(v)))
429 .collect(),
430 ));
431 }
432 Self::DenseF64(v) => {
433 *self = Self::SparseElement(Box::new(
434 v.into_iter()
435 .copied()
436 .enumerate()
437 .map(|(i, v)| (i as u32, JsValue::from(v)))
438 .collect(),
439 ));
440 }
441 Self::DenseElement(v) => {
442 *self = Self::SparseElement(Box::new(
443 v.into_iter()
444 .enumerate()
445 .map(|(i, v)| (i as u32, v.clone()))
446 .collect(),
447 ));
448 }
449 _ => {}
450 }
451 }
452
453 fn iter(&self) -> IndexProperties<'_> {
454 match self {
455 Self::DenseI32(vec) => IndexProperties::DenseI32(vec.iter().enumerate()),
456 Self::DenseF64(vec) => IndexProperties::DenseF64(vec.iter().enumerate()),
457 Self::DenseElement(vec) => IndexProperties::DenseElement(vec.iter().enumerate()),
458 Self::SparseElement(map) => IndexProperties::SparseElement(map.iter()),
459 Self::SparseProperty(map) => IndexProperties::SparseProperty(map.iter()),
460 }
461 }
462
463 fn keys(&self) -> IndexPropertyKeys<'_> {
464 match self {
465 Self::DenseI32(vec) => IndexPropertyKeys::Dense(0..vec.len() as u32),
466 Self::DenseF64(vec) => IndexPropertyKeys::Dense(0..vec.len() as u32),
467 Self::DenseElement(vec) => IndexPropertyKeys::Dense(0..vec.len() as u32),
468 Self::SparseElement(map) => IndexPropertyKeys::SparseElement(map.keys()),
469 Self::SparseProperty(map) => IndexPropertyKeys::SparseProperty(map.keys()),
470 }
471 }
472
473 fn values(&self) -> IndexPropertyValues<'_> {
474 match self {
475 Self::DenseI32(vec) => IndexPropertyValues::DenseI32(vec.iter()),
476 Self::DenseF64(vec) => IndexPropertyValues::DenseF64(vec.iter()),
477 Self::DenseElement(vec) => IndexPropertyValues::DenseElement(vec.iter()),
478 Self::SparseElement(map) => IndexPropertyValues::SparseElement(map.values()),
479 Self::SparseProperty(map) => IndexPropertyValues::SparseProperty(map.values()),
480 }
481 }
482}
483
484impl<'a> IntoIterator for &'a IndexedProperties {
485 type IntoIter = IndexProperties<'a>;
486 type Item = (u32, PropertyDescriptor);
487 fn into_iter(self) -> Self::IntoIter {
488 self.iter()
489 }
490}
491
492#[derive(Default, Debug, Trace, Finalize)]
496pub struct PropertyMap {
497 pub(crate) indexed_properties: IndexedProperties,
499
500 pub(crate) shape: Shape,
501 pub(crate) storage: ObjectStorage,
502}
503
504impl PropertyMap {
505 #[must_use]
507 #[inline]
508 pub fn new(shape: Shape, indexed_properties: IndexedProperties) -> Self {
509 Self {
510 indexed_properties,
511 shape,
512 storage: Vec::default(),
513 }
514 }
515
516 #[must_use]
518 #[inline]
519 pub fn from_prototype_unique_shape(prototype: JsPrototype) -> Self {
520 Self {
521 indexed_properties: IndexedProperties::default(),
522 shape: UniqueShape::new(prototype, PropertyTableInner::default()).into(),
523 storage: Vec::default(),
524 }
525 }
526
527 #[must_use]
529 #[inline]
530 pub fn from_prototype_with_shared_shape(
531 root_shape: &RootShape,
532 prototype: JsPrototype,
533 ) -> Self {
534 let shape = root_shape.shape().change_prototype_transition(prototype);
535 Self {
536 indexed_properties: IndexedProperties::default(),
537 shape: shape.into(),
538 storage: Vec::default(),
539 }
540 }
541
542 #[must_use]
544 pub fn get(&self, key: &PropertyKey) -> Option<PropertyDescriptor> {
545 if let PropertyKey::Index(index) = key {
546 return self.indexed_properties.get(index.get());
547 }
548 if let Some(slot) = self.shape.lookup(key) {
549 return Some(self.get_storage(slot));
550 }
551
552 None
553 }
554
555 #[must_use]
557 pub(crate) fn get_with_slot(
558 &self,
559 key: &PropertyKey,
560 out_slot: &mut Slot,
561 ) -> Option<PropertyDescriptor> {
562 if let PropertyKey::Index(index) = key {
563 return self.indexed_properties.get(index.get());
564 }
565 if let Some(slot) = self.shape.lookup(key) {
566 out_slot.index = slot.index;
567
568 out_slot.attributes = (out_slot.attributes & SlotAttributes::INLINE_CACHE_BITS)
570 | slot.attributes
571 | SlotAttributes::FOUND;
572 return Some(self.get_storage(slot));
573 }
574
575 None
576 }
577
578 #[must_use]
580 pub(crate) fn get_storage(&self, Slot { index, attributes }: Slot) -> PropertyDescriptor {
581 let index = index as usize;
582 let mut builder = PropertyDescriptor::builder()
583 .configurable(attributes.contains(SlotAttributes::CONFIGURABLE))
584 .enumerable(attributes.contains(SlotAttributes::ENUMERABLE));
585 if attributes.is_accessor_descriptor() {
586 if attributes.has_get() {
587 builder = builder.get(self.storage[index].clone());
588 }
589 if attributes.has_set() {
590 builder = builder.set(self.storage[index + 1].clone());
591 }
592 } else {
593 builder = builder.writable(attributes.contains(SlotAttributes::WRITABLE));
594 builder = builder.value(self.storage[index].clone());
595 }
596 builder.build()
597 }
598
599 pub fn insert(&mut self, key: &PropertyKey, property: PropertyDescriptor) -> bool {
601 let mut dummy_slot = Slot::new();
602 self.insert_with_slot(key, property, &mut dummy_slot)
603 }
604
605 pub(crate) fn insert_with_slot(
607 &mut self,
608 key: &PropertyKey,
609 property: PropertyDescriptor,
610 out_slot: &mut Slot,
611 ) -> bool {
612 if let PropertyKey::Index(index) = key {
613 return self.indexed_properties.insert(index.get(), property);
614 }
615
616 let attributes = property.to_slot_attributes();
617
618 if let Some(slot) = self.shape.lookup(key) {
619 let index = slot.index as usize;
620
621 if slot.attributes != attributes {
622 let key = TransitionKey {
623 property_key: key.clone(),
624 attributes,
625 };
626 let transition = self.shape.change_attributes_transition(key);
627 self.shape = transition.shape;
628 match transition.action {
629 ChangeTransitionAction::Nothing => {}
630 ChangeTransitionAction::Remove => {
631 self.storage.remove(slot.index as usize + 1);
632 }
633 ChangeTransitionAction::Insert => {
634 self.storage.insert(index, JsValue::undefined());
636 }
637 }
638 }
639
640 if attributes.is_accessor_descriptor() {
641 if attributes.has_get() {
642 self.storage[index] = property
643 .get()
644 .cloned()
645 .map(JsValue::new)
646 .unwrap_or_default();
647 }
648 if attributes.has_set() {
649 self.storage[index + 1] = property
650 .set()
651 .cloned()
652 .map(JsValue::new)
653 .unwrap_or_default();
654 }
655 } else {
656 self.storage[index] = property.expect_value().clone();
657 }
658 out_slot.index = slot.index;
659 out_slot.attributes =
660 (out_slot.attributes & SlotAttributes::INLINE_CACHE_BITS) | attributes;
661 return true;
662 }
663
664 let transition_key = TransitionKey {
665 property_key: key.clone(),
666 attributes,
667 };
668 self.shape = self.shape.insert_property_transition(transition_key);
669
670 debug_assert_eq!(
672 self.shape.lookup(key),
673 Some(Slot {
674 index: self.storage.len() as u32,
675 attributes
676 })
677 );
678
679 out_slot.index = self.storage.len() as u32;
680 out_slot.attributes =
681 (out_slot.attributes & SlotAttributes::INLINE_CACHE_BITS) | attributes;
682
683 if attributes.is_accessor_descriptor() {
684 self.storage.push(
685 property
686 .get()
687 .cloned()
688 .map(JsValue::new)
689 .unwrap_or_default(),
690 );
691 self.storage.push(
692 property
693 .set()
694 .cloned()
695 .map(JsValue::new)
696 .unwrap_or_default(),
697 );
698 } else {
699 self.storage
700 .push(property.value().cloned().unwrap_or_default());
701 }
702
703 false
704 }
705
706 pub fn remove(&mut self, key: &PropertyKey) -> bool {
708 if let PropertyKey::Index(index) = key {
709 return self.indexed_properties.remove(index.get());
710 }
711 if let Some(slot) = self.shape.lookup(key) {
712 if slot.attributes.is_accessor_descriptor() {
714 self.storage.remove(slot.index as usize + 1);
715 }
716 self.storage.remove(slot.index as usize);
717
718 self.shape = self.shape.remove_property_transition(key);
719 return true;
720 }
721
722 false
723 }
724
725 pub(crate) fn override_indexed_properties(&mut self, properties: ThinVec<JsValue>) {
727 self.indexed_properties = IndexedProperties::DenseElement(properties);
728 }
729
730 pub(crate) fn get_dense_property(&self, index: u32) -> Option<JsValue> {
731 let index = index as usize;
732 match &self.indexed_properties {
733 IndexedProperties::DenseI32(properties) => {
734 properties.get(index).copied().map(JsValue::from)
735 }
736 IndexedProperties::DenseF64(properties) => {
737 properties.get(index).copied().map(JsValue::from)
738 }
739 IndexedProperties::DenseElement(properties) => properties.get(index).cloned(),
740 IndexedProperties::SparseProperty(_) | IndexedProperties::SparseElement(_) => None,
741 }
742 }
743
744 pub(crate) fn set_dense_property(&mut self, index: u32, value: &JsValue) -> bool {
745 let index = index as usize;
746
747 match &mut self.indexed_properties {
748 IndexedProperties::DenseI32(properties) => {
749 let Some(element) = properties.get_mut(index) else {
750 return false;
751 };
752
753 let is_rational_integer = |n: f64| n.to_bits() == f64::from(n as i32).to_bits();
756
757 let value = match value.variant() {
758 JsVariant::Integer32(n) => n,
759 JsVariant::Float64(n) if is_rational_integer(n) => n as i32,
760 JsVariant::Float64(value) => {
761 let mut properties = properties
762 .iter()
763 .copied()
764 .map(f64::from)
765 .collect::<ThinVec<_>>();
766 properties[index] = value;
767 self.indexed_properties = IndexedProperties::DenseF64(properties);
768
769 return true;
770 }
771 _ => {
772 let mut properties = properties
773 .iter()
774 .copied()
775 .map(JsValue::from)
776 .collect::<ThinVec<_>>();
777 properties[index] = value.clone();
778 self.indexed_properties = IndexedProperties::DenseElement(properties);
779
780 return true;
781 }
782 };
783
784 *element = value;
785 true
786 }
787 IndexedProperties::DenseF64(properties) => {
788 let Some(element) = properties.get_mut(index) else {
789 return false;
790 };
791
792 let Some(value) = value.as_number() else {
793 let mut properties = properties
794 .iter()
795 .copied()
796 .map(JsValue::from)
797 .collect::<ThinVec<_>>();
798 properties[index] = value.clone();
799 self.indexed_properties = IndexedProperties::DenseElement(properties);
800 return true;
801 };
802
803 *element = value;
804 true
805 }
806 IndexedProperties::DenseElement(properties) => {
807 let Some(element) = properties.get_mut(index) else {
808 return false;
809 };
810 *element = value.clone();
811 true
812 }
813 IndexedProperties::SparseProperty(_) | IndexedProperties::SparseElement(_) => false,
814 }
815 }
816
817 pub(crate) fn to_dense_indexed_properties(&self) -> Option<ThinVec<JsValue>> {
819 match &self.indexed_properties {
820 IndexedProperties::DenseI32(properties) => {
821 Some(properties.iter().copied().map(JsValue::from).collect())
822 }
823 IndexedProperties::DenseF64(properties) => {
824 Some(properties.iter().copied().map(JsValue::from).collect())
825 }
826 IndexedProperties::DenseElement(properties) => Some(properties.clone()),
827 IndexedProperties::SparseProperty(_) | IndexedProperties::SparseElement(_) => None,
828 }
829 }
830
831 pub(crate) fn dense_indexed_properties_mut(&mut self) -> Option<&mut ThinVec<JsValue>> {
833 if let IndexedProperties::DenseElement(properties) = &mut self.indexed_properties {
834 Some(properties)
835 } else {
836 None
837 }
838 }
839
840 #[inline]
844 #[must_use]
845 pub fn index_properties(&self) -> IndexProperties<'_> {
846 self.indexed_properties.iter()
847 }
848
849 #[inline]
853 #[must_use]
854 pub fn index_property_keys(&self) -> IndexPropertyKeys<'_> {
855 self.indexed_properties.keys()
856 }
857
858 #[inline]
862 #[must_use]
863 pub fn index_property_values(&self) -> IndexPropertyValues<'_> {
864 self.indexed_properties.values()
865 }
866
867 #[inline]
869 #[must_use]
870 pub fn contains_key(&self, key: &PropertyKey) -> bool {
871 if let PropertyKey::Index(index) = key {
872 return self.indexed_properties.contains_key(index.get());
873 }
874 if self.shape.lookup(key).is_some() {
875 return true;
876 }
877
878 false
879 }
880}
881
882#[derive(Debug, Clone)]
884pub enum IndexProperties<'a> {
885 DenseI32(std::iter::Enumerate<std::slice::Iter<'a, i32>>),
887
888 DenseF64(std::iter::Enumerate<std::slice::Iter<'a, f64>>),
890
891 DenseElement(std::iter::Enumerate<std::slice::Iter<'a, JsValue>>),
893
894 SparseElement(hash_map::Iter<'a, u32, JsValue>),
896
897 SparseProperty(hash_map::Iter<'a, u32, PropertyDescriptor>),
899}
900
901impl Iterator for IndexProperties<'_> {
902 type Item = (u32, PropertyDescriptor);
903
904 fn next(&mut self) -> Option<Self::Item> {
905 let (index, value) = match self {
906 Self::DenseI32(vec) => vec
907 .next()
908 .map(|(index, value)| (index, JsValue::from(*value)))?,
909 Self::DenseF64(vec) => vec
910 .next()
911 .map(|(index, value)| (index, JsValue::from(*value)))?,
912 Self::DenseElement(vec) => vec.next().map(|(index, value)| (index, value.clone()))?,
913 Self::SparseProperty(map) => {
914 return map.next().map(|(index, value)| (*index, value.clone()));
915 }
916 Self::SparseElement(map) => map
917 .next()
918 .map(|(index, value)| (*index as usize, value.clone()))?,
919 };
920
921 Some((
922 index as u32,
923 PropertyDescriptorBuilder::new()
924 .writable(true)
925 .configurable(true)
926 .enumerable(true)
927 .value(value.clone())
928 .build(),
929 ))
930 }
931
932 #[inline]
933 fn size_hint(&self) -> (usize, Option<usize>) {
934 match self {
935 Self::DenseI32(vec) => vec.size_hint(),
936 Self::DenseF64(vec) => vec.size_hint(),
937 Self::DenseElement(vec) => vec.size_hint(),
938 Self::SparseProperty(map) => map.size_hint(),
939 Self::SparseElement(map) => map.size_hint(),
940 }
941 }
942}
943
944impl ExactSizeIterator for IndexProperties<'_> {
945 #[inline]
946 fn len(&self) -> usize {
947 match self {
948 Self::DenseI32(vec) => vec.len(),
949 Self::DenseF64(vec) => vec.len(),
950 Self::DenseElement(vec) => vec.len(),
951 Self::SparseProperty(map) => map.len(),
952 Self::SparseElement(map) => map.len(),
953 }
954 }
955}
956
957impl FusedIterator for IndexProperties<'_> {}
958
959#[derive(Debug, Clone)]
961pub enum IndexPropertyKeys<'a> {
962 Dense(std::ops::Range<u32>),
964
965 SparseProperty(hash_map::Keys<'a, u32, PropertyDescriptor>),
967
968 SparseElement(hash_map::Keys<'a, u32, JsValue>),
970}
971
972impl Iterator for IndexPropertyKeys<'_> {
973 type Item = u32;
974
975 #[inline]
976 fn next(&mut self) -> Option<Self::Item> {
977 match self {
978 Self::Dense(vec) => vec.next(),
979 Self::SparseProperty(map) => map.next().copied(),
980 Self::SparseElement(map) => map.next().copied(),
981 }
982 }
983
984 #[inline]
985 fn size_hint(&self) -> (usize, Option<usize>) {
986 match self {
987 Self::Dense(vec) => vec.size_hint(),
988 Self::SparseProperty(map) => map.size_hint(),
989 Self::SparseElement(map) => map.size_hint(),
990 }
991 }
992}
993
994impl ExactSizeIterator for IndexPropertyKeys<'_> {
995 #[inline]
996 fn len(&self) -> usize {
997 match self {
998 Self::Dense(vec) => vec.len(),
999 Self::SparseProperty(map) => map.len(),
1000 Self::SparseElement(map) => map.len(),
1001 }
1002 }
1003}
1004
1005impl FusedIterator for IndexPropertyKeys<'_> {}
1006
1007#[derive(Debug, Clone)]
1009#[allow(variant_size_differences)]
1010pub enum IndexPropertyValues<'a> {
1011 DenseI32(std::slice::Iter<'a, i32>),
1013
1014 DenseF64(std::slice::Iter<'a, f64>),
1016
1017 DenseElement(std::slice::Iter<'a, JsValue>),
1019
1020 SparseProperty(hash_map::Values<'a, u32, PropertyDescriptor>),
1022
1023 SparseElement(hash_map::Values<'a, u32, JsValue>),
1025}
1026
1027impl Iterator for IndexPropertyValues<'_> {
1028 type Item = PropertyDescriptor;
1029
1030 fn next(&mut self) -> Option<Self::Item> {
1031 let value = match self {
1032 Self::DenseI32(vec) => vec.next().copied()?.into(),
1033 Self::DenseF64(vec) => vec.next().copied()?.into(),
1034 Self::DenseElement(vec) => vec.next().cloned()?,
1035 Self::SparseProperty(map) => return map.next().cloned(),
1036 Self::SparseElement(map) => map.next().cloned()?,
1037 };
1038
1039 Some(
1040 PropertyDescriptorBuilder::new()
1041 .writable(true)
1042 .configurable(true)
1043 .enumerable(true)
1044 .value(value)
1045 .build(),
1046 )
1047 }
1048
1049 #[inline]
1050 fn size_hint(&self) -> (usize, Option<usize>) {
1051 match self {
1052 Self::DenseI32(vec) => vec.size_hint(),
1053 Self::DenseF64(vec) => vec.size_hint(),
1054 Self::DenseElement(vec) => vec.size_hint(),
1055 Self::SparseProperty(map) => map.size_hint(),
1056 Self::SparseElement(map) => map.size_hint(),
1057 }
1058 }
1059}
1060
1061impl ExactSizeIterator for IndexPropertyValues<'_> {
1062 #[inline]
1063 fn len(&self) -> usize {
1064 match self {
1065 Self::DenseI32(vec) => vec.len(),
1066 Self::DenseF64(vec) => vec.len(),
1067 Self::DenseElement(vec) => vec.len(),
1068 Self::SparseProperty(map) => map.len(),
1069 Self::SparseElement(map) => map.len(),
1070 }
1071 }
1072}