1#[cfg(feature = "alloc")]
4use alloc::alloc::{Layout, alloc, dealloc, realloc};
5#[cfg(feature = "alloc")]
6use alloc::borrow::ToOwned;
7#[cfg(feature = "std")]
8use alloc::boxed::Box;
9#[cfg(feature = "alloc")]
10use alloc::collections::BTreeMap;
11use core::fmt::{self, Debug, Formatter};
12use core::hash::{Hash, Hasher};
13use core::iter::FromIterator;
14use core::ops::{Index, IndexMut};
15use core::{cmp, mem, ptr};
16
17#[cfg(feature = "std")]
18use indexmap::IndexMap;
19#[cfg(feature = "std")]
20use std::collections::HashMap;
21
22use crate::string::VString;
23use crate::value::{TypeTag, Value};
24
25#[cfg(feature = "std")]
28const LARGE_MODE_THRESHOLD: usize = 32;
29
30#[cfg(feature = "std")]
32const LARGE_MODE_CAP_SENTINEL: usize = usize::MAX;
33
34#[repr(C)]
36struct KeyValuePair {
37 key: VString,
38 value: Value,
39}
40
41#[repr(C, align(8))]
43struct ObjectHeader {
44 len: usize,
46 cap: usize,
48 }
50
51#[cfg(feature = "std")]
54#[repr(C, align(8))]
55struct LargeModeStorage {
56 _len_unused: usize,
58 cap_sentinel: usize,
60 map: IndexMap<VString, Value>,
62}
63
64#[repr(transparent)]
73#[derive(Clone)]
74pub struct VObject(pub(crate) Value);
75
76impl VObject {
77 fn layout(cap: usize) -> Layout {
78 Layout::new::<ObjectHeader>()
79 .extend(Layout::array::<KeyValuePair>(cap).unwrap())
80 .unwrap()
81 .0
82 .pad_to_align()
83 }
84
85 #[cfg(feature = "alloc")]
86 fn alloc(cap: usize) -> *mut ObjectHeader {
87 unsafe {
88 let layout = Self::layout(cap);
89 let ptr = alloc(layout).cast::<ObjectHeader>();
90 (*ptr).len = 0;
91 (*ptr).cap = cap;
92 ptr
93 }
94 }
95
96 #[cfg(feature = "alloc")]
97 fn realloc_ptr(ptr: *mut ObjectHeader, new_cap: usize) -> *mut ObjectHeader {
98 unsafe {
99 let old_cap = (*ptr).cap;
100 let old_layout = Self::layout(old_cap);
101 let new_layout = Self::layout(new_cap);
102 let new_ptr =
103 realloc(ptr.cast::<u8>(), old_layout, new_layout.size()).cast::<ObjectHeader>();
104 (*new_ptr).cap = new_cap;
105 new_ptr
106 }
107 }
108
109 #[cfg(feature = "alloc")]
110 fn dealloc_ptr(ptr: *mut ObjectHeader) {
111 unsafe {
112 let cap = (*ptr).cap;
113 let layout = Self::layout(cap);
114 dealloc(ptr.cast::<u8>(), layout);
115 }
116 }
117
118 #[cfg(feature = "std")]
120 #[inline]
121 fn is_large_mode(&self) -> bool {
122 unsafe {
125 let header = self.0.heap_ptr() as *const ObjectHeader;
126 (*header).cap == LARGE_MODE_CAP_SENTINEL
127 }
128 }
129
130 #[cfg(not(feature = "std"))]
132 #[inline]
133 fn is_large_mode(&self) -> bool {
134 false
136 }
137
138 #[cfg(feature = "std")]
140 #[inline]
141 fn as_indexmap(&self) -> &IndexMap<VString, Value> {
142 debug_assert!(self.is_large_mode());
143 unsafe {
144 let storage = self.0.heap_ptr() as *const LargeModeStorage;
145 &(*storage).map
146 }
147 }
148
149 #[cfg(feature = "std")]
151 #[inline]
152 fn as_indexmap_mut(&mut self) -> &mut IndexMap<VString, Value> {
153 debug_assert!(self.is_large_mode());
154 unsafe {
155 let storage = self.0.heap_ptr_mut() as *mut LargeModeStorage;
156 &mut (*storage).map
157 }
158 }
159
160 fn header(&self) -> &ObjectHeader {
161 debug_assert!(!self.is_large_mode());
162 unsafe { &*(self.0.heap_ptr() as *const ObjectHeader) }
163 }
164
165 fn header_mut(&mut self) -> &mut ObjectHeader {
166 debug_assert!(!self.is_large_mode());
167 unsafe { &mut *(self.0.heap_ptr_mut() as *mut ObjectHeader) }
168 }
169
170 fn items_ptr(&self) -> *const KeyValuePair {
171 debug_assert!(!self.is_large_mode());
172 unsafe { (self.0.heap_ptr() as *const ObjectHeader).add(1).cast() }
175 }
176
177 fn items_ptr_mut(&mut self) -> *mut KeyValuePair {
178 debug_assert!(!self.is_large_mode());
179 unsafe { (self.0.heap_ptr_mut() as *mut ObjectHeader).add(1).cast() }
181 }
182
183 fn items(&self) -> &[KeyValuePair] {
184 debug_assert!(!self.is_large_mode());
185 unsafe { core::slice::from_raw_parts(self.items_ptr(), self.small_len()) }
186 }
187
188 fn items_mut(&mut self) -> &mut [KeyValuePair] {
189 debug_assert!(!self.is_large_mode());
190 unsafe { core::slice::from_raw_parts_mut(self.items_ptr_mut(), self.small_len()) }
191 }
192
193 #[inline]
195 fn small_len(&self) -> usize {
196 debug_assert!(!self.is_large_mode());
197 self.header().len
198 }
199
200 #[cfg(feature = "std")]
202 fn convert_to_large_mode(&mut self) {
203 debug_assert!(!self.is_large_mode());
204
205 let mut map = IndexMap::with_capacity(self.small_len() + 1);
207 unsafe {
208 let len = self.small_len();
209 let items_ptr = self.items_ptr_mut();
210
211 for i in 0..len {
213 let kv = items_ptr.add(i).read();
214 map.insert(kv.key, kv.value);
215 }
216
217 Self::dealloc_ptr(self.0.heap_ptr_mut().cast());
219
220 let storage = LargeModeStorage {
222 _len_unused: 0,
223 cap_sentinel: LARGE_MODE_CAP_SENTINEL,
224 map,
225 };
226 let boxed = Box::new(storage);
227 let ptr = Box::into_raw(boxed);
228 self.0.set_ptr(ptr.cast());
229 }
230 }
231
232 #[cfg(feature = "alloc")]
234 #[inline]
235 #[must_use]
236 pub fn new() -> Self {
237 Self::with_capacity(0)
238 }
239
240 #[cfg(feature = "alloc")]
242 #[must_use]
243 pub fn with_capacity(cap: usize) -> Self {
244 #[cfg(feature = "std")]
246 if cap >= LARGE_MODE_THRESHOLD {
247 let storage = LargeModeStorage {
248 _len_unused: 0,
249 cap_sentinel: LARGE_MODE_CAP_SENTINEL,
250 map: IndexMap::with_capacity(cap),
251 };
252 let boxed = Box::new(storage);
253 let ptr = Box::into_raw(boxed);
254 return VObject(unsafe { Value::new_ptr(ptr.cast(), TypeTag::Object) });
255 }
256
257 unsafe {
258 let ptr = Self::alloc(cap);
259 VObject(Value::new_ptr(ptr.cast(), TypeTag::Object))
260 }
261 }
262
263 #[inline]
265 #[must_use]
266 pub fn len(&self) -> usize {
267 #[cfg(feature = "std")]
268 if self.is_large_mode() {
269 return self.as_indexmap().len();
270 }
271 self.header().len
272 }
273
274 #[inline]
276 #[must_use]
277 pub fn is_empty(&self) -> bool {
278 self.len() == 0
279 }
280
281 #[inline]
283 #[must_use]
284 pub fn capacity(&self) -> usize {
285 #[cfg(feature = "std")]
286 if self.is_large_mode() {
287 return self.as_indexmap().capacity();
288 }
289 self.header().cap
290 }
291
292 #[cfg(feature = "alloc")]
294 pub fn reserve(&mut self, additional: usize) {
295 #[cfg(feature = "std")]
296 if self.is_large_mode() {
297 self.as_indexmap_mut().reserve(additional);
298 return;
299 }
300
301 let current_cap = self.capacity();
302 let desired_cap = self
303 .len()
304 .checked_add(additional)
305 .expect("capacity overflow");
306
307 if current_cap >= desired_cap {
308 return;
309 }
310
311 let new_cap = cmp::max(current_cap * 2, desired_cap.max(4));
312
313 unsafe {
314 let new_ptr = Self::realloc_ptr(self.0.heap_ptr_mut().cast(), new_cap);
315 self.0.set_ptr(new_ptr.cast());
316 }
317 }
318
319 #[inline]
321 #[must_use]
322 pub fn get(&self, key: &str) -> Option<&Value> {
323 #[cfg(feature = "std")]
324 if self.is_large_mode() {
325 return self.as_indexmap().get(key);
326 }
327 self.items()
328 .iter()
329 .find(|kv| kv.key.as_str() == key)
330 .map(|kv| &kv.value)
331 }
332
333 #[inline]
335 pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
336 #[cfg(feature = "std")]
337 if self.is_large_mode() {
338 return self.as_indexmap_mut().get_mut(key);
339 }
340 self.items_mut()
341 .iter_mut()
342 .find(|kv| kv.key.as_str() == key)
343 .map(|kv| &mut kv.value)
344 }
345
346 #[inline]
348 #[must_use]
349 pub fn get_key_value(&self, key: &str) -> Option<(&VString, &Value)> {
350 #[cfg(feature = "std")]
351 if self.is_large_mode() {
352 return self.as_indexmap().get_key_value(key);
353 }
354 self.items()
355 .iter()
356 .find(|kv| kv.key.as_str() == key)
357 .map(|kv| (&kv.key, &kv.value))
358 }
359
360 #[inline]
362 #[must_use]
363 pub fn contains_key(&self, key: &str) -> bool {
364 #[cfg(feature = "std")]
365 if self.is_large_mode() {
366 return self.as_indexmap().contains_key(key);
367 }
368 self.items().iter().any(|kv| kv.key.as_str() == key)
369 }
370
371 #[cfg(feature = "alloc")]
373 pub fn insert(&mut self, key: impl Into<VString>, value: impl Into<Value>) -> Option<Value> {
374 let key = key.into();
375 let value = value.into();
376
377 #[cfg(feature = "std")]
378 if self.is_large_mode() {
379 return self.as_indexmap_mut().insert(key, value);
380 }
381
382 if let Some(idx) = self
384 .items()
385 .iter()
386 .position(|kv| kv.key.as_str() == key.as_str())
387 {
388 return Some(mem::replace(&mut self.items_mut()[idx].value, value));
390 }
391
392 #[cfg(feature = "std")]
394 if self.small_len() >= LARGE_MODE_THRESHOLD {
395 self.convert_to_large_mode();
396 return self.as_indexmap_mut().insert(key, value);
397 }
398
399 self.reserve(1);
401 let new_idx = self.header().len;
402
403 unsafe {
404 let ptr = self.items_ptr_mut().add(new_idx);
405 ptr.write(KeyValuePair { key, value });
406 self.header_mut().len = new_idx + 1;
407 }
408
409 None
410 }
411
412 pub fn remove(&mut self, key: &str) -> Option<Value> {
414 self.remove_entry(key).map(|(_, v)| v)
415 }
416
417 pub fn remove_entry(&mut self, key: &str) -> Option<(VString, Value)> {
419 #[cfg(feature = "std")]
420 if self.is_large_mode() {
421 return self.as_indexmap_mut().shift_remove_entry(key);
422 }
423
424 let idx = self.items().iter().position(|kv| kv.key.as_str() == key)?;
425 let len = self.small_len();
426
427 unsafe {
428 let ptr = self.items_ptr_mut().add(idx);
429 let kv = ptr.read();
430
431 if idx < len - 1 {
433 ptr::copy(ptr.add(1), ptr, len - idx - 1);
434 }
435
436 self.header_mut().len = len - 1;
437
438 Some((kv.key, kv.value))
439 }
440 }
441
442 pub fn clear(&mut self) {
444 #[cfg(feature = "std")]
445 if self.is_large_mode() {
446 self.as_indexmap_mut().clear();
447 return;
448 }
449
450 while !self.is_empty() {
451 unsafe {
452 let len = self.header().len;
453 self.header_mut().len = len - 1;
454 let ptr = self.items_ptr_mut().add(len - 1);
455 ptr::drop_in_place(ptr);
456 }
457 }
458 }
459
460 #[inline]
462 pub fn keys(&self) -> Keys<'_> {
463 #[cfg(feature = "std")]
464 if self.is_large_mode() {
465 return Keys(KeysInner::Large(self.as_indexmap().keys()));
466 }
467 Keys(KeysInner::Small(self.items().iter()))
468 }
469
470 #[inline]
472 pub fn values(&self) -> Values<'_> {
473 #[cfg(feature = "std")]
474 if self.is_large_mode() {
475 return Values(ValuesInner::Large(self.as_indexmap().values()));
476 }
477 Values(ValuesInner::Small(self.items().iter()))
478 }
479
480 #[inline]
482 pub fn values_mut(&mut self) -> ValuesMut<'_> {
483 #[cfg(feature = "std")]
484 if self.is_large_mode() {
485 return ValuesMut(ValuesMutInner::Large(self.as_indexmap_mut().values_mut()));
486 }
487 ValuesMut(ValuesMutInner::Small(self.items_mut().iter_mut()))
488 }
489
490 #[inline]
492 pub fn iter(&self) -> Iter<'_> {
493 #[cfg(feature = "std")]
494 if self.is_large_mode() {
495 return Iter(IterInner::Large(self.as_indexmap().iter()));
496 }
497 Iter(IterInner::Small(self.items().iter()))
498 }
499
500 #[inline]
502 pub fn iter_mut(&mut self) -> IterMut<'_> {
503 #[cfg(feature = "std")]
504 if self.is_large_mode() {
505 return IterMut(IterMutInner::Large(self.as_indexmap_mut().iter_mut()));
506 }
507 IterMut(IterMutInner::Small(self.items_mut().iter_mut()))
508 }
509
510 #[cfg(feature = "alloc")]
512 pub fn shrink_to_fit(&mut self) {
513 #[cfg(feature = "std")]
514 if self.is_large_mode() {
515 self.as_indexmap_mut().shrink_to_fit();
516 return;
517 }
518
519 let len = self.len();
520 let cap = self.capacity();
521
522 if len < cap {
523 unsafe {
524 let new_ptr = Self::realloc_ptr(self.0.heap_ptr_mut().cast(), len);
525 self.0.set_ptr(new_ptr.cast());
526 }
527 }
528 }
529
530 pub(crate) fn clone_impl(&self) -> Value {
531 #[cfg(feature = "std")]
532 if self.is_large_mode() {
533 let storage = LargeModeStorage {
534 _len_unused: 0,
535 cap_sentinel: LARGE_MODE_CAP_SENTINEL,
536 map: self.as_indexmap().clone(),
537 };
538 let boxed = Box::new(storage);
539 let ptr = Box::into_raw(boxed);
540 return unsafe { Value::new_ptr(ptr.cast(), TypeTag::Object) };
541 }
542
543 let mut new = VObject::with_capacity(self.len());
544 for kv in self.items() {
545 new.insert(kv.key.clone(), kv.value.clone());
546 }
547 new.0
548 }
549
550 pub(crate) fn drop_impl(&mut self) {
551 #[cfg(feature = "std")]
552 if self.is_large_mode() {
553 unsafe {
554 drop(Box::from_raw(self.0.heap_ptr_mut() as *mut LargeModeStorage));
555 }
556 return;
557 }
558
559 self.clear();
560 unsafe {
561 Self::dealloc_ptr(self.0.heap_ptr_mut().cast());
562 }
563 }
564}
565
566enum KeysInner<'a> {
569 Small(core::slice::Iter<'a, KeyValuePair>),
570 #[cfg(feature = "std")]
571 Large(indexmap::map::Keys<'a, VString, Value>),
572}
573
574pub struct Keys<'a>(KeysInner<'a>);
576
577impl<'a> Iterator for Keys<'a> {
578 type Item = &'a VString;
579
580 fn next(&mut self) -> Option<Self::Item> {
581 match &mut self.0 {
582 KeysInner::Small(iter) => iter.next().map(|kv| &kv.key),
583 #[cfg(feature = "std")]
584 KeysInner::Large(iter) => iter.next(),
585 }
586 }
587
588 fn size_hint(&self) -> (usize, Option<usize>) {
589 match &self.0 {
590 KeysInner::Small(iter) => iter.size_hint(),
591 #[cfg(feature = "std")]
592 KeysInner::Large(iter) => iter.size_hint(),
593 }
594 }
595}
596
597impl ExactSizeIterator for Keys<'_> {}
598
599enum ValuesInner<'a> {
600 Small(core::slice::Iter<'a, KeyValuePair>),
601 #[cfg(feature = "std")]
602 Large(indexmap::map::Values<'a, VString, Value>),
603}
604
605pub struct Values<'a>(ValuesInner<'a>);
607
608impl<'a> Iterator for Values<'a> {
609 type Item = &'a Value;
610
611 fn next(&mut self) -> Option<Self::Item> {
612 match &mut self.0 {
613 ValuesInner::Small(iter) => iter.next().map(|kv| &kv.value),
614 #[cfg(feature = "std")]
615 ValuesInner::Large(iter) => iter.next(),
616 }
617 }
618
619 fn size_hint(&self) -> (usize, Option<usize>) {
620 match &self.0 {
621 ValuesInner::Small(iter) => iter.size_hint(),
622 #[cfg(feature = "std")]
623 ValuesInner::Large(iter) => iter.size_hint(),
624 }
625 }
626}
627
628impl ExactSizeIterator for Values<'_> {}
629
630enum ValuesMutInner<'a> {
631 Small(core::slice::IterMut<'a, KeyValuePair>),
632 #[cfg(feature = "std")]
633 Large(indexmap::map::ValuesMut<'a, VString, Value>),
634}
635
636pub struct ValuesMut<'a>(ValuesMutInner<'a>);
638
639impl<'a> Iterator for ValuesMut<'a> {
640 type Item = &'a mut Value;
641
642 fn next(&mut self) -> Option<Self::Item> {
643 match &mut self.0 {
644 ValuesMutInner::Small(iter) => iter.next().map(|kv| &mut kv.value),
645 #[cfg(feature = "std")]
646 ValuesMutInner::Large(iter) => iter.next(),
647 }
648 }
649
650 fn size_hint(&self) -> (usize, Option<usize>) {
651 match &self.0 {
652 ValuesMutInner::Small(iter) => iter.size_hint(),
653 #[cfg(feature = "std")]
654 ValuesMutInner::Large(iter) => iter.size_hint(),
655 }
656 }
657}
658
659impl ExactSizeIterator for ValuesMut<'_> {}
660
661enum IterInner<'a> {
662 Small(core::slice::Iter<'a, KeyValuePair>),
663 #[cfg(feature = "std")]
664 Large(indexmap::map::Iter<'a, VString, Value>),
665}
666
667pub struct Iter<'a>(IterInner<'a>);
669
670impl<'a> Iterator for Iter<'a> {
671 type Item = (&'a VString, &'a Value);
672
673 fn next(&mut self) -> Option<Self::Item> {
674 match &mut self.0 {
675 IterInner::Small(iter) => iter.next().map(|kv| (&kv.key, &kv.value)),
676 #[cfg(feature = "std")]
677 IterInner::Large(iter) => iter.next(),
678 }
679 }
680
681 fn size_hint(&self) -> (usize, Option<usize>) {
682 match &self.0 {
683 IterInner::Small(iter) => iter.size_hint(),
684 #[cfg(feature = "std")]
685 IterInner::Large(iter) => iter.size_hint(),
686 }
687 }
688}
689
690impl ExactSizeIterator for Iter<'_> {}
691
692enum IterMutInner<'a> {
693 Small(core::slice::IterMut<'a, KeyValuePair>),
694 #[cfg(feature = "std")]
695 Large(indexmap::map::IterMut<'a, VString, Value>),
696}
697
698pub struct IterMut<'a>(IterMutInner<'a>);
700
701impl<'a> Iterator for IterMut<'a> {
702 type Item = (&'a VString, &'a mut Value);
703
704 fn next(&mut self) -> Option<Self::Item> {
705 match &mut self.0 {
706 IterMutInner::Small(iter) => iter.next().map(|kv| (&kv.key, &mut kv.value)),
707 #[cfg(feature = "std")]
708 IterMutInner::Large(iter) => iter.next(),
709 }
710 }
711
712 fn size_hint(&self) -> (usize, Option<usize>) {
713 match &self.0 {
714 IterMutInner::Small(iter) => iter.size_hint(),
715 #[cfg(feature = "std")]
716 IterMutInner::Large(iter) => iter.size_hint(),
717 }
718 }
719}
720
721impl ExactSizeIterator for IterMut<'_> {}
722
723pub struct ObjectIntoIter {
725 object: VObject,
726}
727
728impl Iterator for ObjectIntoIter {
729 type Item = (VString, Value);
730
731 fn next(&mut self) -> Option<Self::Item> {
732 if self.object.is_empty() {
733 None
734 } else {
735 let key = self.object.items()[0].key.as_str().to_owned();
737 self.object.remove_entry(&key)
738 }
739 }
740
741 fn size_hint(&self) -> (usize, Option<usize>) {
742 let len = self.object.len();
743 (len, Some(len))
744 }
745}
746
747impl ExactSizeIterator for ObjectIntoIter {}
748
749impl IntoIterator for VObject {
750 type Item = (VString, Value);
751 type IntoIter = ObjectIntoIter;
752
753 fn into_iter(self) -> Self::IntoIter {
754 ObjectIntoIter { object: self }
755 }
756}
757
758impl<'a> IntoIterator for &'a VObject {
759 type Item = (&'a VString, &'a Value);
760 type IntoIter = Iter<'a>;
761
762 fn into_iter(self) -> Self::IntoIter {
763 self.iter()
764 }
765}
766
767impl<'a> IntoIterator for &'a mut VObject {
768 type Item = (&'a VString, &'a mut Value);
769 type IntoIter = IterMut<'a>;
770
771 fn into_iter(self) -> Self::IntoIter {
772 self.iter_mut()
773 }
774}
775
776impl Index<&str> for VObject {
779 type Output = Value;
780
781 fn index(&self, key: &str) -> &Value {
782 self.get(key).expect("key not found")
783 }
784}
785
786impl IndexMut<&str> for VObject {
787 fn index_mut(&mut self, key: &str) -> &mut Value {
788 self.get_mut(key).expect("key not found")
789 }
790}
791
792impl PartialEq for VObject {
795 fn eq(&self, other: &Self) -> bool {
796 if self.len() != other.len() {
797 return false;
798 }
799 for (k, v) in self.iter() {
800 if other.get(k.as_str()) != Some(v) {
801 return false;
802 }
803 }
804 true
805 }
806}
807
808impl Eq for VObject {}
809
810impl Hash for VObject {
811 fn hash<H: Hasher>(&self, state: &mut H) {
812 self.len().hash(state);
815
816 let mut total: u64 = 0;
818 for (k, _v) in self.iter() {
819 let mut kh: u64 = 0;
821 for byte in k.as_bytes() {
822 kh = kh.wrapping_mul(31).wrapping_add(*byte as u64);
823 }
824 total ^= kh;
826 }
827 total.hash(state);
828 }
829}
830
831impl Debug for VObject {
832 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
833 f.debug_map().entries(self.iter()).finish()
834 }
835}
836
837impl Default for VObject {
838 fn default() -> Self {
839 Self::new()
840 }
841}
842
843#[cfg(feature = "alloc")]
846impl<K: Into<VString>, V: Into<Value>> FromIterator<(K, V)> for VObject {
847 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
848 let iter = iter.into_iter();
849 let (lower, _) = iter.size_hint();
850 let mut obj = VObject::with_capacity(lower);
851 for (k, v) in iter {
852 obj.insert(k, v);
853 }
854 obj
855 }
856}
857
858#[cfg(feature = "alloc")]
859impl<K: Into<VString>, V: Into<Value>> Extend<(K, V)> for VObject {
860 fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
861 let iter = iter.into_iter();
862 let (lower, _) = iter.size_hint();
863 self.reserve(lower);
864 for (k, v) in iter {
865 self.insert(k, v);
866 }
867 }
868}
869
870#[cfg(feature = "std")]
873impl<K: Into<VString>, V: Into<Value>> From<HashMap<K, V>> for VObject {
874 fn from(map: HashMap<K, V>) -> Self {
875 map.into_iter().collect()
876 }
877}
878
879#[cfg(feature = "alloc")]
880impl<K: Into<VString>, V: Into<Value>> From<BTreeMap<K, V>> for VObject {
881 fn from(map: BTreeMap<K, V>) -> Self {
882 map.into_iter().collect()
883 }
884}
885
886impl AsRef<Value> for VObject {
889 fn as_ref(&self) -> &Value {
890 &self.0
891 }
892}
893
894impl AsMut<Value> for VObject {
895 fn as_mut(&mut self) -> &mut Value {
896 &mut self.0
897 }
898}
899
900impl From<VObject> for Value {
901 fn from(obj: VObject) -> Self {
902 obj.0
903 }
904}
905
906impl VObject {
907 #[inline]
909 pub fn into_value(self) -> Value {
910 self.0
911 }
912}
913
914#[cfg(test)]
915mod tests {
916 use super::*;
917 use crate::ValueType;
918
919 #[test]
920 fn test_new() {
921 let obj = VObject::new();
922 assert!(obj.is_empty());
923 assert_eq!(obj.len(), 0);
924 }
925
926 #[test]
927 fn test_insert_get() {
928 let mut obj = VObject::new();
929 obj.insert("name", Value::from("Alice"));
930 obj.insert("age", Value::from(30));
931
932 assert_eq!(obj.len(), 2);
933 assert!(obj.contains_key("name"));
934 assert!(obj.contains_key("age"));
935 assert!(!obj.contains_key("email"));
936
937 assert_eq!(
938 obj.get("name").unwrap().as_string().unwrap().as_str(),
939 "Alice"
940 );
941 assert_eq!(
942 obj.get("age").unwrap().as_number().unwrap().to_i64(),
943 Some(30)
944 );
945 }
946
947 #[test]
948 fn test_insert_replace() {
949 let mut obj = VObject::new();
950 assert!(obj.insert("key", Value::from(1)).is_none());
951 assert!(obj.insert("key", Value::from(2)).is_some());
952 assert_eq!(obj.len(), 1);
953 assert_eq!(
954 obj.get("key").unwrap().as_number().unwrap().to_i64(),
955 Some(2)
956 );
957 }
958
959 #[test]
960 fn test_remove() {
961 let mut obj = VObject::new();
962 obj.insert("a", Value::from(1));
963 obj.insert("b", Value::from(2));
964 obj.insert("c", Value::from(3));
965
966 let removed = obj.remove("b");
967 assert!(removed.is_some());
968 assert_eq!(obj.len(), 2);
969 assert!(!obj.contains_key("b"));
970 }
971
972 #[test]
973 fn test_clone() {
974 let mut obj = VObject::new();
975 obj.insert("key", Value::from("value"));
976
977 let obj2 = obj.clone();
978 assert_eq!(obj, obj2);
979 }
980
981 #[test]
982 fn test_iter() {
983 let mut obj = VObject::new();
984 obj.insert("a", Value::from(1));
985 obj.insert("b", Value::from(2));
986
987 let keys: Vec<_> = obj.keys().map(|k| k.as_str()).collect();
988 assert_eq!(keys, vec!["a", "b"]);
989 }
990
991 #[test]
992 fn test_collect() {
993 let obj: VObject = vec![("a", Value::from(1)), ("b", Value::from(2))]
994 .into_iter()
995 .collect();
996 assert_eq!(obj.len(), 2);
997 }
998
999 #[test]
1000 fn test_index() {
1001 let mut obj = VObject::new();
1002 obj.insert("key", Value::from(42));
1003
1004 assert_eq!(obj["key"].as_number().unwrap().to_i64(), Some(42));
1005 }
1006
1007 #[test]
1008 fn inline_strings_in_objects_remain_inline() {
1009 let mut obj = VObject::new();
1010 for idx in 0..=crate::string::VString::INLINE_LEN_MAX.min(5) {
1011 let key = format!("k{idx}");
1012 let val = "v".repeat(idx);
1013 obj.insert(key.as_str(), Value::from(val.as_str()));
1014 }
1015
1016 for (key, value) in obj.iter() {
1017 assert!(
1018 key.0.is_inline_string(),
1019 "object key {:?} expected inline storage",
1020 key.as_str()
1021 );
1022 if value.value_type() == ValueType::String {
1023 assert!(
1024 value.is_inline_string(),
1025 "object value {value:?} expected inline storage"
1026 );
1027 }
1028 }
1029
1030 let mut cloned = obj.clone();
1031 for (key, value) in cloned.iter() {
1032 assert!(key.0.is_inline_string(), "cloned key lost inline storage");
1033 if value.value_type() == ValueType::String {
1034 assert!(value.is_inline_string(), "cloned value lost inline storage");
1035 }
1036 }
1037
1038 let (removed_key, removed_value) = cloned.remove_entry("k1").expect("entry exists");
1039 assert!(
1040 removed_key.0.is_inline_string(),
1041 "removed key should stay inline"
1042 );
1043 if removed_value.value_type() == ValueType::String {
1044 assert!(
1045 removed_value.is_inline_string(),
1046 "removed value should stay inline"
1047 );
1048 }
1049 }
1050}