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