scuffle_amf0/
object.rs

1//! This code is modified from <https://github.com/serde-rs/json/blob/v1.0.140/src/map.rs>
2//!
3//! A map of scuffle_bytes_util::StringCow to crate::Amf0Value.
4//!
5//! By default the map is backed by a [`BTreeMap`]. Enable the `preserve_order`
6//! feature of scuffle_amf0 to use [`IndexMap`] instead.
7//!
8//! [`BTreeMap`]: std::collections::BTreeMap
9//! [`IndexMap`]: indexmap::IndexMap
10
11#[cfg(not(feature = "preserve_order"))]
12use alloc::collections::{BTreeMap, btree_map};
13use core::borrow::Borrow;
14use core::fmt::{self, Debug};
15use core::hash::Hash;
16use core::iter::FusedIterator;
17use core::ops;
18use std::marker::PhantomData;
19
20#[cfg(feature = "preserve_order")]
21use indexmap::IndexMap;
22use scuffle_bytes_util::StringCow;
23use serde::de;
24
25use crate::{Amf0Error, Amf0Value};
26
27/// Represents a JSON key/value type.
28#[derive(Clone, PartialEq)]
29pub struct Amf0Object<'a> {
30    map: MapImpl<StringCow<'a>, Amf0Value<'a>>,
31}
32
33#[cfg(not(feature = "preserve_order"))]
34type MapImpl<K, V> = BTreeMap<K, V>;
35#[cfg(feature = "preserve_order")]
36type MapImpl<K, V> = IndexMap<K, V>;
37
38impl<'a> Default for Amf0Object<'a> {
39    fn default() -> Self {
40        Self::new()
41    }
42}
43
44impl<'a> Amf0Object<'a> {
45    /// Makes a new empty Map.
46    #[inline]
47    pub fn new() -> Self {
48        Amf0Object { map: MapImpl::new() }
49    }
50
51    /// Makes a new empty Map with the given initial capacity.
52    #[inline]
53    pub fn with_capacity(capacity: usize) -> Self {
54        Amf0Object {
55            #[cfg(not(feature = "preserve_order"))]
56            map: {
57                // does not support with_capacity
58                let _ = capacity;
59                BTreeMap::new()
60            },
61            #[cfg(feature = "preserve_order")]
62            map: IndexMap::with_capacity(capacity),
63        }
64    }
65
66    /// Clears the map, removing all values.
67    #[inline]
68    pub fn clear(&mut self) {
69        self.map.clear();
70    }
71
72    /// Returns a reference to the value corresponding to the key.
73    ///
74    /// The key may be any borrowed form of the map's key type, but the ordering
75    /// on the borrowed form *must* match the ordering on the key type.
76    #[inline]
77    pub fn get<Q>(&self, key: &Q) -> Option<&Amf0Value<'a>>
78    where
79        StringCow<'a>: Borrow<Q>,
80        Q: ?Sized + Ord + Eq + Hash,
81    {
82        self.map.get(key)
83    }
84
85    /// Returns true if the map contains a value for the specified key.
86    ///
87    /// The key may be any borrowed form of the map's key type, but the ordering
88    /// on the borrowed form *must* match the ordering on the key type.
89    #[inline]
90    pub fn contains_key<Q>(&self, key: &Q) -> bool
91    where
92        StringCow<'a>: Borrow<Q>,
93        Q: ?Sized + Ord + Eq + Hash,
94    {
95        self.map.contains_key(key)
96    }
97
98    /// Returns a mutable reference to the value corresponding to the key.
99    ///
100    /// The key may be any borrowed form of the map's key type, but the ordering
101    /// on the borrowed form *must* match the ordering on the key type.
102    #[inline]
103    pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut Amf0Value<'a>>
104    where
105        StringCow<'a>: Borrow<Q>,
106        Q: ?Sized + Ord + Eq + Hash,
107    {
108        self.map.get_mut(key)
109    }
110
111    /// Returns the key-value pair matching the given key.
112    ///
113    /// The key may be any borrowed form of the map's key type, but the ordering
114    /// on the borrowed form *must* match the ordering on the key type.
115    #[inline]
116    pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&StringCow<'a>, &Amf0Value<'a>)>
117    where
118        StringCow<'a>: Borrow<Q>,
119        Q: ?Sized + Ord + Eq + Hash,
120    {
121        self.map.get_key_value(key)
122    }
123
124    /// Inserts a key-value pair into the map.
125    ///
126    /// If the map did not have this key present, `None` is returned.
127    ///
128    /// If the map did have this key present, the value is updated, and the old
129    /// value is returned.
130    #[inline]
131    pub fn insert(&mut self, k: StringCow<'a>, v: Amf0Value<'a>) -> Option<Amf0Value<'a>> {
132        self.map.insert(k, v)
133    }
134
135    /// Insert a key-value pair in the map at the given index.
136    ///
137    /// If the map did not have this key present, `None` is returned.
138    ///
139    /// If the map did have this key present, the key is moved to the new
140    /// position, the value is updated, and the old value is returned.
141    #[cfg(feature = "preserve_order")]
142    #[inline]
143    pub fn shift_insert(&mut self, index: usize, k: StringCow<'a>, v: Amf0Value<'a>) -> Option<Amf0Value<'a>> {
144        self.map.shift_insert(index, k, v)
145    }
146
147    /// Removes a key from the map, returning the value at the key if the key
148    /// was previously in the map.
149    ///
150    /// The key may be any borrowed form of the map's key type, but the ordering
151    /// on the borrowed form *must* match the ordering on the key type.
152    ///
153    /// If scuffle_amf0's "preserve_order" is enabled, `.remove(key)` is
154    /// equivalent to [`.swap_remove(key)`][Self::swap_remove], replacing this
155    /// entry's position with the last element. If you need to preserve the
156    /// relative order of the keys in the map, use
157    /// [`.shift_remove(key)`][Self::shift_remove] instead.
158    #[inline]
159    pub fn remove<Q>(&mut self, key: &Q) -> Option<Amf0Value<'a>>
160    where
161        StringCow<'a>: Borrow<Q>,
162        Q: ?Sized + Ord + Eq + Hash,
163    {
164        #[cfg(feature = "preserve_order")]
165        return self.swap_remove(key);
166        #[cfg(not(feature = "preserve_order"))]
167        return self.map.remove(key);
168    }
169
170    /// Removes a key from the map, returning the stored key and value if the
171    /// key was previously in the map.
172    ///
173    /// The key may be any borrowed form of the map's key type, but the ordering
174    /// on the borrowed form *must* match the ordering on the key type.
175    ///
176    /// If scuffle_amf0's "preserve_order" is enabled, `.remove_entry(key)` is
177    /// equivalent to [`.swap_remove_entry(key)`][Self::swap_remove_entry],
178    /// replacing this entry's position with the last element. If you need to
179    /// preserve the relative order of the keys in the map, use
180    /// [`.shift_remove_entry(key)`][Self::shift_remove_entry] instead.
181    #[inline]
182    pub fn remove_entry<Q>(&mut self, key: &Q) -> Option<(StringCow<'a>, Amf0Value<'a>)>
183    where
184        StringCow<'a>: Borrow<Q>,
185        Q: ?Sized + Ord + Eq + Hash,
186    {
187        #[cfg(feature = "preserve_order")]
188        return self.swap_remove_entry(key);
189        #[cfg(not(feature = "preserve_order"))]
190        return self.map.remove_entry(key);
191    }
192
193    /// Removes and returns the value corresponding to the key from the map.
194    ///
195    /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the
196    /// last element of the map and popping it off. This perturbs the position
197    /// of what used to be the last element!
198    ///
199    /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove
200    #[cfg(feature = "preserve_order")]
201    #[inline]
202    pub fn swap_remove<Q>(&mut self, key: &Q) -> Option<Amf0Value<'a>>
203    where
204        StringCow<'a>: Borrow<Q>,
205        Q: ?Sized + Ord + Eq + Hash,
206    {
207        self.map.swap_remove(key)
208    }
209
210    /// Remove and return the key-value pair.
211    ///
212    /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the
213    /// last element of the map and popping it off. This perturbs the position
214    /// of what used to be the last element!
215    ///
216    /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove
217    #[cfg(feature = "preserve_order")]
218    #[inline]
219    pub fn swap_remove_entry<Q>(&mut self, key: &Q) -> Option<(StringCow<'a>, Amf0Value<'a>)>
220    where
221        StringCow<'a>: Borrow<Q>,
222        Q: ?Sized + Ord + Eq + Hash,
223    {
224        self.map.swap_remove_entry(key)
225    }
226
227    /// Removes and returns the value corresponding to the key from the map.
228    ///
229    /// Like [`Vec::remove`], the entry is removed by shifting all of the
230    /// elements that follow it, preserving their relative order. This perturbs
231    /// the index of all of those elements!
232    ///
233    /// [`Vec::remove`]: std::vec::Vec::remove
234    #[cfg(feature = "preserve_order")]
235    #[inline]
236    pub fn shift_remove<Q>(&mut self, key: &Q) -> Option<Amf0Value<'a>>
237    where
238        StringCow<'a>: Borrow<Q>,
239        Q: ?Sized + Ord + Eq + Hash,
240    {
241        self.map.shift_remove(key)
242    }
243
244    /// Remove and return the key-value pair.
245    ///
246    /// Like [`Vec::remove`], the entry is removed by shifting all of the
247    /// elements that follow it, preserving their relative order. This perturbs
248    /// the index of all of those elements!
249    ///
250    /// [`Vec::remove`]: std::vec::Vec::remove
251    #[cfg(feature = "preserve_order")]
252    #[inline]
253    pub fn shift_remove_entry<Q>(&mut self, key: &Q) -> Option<(StringCow<'a>, Amf0Value<'a>)>
254    where
255        StringCow<'a>: Borrow<Q>,
256        Q: ?Sized + Ord + Eq + Hash,
257    {
258        self.map.shift_remove_entry(key)
259    }
260
261    /// Moves all elements from other into self, leaving other empty.
262    #[inline]
263    pub fn append(&mut self, other: &mut Self) {
264        #[cfg(feature = "preserve_order")]
265        self.map.extend(std::mem::take(&mut other.map));
266        #[cfg(not(feature = "preserve_order"))]
267        self.map.append(&mut other.map);
268    }
269
270    /// Gets the given key's corresponding entry in the map for in-place
271    /// manipulation.
272    pub fn entry(&mut self, key: impl Into<StringCow<'a>>) -> Entry<'_, 'a> {
273        #[cfg(not(feature = "preserve_order"))]
274        use alloc::collections::btree_map::Entry as EntryImpl;
275
276        #[cfg(feature = "preserve_order")]
277        use indexmap::map::Entry as EntryImpl;
278
279        match self.map.entry(key.into()) {
280            EntryImpl::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }),
281            EntryImpl::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied }),
282        }
283    }
284
285    /// Returns the number of elements in the map.
286    #[inline]
287    pub fn len(&self) -> usize {
288        self.map.len()
289    }
290
291    /// Returns true if the map contains no elements.
292    #[inline]
293    pub fn is_empty(&self) -> bool {
294        self.map.is_empty()
295    }
296
297    /// Gets an iterator over the entries of the map.
298    #[inline]
299    pub fn iter(&self) -> Iter<'_, 'a> {
300        Iter { iter: self.map.iter() }
301    }
302
303    /// Gets a mutable iterator over the entries of the map.
304    #[inline]
305    pub fn iter_mut(&mut self) -> IterMut<'_, 'a> {
306        IterMut {
307            iter: self.map.iter_mut(),
308        }
309    }
310
311    /// Gets an iterator over the keys of the map.
312    #[inline]
313    pub fn keys(&self) -> Keys<'_, 'a> {
314        Keys { iter: self.map.keys() }
315    }
316
317    /// Gets an iterator over the values of the map.
318    #[inline]
319    pub fn values(&self) -> Values<'_, 'a> {
320        Values { iter: self.map.values() }
321    }
322
323    /// Gets an iterator over mutable values of the map.
324    #[inline]
325    pub fn values_mut(&mut self) -> ValuesMut<'_, 'a> {
326        ValuesMut {
327            iter: self.map.values_mut(),
328        }
329    }
330
331    /// Gets an iterator over the values of the map.
332    #[inline]
333    pub fn into_values(self) -> IntoValues<'a> {
334        IntoValues {
335            iter: self.map.into_values(),
336        }
337    }
338
339    /// Retains only the elements specified by the predicate.
340    ///
341    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)`
342    /// returns `false`.
343    #[inline]
344    pub fn retain<F>(&mut self, f: F)
345    where
346        F: FnMut(&StringCow<'a>, &mut Amf0Value<'a>) -> bool,
347    {
348        self.map.retain(f);
349    }
350
351    /// Sorts this map's entries in-place using `str`'s usual ordering.
352    ///
353    /// If scuffle_amf0's "preserve_order" feature is not enabled, this method
354    /// does no work because all JSON maps are always kept in a sorted state.
355    ///
356    /// If scuffle_amf0's "preserve_order" feature is enabled, this method
357    /// destroys the original source order or insertion order of this map in
358    /// favor of an alphanumerical order that matches how a BTreeMap with the
359    /// same contents would be ordered. This takes **O(n log n + c)** time where
360    /// _n_ is the length of the map and _c_ is the capacity.
361    #[inline]
362    pub fn sort_keys(&mut self) {
363        #[cfg(feature = "preserve_order")]
364        self.map.sort_unstable_keys();
365    }
366}
367
368/// Access an element of this map. Panics if the given key is not present in the
369/// map.
370///
371/// ```
372/// use scuffle_amf0::{Amf0Object, Amf0Value};
373/// use std::collections::BTreeMap;
374/// use scuffle_bytes_util::StringCow;
375///
376/// let mut map = scuffle_amf0::Amf0Object::new();
377/// map.insert(StringCow::from_ref("type"), Amf0Value::String("example".into()));
378/// let obj = Amf0Object::from(map);
379///
380/// assert_eq!(obj["type"], Amf0Value::String("example".into()));
381/// ```
382impl<'a, Q> ops::Index<&Q> for Amf0Object<'a>
383where
384    StringCow<'a>: Borrow<Q>,
385    Q: ?Sized + Ord + Eq + Hash,
386{
387    type Output = Amf0Value<'a>;
388
389    fn index(&self, index: &Q) -> &Self::Output {
390        self.map.index(index)
391    }
392}
393
394/// Mutably access an element of this map. Panics if the given key is not
395/// present in the map.
396impl<'a, Q> ops::IndexMut<&Q> for Amf0Object<'a>
397where
398    StringCow<'a>: Borrow<Q>,
399    Q: ?Sized + Ord + Eq + Hash,
400{
401    fn index_mut(&mut self, index: &Q) -> &mut Self::Output {
402        self.map.get_mut(index).expect("no entry found for key")
403    }
404}
405
406impl Debug for Amf0Object<'_> {
407    #[inline]
408    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
409        self.map.fmt(formatter)
410    }
411}
412
413#[cfg(feature = "serde")]
414impl serde::ser::Serialize for Amf0Object<'_> {
415    #[inline]
416    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
417    where
418        S: serde::ser::Serializer,
419    {
420        use serde::ser::SerializeMap;
421        let mut map = serializer.serialize_map(Some(self.len()))?;
422        for (k, v) in self {
423            map.serialize_entry(k, v)?;
424        }
425        map.end()
426    }
427}
428
429#[cfg(feature = "serde")]
430impl<'de> de::Deserialize<'de> for Amf0Object<'de> {
431    #[inline]
432    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
433    where
434        D: de::Deserializer<'de>,
435    {
436        struct Visitor;
437
438        impl<'de> de::Visitor<'de> for Visitor {
439            type Value = Amf0Object<'de>;
440
441            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
442                formatter.write_str("a map")
443            }
444
445            #[inline]
446            fn visit_unit<E>(self) -> Result<Self::Value, E>
447            where
448                E: de::Error,
449            {
450                Ok(Amf0Object::new())
451            }
452
453            #[inline]
454            fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
455            where
456                V: de::MapAccess<'de>,
457            {
458                let mut values = Amf0Object::new();
459
460                while let Some((key, value)) = visitor.next_entry()? {
461                    values.insert(key, value);
462                }
463
464                Ok(values)
465            }
466        }
467
468        deserializer.deserialize_map(Visitor)
469    }
470}
471
472impl<'a> FromIterator<(StringCow<'a>, Amf0Value<'a>)> for Amf0Object<'a> {
473    fn from_iter<T>(iter: T) -> Self
474    where
475        T: IntoIterator<Item = (StringCow<'a>, Amf0Value<'a>)>,
476    {
477        Amf0Object {
478            map: FromIterator::from_iter(iter),
479        }
480    }
481}
482
483impl<'a> Extend<(StringCow<'a>, Amf0Value<'a>)> for Amf0Object<'a> {
484    fn extend<T>(&mut self, iter: T)
485    where
486        T: IntoIterator<Item = (StringCow<'a>, Amf0Value<'a>)>,
487    {
488        self.map.extend(iter);
489    }
490}
491
492macro_rules! delegate_iterator {
493    (($name:ident $($generics:tt)*) => $item:ty) => {
494        impl $($generics)* Iterator for $name $($generics)* {
495            type Item = $item;
496            #[inline]
497            fn next(&mut self) -> Option<Self::Item> {
498                self.iter.next()
499            }
500            #[inline]
501            fn size_hint(&self) -> (usize, Option<usize>) {
502                self.iter.size_hint()
503            }
504        }
505
506        impl $($generics)* DoubleEndedIterator for $name $($generics)* {
507            #[inline]
508            fn next_back(&mut self) -> Option<Self::Item> {
509                self.iter.next_back()
510            }
511        }
512
513        impl $($generics)* ExactSizeIterator for $name $($generics)* {
514            #[inline]
515            fn len(&self) -> usize {
516                self.iter.len()
517            }
518        }
519
520        impl $($generics)* FusedIterator for $name $($generics)* {}
521    }
522}
523
524#[cfg(feature = "serde")]
525impl<'de> de::IntoDeserializer<'de, Amf0Error> for Amf0Object<'de> {
526    type Deserializer = Self;
527
528    fn into_deserializer(self) -> Self::Deserializer {
529        self
530    }
531}
532
533#[cfg(feature = "serde")]
534impl<'de> de::IntoDeserializer<'de, Amf0Error> for &'de Amf0Object<'de> {
535    type Deserializer = Self;
536
537    fn into_deserializer(self) -> Self::Deserializer {
538        self
539    }
540}
541
542#[cfg(feature = "serde")]
543impl<'de> serde::de::Deserializer<'de> for Amf0Object<'de> {
544    type Error = Amf0Error;
545
546    serde::forward_to_deserialize_any! {
547        bool f64 f32 char str string unit
548        i8 i16 i32 i64 u8 u16 u32 u64
549        seq map newtype_struct tuple
550        struct enum ignored_any identifier
551        bytes byte_buf option unit_struct
552        tuple_struct
553    }
554
555    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
556    where
557        V: de::Visitor<'de>,
558    {
559        visitor.visit_map(Amf0MapAccess {
560            iter: self.into_iter(),
561            _phantom: PhantomData,
562            value: None,
563        })
564    }
565}
566
567#[cfg(feature = "serde")]
568impl<'de> serde::de::Deserializer<'de> for &'de Amf0Object<'de> {
569    type Error = Amf0Error;
570
571    serde::forward_to_deserialize_any! {
572        bool f64 f32 char str string unit
573        i8 i16 i32 i64 u8 u16 u32 u64
574        seq map newtype_struct tuple
575        struct enum ignored_any identifier
576        bytes byte_buf option unit_struct
577        tuple_struct
578    }
579
580    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
581    where
582        V: de::Visitor<'de>,
583    {
584        visitor.visit_map(Amf0MapAccess {
585            iter: self.into_iter(),
586            _phantom: PhantomData,
587            value: None,
588        })
589    }
590}
591
592#[cfg(feature = "serde")]
593struct Amf0MapAccess<I, K, V> {
594    iter: I,
595    value: Option<V>,
596    _phantom: PhantomData<K>,
597}
598
599#[cfg(feature = "serde")]
600impl<'de, I, K, V> serde::de::MapAccess<'de> for Amf0MapAccess<I, K, V>
601where
602    I: Iterator<Item = (K, V)>,
603    K: serde::de::IntoDeserializer<'de, Amf0Error>,
604    V: serde::de::IntoDeserializer<'de, Amf0Error>,
605{
606    type Error = Amf0Error;
607
608    fn next_key_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>, Self::Error>
609    where
610        S: serde::de::DeserializeSeed<'de>,
611    {
612        match self.iter.next() {
613            Some((key, value)) => {
614                self.value = Some(value);
615                seed.deserialize(key.into_deserializer()).map(Some)
616            }
617            None => Ok(None),
618        }
619    }
620
621    fn next_value_seed<S>(&mut self, seed: S) -> Result<S::Value, Self::Error>
622    where
623        S: serde::de::DeserializeSeed<'de>,
624    {
625        seed.deserialize(self.value.take().unwrap().into_deserializer())
626    }
627}
628
629//////////////////////////////////////////////////////////////////////////////
630
631/// A view into a single entry in a map, which may either be vacant or occupied.
632/// This enum is constructed from the [`entry`] method on [`Amf0Object`].
633///
634/// [`entry`]: Amf0Object::entry
635pub enum Entry<'a, 'b> {
636    /// A vacant Entry.
637    Vacant(VacantEntry<'a, 'b>),
638    /// An occupied Entry.
639    Occupied(OccupiedEntry<'a, 'b>),
640}
641
642/// A vacant Entry. It is part of the [`Entry`] enum.
643pub struct VacantEntry<'a, 'b> {
644    vacant: VacantEntryImpl<'a, 'b>,
645}
646
647/// An occupied Entry. It is part of the [`Entry`] enum.
648pub struct OccupiedEntry<'a, 'b> {
649    occupied: OccupiedEntryImpl<'a, 'b>,
650}
651
652#[cfg(not(feature = "preserve_order"))]
653type VacantEntryImpl<'a, 'b> = btree_map::VacantEntry<'a, StringCow<'b>, Amf0Value<'b>>;
654#[cfg(feature = "preserve_order")]
655type VacantEntryImpl<'a, 'b> = indexmap::map::VacantEntry<'a, StringCow<'b>, Amf0Value<'b>>;
656
657#[cfg(not(feature = "preserve_order"))]
658type OccupiedEntryImpl<'a, 'b> = btree_map::OccupiedEntry<'a, StringCow<'b>, Amf0Value<'b>>;
659#[cfg(feature = "preserve_order")]
660type OccupiedEntryImpl<'a, 'b> = indexmap::map::OccupiedEntry<'a, StringCow<'b>, Amf0Value<'b>>;
661
662impl<'a, 'b> Entry<'a, 'b> {
663    /// Returns a reference to this entry's key.
664    ///
665    /// # Examples
666    ///
667    /// ```
668    /// let mut map = scuffle_amf0::Amf0Object::new();
669    /// assert_eq!(map.entry("serde").key(), &"serde");
670    /// ```
671    pub fn key(&self) -> &StringCow<'b> {
672        match self {
673            Entry::Vacant(e) => e.key(),
674            Entry::Occupied(e) => e.key(),
675        }
676    }
677
678    /// Ensures a value is in the entry by inserting the default if empty, and
679    /// returns a mutable reference to the value in the entry.
680    pub fn or_insert(self, default: Amf0Value<'b>) -> &'a mut Amf0Value<'b> {
681        match self {
682            Entry::Vacant(entry) => entry.insert(default),
683            Entry::Occupied(entry) => entry.into_mut(),
684        }
685    }
686
687    /// Ensures a value is in the entry by inserting the result of the default
688    /// function if empty, and returns a mutable reference to the value in the
689    /// entry.
690    pub fn or_insert_with<F>(self, default: F) -> &'a mut Amf0Value<'b>
691    where
692        F: FnOnce() -> Amf0Value<'b>,
693    {
694        match self {
695            Entry::Vacant(entry) => entry.insert(default()),
696            Entry::Occupied(entry) => entry.into_mut(),
697        }
698    }
699
700    /// Provides in-place mutable access to an occupied entry before any
701    /// potential inserts into the map.
702    pub fn and_modify<F>(self, f: F) -> Self
703    where
704        F: FnOnce(&mut Amf0Value<'b>),
705    {
706        match self {
707            Entry::Occupied(mut entry) => {
708                f(entry.get_mut());
709                Entry::Occupied(entry)
710            }
711            Entry::Vacant(entry) => Entry::Vacant(entry),
712        }
713    }
714}
715
716impl<'a, 'b> VacantEntry<'a, 'b> {
717    /// Gets a reference to the key that would be used when inserting a value
718    /// through the VacantEntry.
719    ///
720    /// # Examples
721    ///
722    /// ```
723    /// use scuffle_amf0::object::Entry;
724    ///
725    /// let mut map = scuffle_amf0::Amf0Object::new();
726    ///
727    /// match map.entry("serde") {
728    ///     Entry::Vacant(vacant) => {
729    ///         assert_eq!(vacant.key(), &"serde");
730    ///     }
731    ///     Entry::Occupied(_) => unimplemented!(),
732    /// }
733    /// ```
734    #[inline]
735    pub fn key(&self) -> &StringCow<'b> {
736        self.vacant.key()
737    }
738
739    /// Sets the value of the entry with the VacantEntry's key, and returns a
740    /// mutable reference to it.
741    #[inline]
742    pub fn insert(self, value: Amf0Value<'b>) -> &'a mut Amf0Value<'b> {
743        self.vacant.insert(value)
744    }
745}
746
747impl<'a, 'b> OccupiedEntry<'a, 'b> {
748    /// Gets a reference to the key in the entry.
749    #[inline]
750    pub fn key(&self) -> &StringCow<'b> {
751        self.occupied.key()
752    }
753
754    /// Gets a reference to the value in the entry.
755    #[inline]
756    pub fn get(&self) -> &Amf0Value<'b> {
757        self.occupied.get()
758    }
759
760    /// Gets a mutable reference to the value in the entry.
761    #[inline]
762    pub fn get_mut(&mut self) -> &mut Amf0Value<'b> {
763        self.occupied.get_mut()
764    }
765
766    /// Converts the entry into a mutable reference to its value.
767    #[inline]
768    pub fn into_mut(self) -> &'a mut Amf0Value<'b> {
769        self.occupied.into_mut()
770    }
771
772    /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns
773    /// the entry's old value.
774    #[inline]
775    pub fn insert(&mut self, value: Amf0Value<'b>) -> Amf0Value<'b> {
776        self.occupied.insert(value)
777    }
778
779    /// Takes the value of the entry out of the map, and returns it.
780    ///
781    /// If scuffle_amf0's "preserve_order" is enabled, `.remove()` is
782    /// equivalent to [`.swap_remove()`][Self::swap_remove], replacing this
783    /// entry's position with the last element. If you need to preserve the
784    /// relative order of the keys in the map, use
785    /// [`.shift_remove()`][Self::shift_remove] instead.
786    #[inline]
787    pub fn remove(self) -> Amf0Value<'b> {
788        #[cfg(feature = "preserve_order")]
789        return self.swap_remove();
790        #[cfg(not(feature = "preserve_order"))]
791        return self.occupied.remove();
792    }
793
794    /// Takes the value of the entry out of the map, and returns it.
795    ///
796    /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the
797    /// last element of the map and popping it off. This perturbs the position
798    /// of what used to be the last element!
799    ///
800    /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove
801    #[cfg(feature = "preserve_order")]
802    #[inline]
803    pub fn swap_remove(self) -> Amf0Value<'b> {
804        self.occupied.swap_remove()
805    }
806
807    /// Takes the value of the entry out of the map, and returns it.
808    ///
809    /// Like [`Vec::remove`], the entry is removed by shifting all of the
810    /// elements that follow it, preserving their relative order. This perturbs
811    /// the index of all of those elements!
812    ///
813    /// [`Vec::remove`]: std::vec::Vec::remove
814    #[cfg(feature = "preserve_order")]
815    #[inline]
816    pub fn shift_remove(self) -> Amf0Value<'b> {
817        self.occupied.shift_remove()
818    }
819
820    /// Removes the entry from the map, returning the stored key and value.
821    ///
822    /// If scuffle_amf0's "preserve_order" is enabled, `.remove_entry()` is
823    /// equivalent to [`.swap_remove_entry()`][Self::swap_remove_entry],
824    /// replacing this entry's position with the last element. If you need to
825    /// preserve the relative order of the keys in the map, use
826    /// [`.shift_remove_entry()`][Self::shift_remove_entry] instead.
827    #[inline]
828    pub fn remove_entry(self) -> (StringCow<'b>, Amf0Value<'b>) {
829        #[cfg(feature = "preserve_order")]
830        return self.swap_remove_entry();
831        #[cfg(not(feature = "preserve_order"))]
832        return self.occupied.remove_entry();
833    }
834
835    /// Removes the entry from the map, returning the stored key and value.
836    ///
837    /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the
838    /// last element of the map and popping it off. This perturbs the position
839    /// of what used to be the last element!
840    ///
841    /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove
842    #[cfg(feature = "preserve_order")]
843    #[inline]
844    pub fn swap_remove_entry(self) -> (StringCow<'b>, Amf0Value<'b>) {
845        self.occupied.swap_remove_entry()
846    }
847
848    /// Removes the entry from the map, returning the stored key and value.
849    ///
850    /// Like [`Vec::remove`], the entry is removed by shifting all of the
851    /// elements that follow it, preserving their relative order. This perturbs
852    /// the index of all of those elements!
853    ///
854    /// [`Vec::remove`]: std::vec::Vec::remove
855    #[cfg(feature = "preserve_order")]
856    #[inline]
857    pub fn shift_remove_entry(self) -> (StringCow<'b>, Amf0Value<'b>) {
858        self.occupied.shift_remove_entry()
859    }
860}
861
862//////////////////////////////////////////////////////////////////////////////
863
864impl<'a, 'b> IntoIterator for &'a Amf0Object<'b> {
865    type IntoIter = Iter<'a, 'b>;
866    type Item = (&'a StringCow<'b>, &'a Amf0Value<'b>);
867
868    #[inline]
869    fn into_iter(self) -> Self::IntoIter {
870        Iter { iter: self.map.iter() }
871    }
872}
873
874/// An iterator over a scuffle_amf0::Amf0Object's entries.
875pub struct Iter<'a, 'b> {
876    iter: IterImpl<'a, 'b>,
877}
878
879#[cfg(not(feature = "preserve_order"))]
880type IterImpl<'a, 'b> = btree_map::Iter<'a, StringCow<'b>, Amf0Value<'b>>;
881#[cfg(feature = "preserve_order")]
882type IterImpl<'a, 'b> = indexmap::map::Iter<'a, StringCow<'b>, Amf0Value<'b>>;
883
884delegate_iterator!((Iter<'a, 'b>) => (&'a StringCow<'b>, &'a Amf0Value<'b>));
885
886//////////////////////////////////////////////////////////////////////////////
887
888impl<'a, 'b> IntoIterator for &'a mut Amf0Object<'b> {
889    type IntoIter = IterMut<'a, 'b>;
890    type Item = (&'a StringCow<'b>, &'a mut Amf0Value<'b>);
891
892    #[inline]
893    fn into_iter(self) -> Self::IntoIter {
894        IterMut {
895            iter: self.map.iter_mut(),
896        }
897    }
898}
899
900/// A mutable iterator over a scuffle_amf0::Amf0Object's entries.
901pub struct IterMut<'a, 'b> {
902    iter: IterMutImpl<'a, 'b>,
903}
904
905#[cfg(not(feature = "preserve_order"))]
906type IterMutImpl<'a, 'b> = btree_map::IterMut<'a, StringCow<'b>, Amf0Value<'b>>;
907#[cfg(feature = "preserve_order")]
908type IterMutImpl<'a, 'b> = indexmap::map::IterMut<'a, StringCow<'b>, Amf0Value<'b>>;
909
910delegate_iterator!((IterMut<'a, 'b>) => (&'a StringCow<'b>, &'a mut Amf0Value<'b>));
911
912//////////////////////////////////////////////////////////////////////////////
913
914impl<'a> IntoIterator for Amf0Object<'a> {
915    type IntoIter = IntoIter<'a>;
916    type Item = (StringCow<'a>, Amf0Value<'a>);
917
918    #[inline]
919    fn into_iter(self) -> Self::IntoIter {
920        IntoIter {
921            iter: self.map.into_iter(),
922        }
923    }
924}
925
926/// An owning iterator over a scuffle_amf0::Amf0Object's entries.
927pub struct IntoIter<'a> {
928    iter: IntoIterImpl<'a>,
929}
930
931#[cfg(not(feature = "preserve_order"))]
932type IntoIterImpl<'a> = btree_map::IntoIter<StringCow<'a>, Amf0Value<'a>>;
933#[cfg(feature = "preserve_order")]
934type IntoIterImpl<'a> = indexmap::map::IntoIter<StringCow<'a>, Amf0Value<'a>>;
935
936delegate_iterator!((IntoIter<'a>) => (StringCow<'a>, Amf0Value<'a>));
937
938//////////////////////////////////////////////////////////////////////////////
939
940/// An iterator over a scuffle_amf0::Amf0Object's keys.
941pub struct Keys<'a, 'b> {
942    iter: KeysImpl<'a, 'b>,
943}
944
945#[cfg(not(feature = "preserve_order"))]
946type KeysImpl<'a, 'b> = btree_map::Keys<'a, StringCow<'b>, Amf0Value<'b>>;
947#[cfg(feature = "preserve_order")]
948type KeysImpl<'a, 'b> = indexmap::map::Keys<'a, StringCow<'b>, Amf0Value<'b>>;
949
950delegate_iterator!((Keys<'a, 'b>) => &'a StringCow<'b>);
951
952//////////////////////////////////////////////////////////////////////////////
953
954/// An iterator over a scuffle_amf0::Amf0Object's values.
955pub struct Values<'a, 'b> {
956    iter: ValuesImpl<'a, 'b>,
957}
958
959#[cfg(not(feature = "preserve_order"))]
960type ValuesImpl<'a, 'b> = btree_map::Values<'a, StringCow<'b>, Amf0Value<'b>>;
961#[cfg(feature = "preserve_order")]
962type ValuesImpl<'a, 'b> = indexmap::map::Values<'a, StringCow<'b>, Amf0Value<'b>>;
963
964delegate_iterator!((Values<'a, 'b>) => &'a Amf0Value<'b>);
965
966//////////////////////////////////////////////////////////////////////////////
967
968/// A mutable iterator over a scuffle_amf0::Amf0Object's values.
969pub struct ValuesMut<'a, 'b> {
970    iter: ValuesMutImpl<'a, 'b>,
971}
972
973#[cfg(not(feature = "preserve_order"))]
974type ValuesMutImpl<'a, 'b> = btree_map::ValuesMut<'a, StringCow<'b>, Amf0Value<'b>>;
975#[cfg(feature = "preserve_order")]
976type ValuesMutImpl<'a, 'b> = indexmap::map::ValuesMut<'a, StringCow<'b>, Amf0Value<'b>>;
977
978delegate_iterator!((ValuesMut<'a, 'b>) => &'a mut Amf0Value<'b>);
979
980//////////////////////////////////////////////////////////////////////////////
981
982/// An owning iterator over a scuffle_amf0::Amf0Object's values.
983pub struct IntoValues<'a> {
984    iter: IntoValuesImpl<'a>,
985}
986
987#[cfg(not(feature = "preserve_order"))]
988type IntoValuesImpl<'a> = btree_map::IntoValues<StringCow<'a>, Amf0Value<'a>>;
989#[cfg(feature = "preserve_order")]
990type IntoValuesImpl<'a> = indexmap::map::IntoValues<StringCow<'a>, Amf0Value<'a>>;
991
992delegate_iterator!((IntoValues<'a>) => Amf0Value<'a>);
993
994#[cfg(test)]
995#[cfg_attr(all(test, coverage_nightly), coverage(off))]
996mod tests {
997    use scuffle_bytes_util::StringCow;
998    use serde::Deserialize;
999
1000    use super::Entry;
1001    use crate::{Amf0Object, Amf0Value};
1002
1003    #[test]
1004    fn test_default_map_is_empty() {
1005        let obj: Amf0Object = Amf0Object::default();
1006        assert!(obj.map.is_empty(), "Default Amf0Object should be empty");
1007    }
1008
1009    #[cfg(feature = "preserve_order")]
1010    #[test]
1011    fn test_capacity_reserves_space_in_preserve_order() {
1012        let capacity = 16;
1013        let obj: Amf0Object = Amf0Object::with_capacity(capacity);
1014
1015        use indexmap::map::IndexMap;
1016        let map: &IndexMap<_, _> = &obj.map;
1017        assert!(
1018            map.capacity() >= capacity,
1019            "IndexMap should reserve at least the requested capacity"
1020        );
1021    }
1022
1023    #[cfg(not(feature = "preserve_order"))]
1024    #[test]
1025    fn test_capacity_ignored_without_preserve_order() {
1026        let capacity = 16;
1027        let obj: Amf0Object = Amf0Object::with_capacity(capacity);
1028
1029        let key = StringCow::from("foo");
1030        let value = Amf0Value::String(StringCow::from("bar"));
1031        assert!(obj.map.insert(key.clone(), value.clone()).is_none());
1032        assert_eq!(obj.map.get(&key), Some(&value));
1033    }
1034
1035    #[test]
1036    fn test_clear() {
1037        let mut obj = Amf0Object::new();
1038
1039        obj.map.insert(StringCow::from("key1"), Amf0Value::Number(1.0));
1040        obj.map
1041            .insert(StringCow::from("key2"), Amf0Value::String(StringCow::from("value")));
1042        obj.map.insert(StringCow::from("key3"), Amf0Value::Boolean(true));
1043
1044        assert!(!obj.map.is_empty(), "Map should not be empty before clear");
1045        obj.clear();
1046        assert!(obj.map.is_empty(), "Map should be empty after clear");
1047    }
1048
1049    #[test]
1050    fn test_contains_key() {
1051        let mut obj = Amf0Object::new();
1052
1053        let existing_key = StringCow::from("present");
1054        let missing_key = "missing";
1055
1056        obj.map.insert(existing_key.clone(), Amf0Value::Boolean(true));
1057
1058        assert!(obj.contains_key(&existing_key), "Expected key to be found using StringCow");
1059        assert!(obj.contains_key("present"), "Expected key to be found using &str");
1060        assert!(!obj.contains_key(missing_key), "Expected missing key to not be found");
1061    }
1062
1063    #[test]
1064    fn test_get_mut_valid() {
1065        let mut obj = Amf0Object::new();
1066        obj.map
1067            .insert(StringCow::from("username"), Amf0Value::String(StringCow::from("old_name")));
1068
1069        if let Some(value) = obj.get_mut("username") {
1070            *value = Amf0Value::String(StringCow::from("new_name"));
1071        } else {
1072            panic!("Expected Some(&mut Amf0Value) for existing key");
1073        }
1074
1075        assert_eq!(obj.map.get("username"), Some(&Amf0Value::String(StringCow::from("new_name"))));
1076    }
1077
1078    #[test]
1079    fn test_get_mut_invalid() {
1080        let mut obj = Amf0Object::new();
1081        assert!(obj.get_mut("nonexistent_key").is_none());
1082    }
1083
1084    #[test]
1085    fn test_get_key_value_valid() {
1086        let mut obj = Amf0Object::new();
1087        let key = StringCow::from("foo");
1088        let value = Amf0Value::Number(3.21);
1089
1090        obj.map.insert(key.clone(), value.clone());
1091
1092        if let Some((found_key, found_value)) = obj.get_key_value("foo") {
1093            assert_eq!(found_key, &key);
1094            assert_eq!(found_value, &value);
1095        } else {
1096            panic!("Expected Some((key, value)) for existing key");
1097        }
1098    }
1099
1100    #[test]
1101    fn test_get_key_value_invalid() {
1102        let obj = Amf0Object::new();
1103        assert!(obj.get_key_value("missing").is_none());
1104    }
1105
1106    #[cfg(feature = "preserve_order")]
1107    #[test]
1108    fn test_shift_insert_inserts_and_shifts_correctly() {
1109        let mut obj = Amf0Object::new();
1110
1111        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1112        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1113        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1114
1115        let ret_new = obj.shift_insert(1, StringCow::from("x"), Amf0Value::Number(9.0));
1116        assert!(ret_new.is_none(), "Inserting a brand‐new key should return None");
1117
1118        let keys_after_insert: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1119        assert_eq!(
1120            keys_after_insert,
1121            vec!["a", "x", "b", "c"],
1122            "After shifting in 'x' at index 1, order should be [\"a\", \"x\", \"b\", \"c\"]"
1123        );
1124
1125        let old_value = obj.shift_insert(0, StringCow::from("b"), Amf0Value::Number(7.0));
1126        assert_eq!(
1127            old_value,
1128            Some(Amf0Value::Number(2.0)),
1129            "Reinserting 'b' must return its previous value"
1130        );
1131
1132        let keys_after_reinsert: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1133        assert_eq!(
1134            keys_after_reinsert,
1135            vec!["b", "a", "x", "c"],
1136            "After shifting 'b' to index 0, order should be [\"b\", \"a\", \"x\", \"c\"]"
1137        );
1138
1139        assert_eq!(
1140            obj.map.get("b"),
1141            Some(&Amf0Value::Number(7.0)),
1142            "The value for key 'b' should now be updated to 7.0"
1143        );
1144    }
1145
1146    #[test]
1147    #[cfg(not(feature = "preserve_order"))]
1148    fn test_remove_non_preserve_order() {
1149        let mut obj = Amf0Object::new();
1150
1151        obj.map.insert(StringCow::from("key1"), Amf0Value::Number(10.0));
1152        obj.map
1153            .insert(StringCow::from("key2"), Amf0Value::String(StringCow::from("value")));
1154        obj.map.insert(StringCow::from("key3"), Amf0Value::Boolean(false));
1155
1156        let removed = obj.remove("key2");
1157        assert_eq!(
1158            removed,
1159            Some(Amf0Value::String(StringCow::from("value"))),
1160            "remove should return the value for an existing key"
1161        );
1162
1163        assert!(!obj.map.contains_key("key2"), "key2 should no longer exist after removal");
1164        assert!(
1165            obj.remove("missing").is_none(),
1166            "remove on a nonexistent key should return None"
1167        );
1168    }
1169
1170    #[test]
1171    #[cfg(feature = "preserve_order")]
1172    fn test_remove_preserve_order_swap_remove_behavior() {
1173        let mut obj = Amf0Object::new();
1174
1175        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1176        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1177        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1178
1179        let removed = obj.remove("b");
1180        assert_eq!(
1181            removed,
1182            Some(Amf0Value::Number(2.0)),
1183            "remove should return the old value for key 'b'"
1184        );
1185
1186        let keys_after: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1187        assert_eq!(
1188            keys_after,
1189            vec!["a", "c"],
1190            "After removing 'b', the order should be [\"a\", \"c\"]"
1191        );
1192        assert!(!obj.map.contains_key("b"), "key 'b' should be gone after removal");
1193        assert!(obj.map.contains_key("c"), "key 'c' should still be present");
1194        assert!(
1195            obj.remove("missing").is_none(),
1196            "remove on a nonexistent key should return None"
1197        );
1198    }
1199
1200    #[test]
1201    #[cfg(not(feature = "preserve_order"))]
1202    fn test_remove_entry_non_preserve_order() {
1203        let mut obj = Amf0Object::new();
1204
1205        obj.map.insert(StringCow::from("k1"), Amf0Value::Number(1.0));
1206        obj.map
1207            .insert(StringCow::from("k2"), Amf0Value::String(StringCow::from("v2")));
1208        obj.map.insert(StringCow::from("k3"), Amf0Value::Boolean(true));
1209
1210        let entry = obj.remove_entry("k2");
1211        assert_eq!(
1212            entry,
1213            Some((StringCow::from("k2"), Amf0Value::String(StringCow::from("v2")))),
1214            "Expected remove_entry to return the removed key and value"
1215        );
1216
1217        assert!(!obj.map.contains_key("k2"), "Key 'k2' should be gone after remove_entry");
1218        assert!(
1219            obj.remove_entry("missing").is_none(),
1220            "remove_entry on nonexistent key should return None"
1221        );
1222    }
1223
1224    #[test]
1225    #[cfg(feature = "preserve_order")]
1226    fn test_remove_entry_preserve_order_swap_remove_entry() {
1227        let mut obj = Amf0Object::new();
1228
1229        obj.map.insert(StringCow::from("a"), Amf0Value::Number(10.0));
1230        obj.map.insert(StringCow::from("b"), Amf0Value::Number(20.0));
1231        obj.map.insert(StringCow::from("c"), Amf0Value::Number(30.0));
1232        obj.map.insert(StringCow::from("d"), Amf0Value::Number(40.0));
1233
1234        let entry = obj.remove_entry("b");
1235        assert_eq!(
1236            entry,
1237            Some((StringCow::from("b"), Amf0Value::Number(20.0))),
1238            "Expected remove_entry to return the removed key 'b' and its value"
1239        );
1240
1241        let keys_after: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1242        assert_eq!(
1243            keys_after,
1244            vec!["a", "d", "c"],
1245            "After swap_remove_entry on 'b', order should be [\"a\", \"d\", \"c\"]"
1246        );
1247        assert!(!obj.map.contains_key("b"), "Key 'b' should be gone after remove_entry");
1248        assert!(obj.map.contains_key("d"), "Key 'd' should still be present");
1249        assert!(obj.map.contains_key("c"), "Key 'c' should still be present");
1250        assert!(
1251            obj.remove_entry("missing").is_none(),
1252            "remove_entry on nonexistent key should return None"
1253        );
1254    }
1255
1256    #[test]
1257    #[cfg(feature = "preserve_order")]
1258    fn test_swap_remove_existing_and_order() {
1259        let mut obj = Amf0Object::new();
1260
1261        obj.map.insert(StringCow::from("one"), Amf0Value::Number(1.0));
1262        obj.map.insert(StringCow::from("two"), Amf0Value::Number(2.0));
1263        obj.map.insert(StringCow::from("three"), Amf0Value::Number(3.0));
1264        obj.map.insert(StringCow::from("four"), Amf0Value::Number(4.0));
1265
1266        let removed = obj.swap_remove("two");
1267        assert_eq!(
1268            removed,
1269            Some(Amf0Value::Number(2.0)),
1270            "swap_remove should return the removed value for key 'two'"
1271        );
1272
1273        let keys_after: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1274        assert_eq!(
1275            keys_after,
1276            vec!["one", "four", "three"],
1277            "After swap_remove on 'two', order should be [\"one\", \"four\", \"three\"]"
1278        );
1279        assert!(!obj.map.contains_key("two"), "Key 'two' should no longer exist");
1280        assert!(obj.map.contains_key("four"), "Key 'four' should still be present");
1281        assert!(
1282            obj.swap_remove("absent").is_none(),
1283            "swap_remove on nonexistent key should return None"
1284        );
1285    }
1286
1287    #[test]
1288    #[cfg(feature = "preserve_order")]
1289    fn test_swap_remove_entry_preserve_order() {
1290        let mut obj = Amf0Object::new();
1291
1292        obj.map.insert(StringCow::from("a"), Amf0Value::Number(10.0));
1293        obj.map.insert(StringCow::from("b"), Amf0Value::Number(20.0));
1294        obj.map.insert(StringCow::from("c"), Amf0Value::Number(30.0));
1295        obj.map.insert(StringCow::from("d"), Amf0Value::Number(40.0));
1296
1297        let entry = obj.swap_remove_entry("b");
1298        assert_eq!(
1299            entry,
1300            Some((StringCow::from("b"), Amf0Value::Number(20.0))),
1301            "Expected swap_remove_entry to return the removed key 'b' and its value"
1302        );
1303
1304        let keys_after: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1305        assert_eq!(
1306            keys_after,
1307            vec!["a", "d", "c"],
1308            "After swap_remove_entry on 'b', order should be [\"a\", \"d\", \"c\"]"
1309        );
1310
1311        assert!(!obj.map.contains_key("b"), "Key 'b' should no longer exist");
1312        assert!(obj.map.contains_key("d"), "Key 'd' should still be present");
1313        assert!(obj.map.contains_key("c"), "Key 'c' should still be present");
1314        assert!(
1315            obj.swap_remove_entry("missing").is_none(),
1316            "swap_remove_entry on nonexistent key should return None"
1317        );
1318    }
1319
1320    #[test]
1321    #[cfg(feature = "preserve_order")]
1322    fn test_shift_remove_preserve_order() {
1323        let mut obj = Amf0Object::new();
1324
1325        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1326        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1327        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1328        obj.map.insert(StringCow::from("d"), Amf0Value::Number(4.0));
1329
1330        let removed = obj.shift_remove("b");
1331        assert_eq!(
1332            removed,
1333            Some(Amf0Value::Number(2.0)),
1334            "shift_remove should return the removed value for key 'b'"
1335        );
1336
1337        let keys_after: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1338        assert_eq!(
1339            keys_after,
1340            vec!["a", "c", "d"],
1341            "After shift_remove on 'b', order should be [\"a\", \"c\", \"d\"]"
1342        );
1343        assert!(!obj.map.contains_key("b"), "Key 'b' should no longer exist");
1344        assert!(obj.map.contains_key("c"), "Key 'c' should still be present");
1345        assert!(obj.map.contains_key("d"), "Key 'd' should still be present");
1346        assert!(
1347            obj.shift_remove("missing").is_none(),
1348            "shift_remove on nonexistent key should return None"
1349        );
1350    }
1351
1352    #[test]
1353    #[cfg(feature = "preserve_order")]
1354    fn test_shift_remove_entry_preserve_order() {
1355        let mut obj = Amf0Object::new();
1356
1357        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1358        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1359        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1360        obj.map.insert(StringCow::from("d"), Amf0Value::Number(4.0));
1361
1362        let entry = obj.shift_remove_entry("b");
1363        assert_eq!(
1364            entry,
1365            Some((StringCow::from("b"), Amf0Value::Number(2.0))),
1366            "Expected shift_remove_entry to return removed key 'b' and its value"
1367        );
1368
1369        let keys_after: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1370        assert_eq!(
1371            keys_after,
1372            vec!["a", "c", "d"],
1373            "After shift_remove_entry on 'b', order should be [\"a\", \"c\", \"d\"]"
1374        );
1375        assert!(!obj.map.contains_key("b"), "Key 'b' should no longer exist");
1376        assert!(obj.map.contains_key("c"), "Key 'c' should still be present");
1377        assert!(obj.map.contains_key("d"), "Key 'd' should still be present");
1378        assert!(
1379            obj.shift_remove_entry("missing").is_none(),
1380            "shift_remove_entry on nonexistent key should return None"
1381        );
1382    }
1383
1384    #[test]
1385    #[cfg(not(feature = "preserve_order"))]
1386    fn test_append_non_preserve_order_merges_and_clears_other() {
1387        let mut obj1 = Amf0Object::new();
1388        let mut obj2 = Amf0Object::new();
1389
1390        obj1.map.insert(StringCow::from("k1"), Amf0Value::Number(1.0));
1391        obj1.map.insert(StringCow::from("k2"), Amf0Value::Number(2.0));
1392
1393        obj2.map.insert(StringCow::from("k2"), Amf0Value::Number(22.0)); // collision
1394        obj2.map.insert(StringCow::from("k3"), Amf0Value::Number(3.0));
1395        obj1.append(&mut obj2);
1396
1397        assert_eq!(obj1.map.len(), 3);
1398        assert_eq!(obj1.map.get("k1"), Some(&Amf0Value::Number(1.0)));
1399        assert_eq!(obj1.map.get("k2"), Some(&Amf0Value::Number(22.0)));
1400        assert_eq!(obj1.map.get("k3"), Some(&Amf0Value::Number(3.0)));
1401        assert!(obj2.map.is_empty(), "obj2 should be emptied after append");
1402    }
1403
1404    #[test]
1405    #[cfg(feature = "preserve_order")]
1406    fn test_append_preserve_order_extends_and_clears_other() {
1407        let mut obj1 = Amf0Object::new();
1408        let mut obj2 = Amf0Object::new();
1409
1410        obj1.map.insert(StringCow::from("a"), Amf0Value::Number(10.0));
1411        obj1.map.insert(StringCow::from("b"), Amf0Value::Number(20.0));
1412
1413        obj2.map.insert(StringCow::from("b"), Amf0Value::Number(200.0)); // collision
1414        obj2.map.insert(StringCow::from("c"), Amf0Value::Number(30.0));
1415        obj1.append(&mut obj2);
1416
1417        let keys_after: Vec<&str> = obj1.map.keys().map(|k| k.as_ref()).collect();
1418        let values_after: Vec<&Amf0Value> = obj1.map.values().collect();
1419
1420        assert_eq!(
1421            keys_after,
1422            vec!["a", "b", "c"],
1423            "Order should preserve original keys, with duplicates replaced, then obj2's new keys"
1424        );
1425
1426        assert_eq!(
1427            values_after,
1428            vec![&Amf0Value::Number(10.0), &Amf0Value::Number(200.0), &Amf0Value::Number(30.0),]
1429        );
1430
1431        assert!(obj2.map.is_empty(), "obj2 should be emptied after append");
1432    }
1433
1434    #[test]
1435    #[cfg(not(feature = "preserve_order"))]
1436    fn test_entry_vacant_inserts_value_non_preserve_order() {
1437        let mut obj = Amf0Object::new();
1438
1439        match obj.entry("new_key") {
1440            Entry::Vacant(mut vacant) => {
1441                vacant.insert(Amf0Value::Number(42.0));
1442            }
1443            Entry::Occupied(_) => panic!("Expected Vacant for a missing key"),
1444        }
1445
1446        assert_eq!(
1447            obj.map.get("new_key"),
1448            Some(&Amf0Value::Number(42.0)),
1449            "Value inserted via entry should be retrievable"
1450        );
1451    }
1452
1453    #[test]
1454    #[cfg(feature = "preserve_order")]
1455    fn test_entry_vacant_inserts_value_preserve_order() {
1456        let mut obj = Amf0Object::new();
1457        match obj.entry("vacant_key") {
1458            Entry::Vacant(vacant) => {
1459                vacant.insert(Amf0Value::Number(123.0));
1460            }
1461            Entry::Occupied(_) => panic!("Expected Vacant for a missing key"),
1462        }
1463
1464        let keys: Vec<&str> = obj.map.keys().map(|k| k.as_ref()).collect();
1465        assert_eq!(keys, vec!["vacant_key"]);
1466        assert_eq!(obj.map.get("vacant_key"), Some(&Amf0Value::Number(123.0)));
1467    }
1468
1469    #[test]
1470    #[cfg(feature = "preserve_order")]
1471    fn test_entry_occupied_modifies_existing_value_preserve_order() {
1472        let mut obj = Amf0Object::new();
1473        obj.map.insert(StringCow::from("existing"), Amf0Value::Number(1.0));
1474
1475        match obj.entry("existing") {
1476            Entry::Vacant(_) => panic!("Expected Occupied for an existing key"),
1477            Entry::Occupied(mut occupied) => {
1478                *occupied.get_mut() = Amf0Value::Number(99.0);
1479            }
1480        }
1481
1482        assert_eq!(
1483            obj.map.get("existing"),
1484            Some(&Amf0Value::Number(99.0)),
1485            "Occupied entry modification should update the stored value"
1486        );
1487    }
1488
1489    #[test]
1490    #[cfg(not(feature = "preserve_order"))]
1491    fn test_is_empty_non_preserve_order() {
1492        let mut obj = Amf0Object::new();
1493        assert!(obj.is_empty(), "Newly created Amf0Object should be empty");
1494
1495        obj.map.insert(StringCow::from("key"), Amf0Value::Number(5.0));
1496        assert!(!obj.is_empty(), "Amf0Object should not be empty after insertion");
1497
1498        obj.clear();
1499        assert!(obj.is_empty(), "Amf0Object should be empty after clear");
1500    }
1501
1502    #[test]
1503    #[cfg(feature = "preserve_order")]
1504    fn test_is_empty_preserve_order() {
1505        let mut obj = Amf0Object::new();
1506        assert!(obj.is_empty(), "Newly created Amf0Object should be empty");
1507
1508        obj.map.insert(StringCow::from("alpha"), Amf0Value::Number(1.0));
1509        assert!(!obj.is_empty(), "Amf0Object should not be empty after insertion");
1510
1511        obj.shift_remove("alpha");
1512        assert!(obj.is_empty(), "Amf0Object should be empty after removing the only key");
1513    }
1514
1515    #[test]
1516    #[cfg(not(feature = "preserve_order"))]
1517    fn test_iter_mut_non_preserve_order() {
1518        let mut obj = Amf0Object::new();
1519        obj.map.insert(StringCow::from("k1"), Amf0Value::Number(1.0));
1520        obj.map.insert(StringCow::from("k2"), Amf0Value::Number(2.0));
1521        obj.map.insert(StringCow::from("k3"), Amf0Value::Number(3.0));
1522
1523        for (_k, v) in obj.iter_mut() {
1524            if let Amf0Value::Number(ref mut n) = *v {
1525                *n += 10.0;
1526            }
1527        }
1528
1529        assert_eq!(obj.map.get("k1"), Some(&Amf0Value::Number(11.0)));
1530        assert_eq!(obj.map.get("k2"), Some(&Amf0Value::Number(12.0)));
1531        assert_eq!(obj.map.get("k3"), Some(&Amf0Value::Number(13.0)));
1532    }
1533
1534    #[test]
1535    #[cfg(feature = "preserve_order")]
1536    fn test_iter_mut_preserve_order() {
1537        let mut obj = Amf0Object::new();
1538        obj.map.insert(StringCow::from("a"), Amf0Value::Number(5.0));
1539        obj.map.insert(StringCow::from("b"), Amf0Value::Number(6.0));
1540        obj.map.insert(StringCow::from("c"), Amf0Value::Number(7.0));
1541
1542        let keys: Vec<&str> = obj.iter_mut().map(|(k, _)| k.as_ref()).collect();
1543        assert_eq!(keys, vec!["a", "b", "c"], "Iteration order should follow insertion order");
1544
1545        for (_k, v) in obj.iter_mut() {
1546            *v = Amf0Value::Number(0.0);
1547        }
1548
1549        assert_eq!(obj.map.get("a"), Some(&Amf0Value::Number(0.0)));
1550        assert_eq!(obj.map.get("b"), Some(&Amf0Value::Number(0.0)));
1551        assert_eq!(obj.map.get("c"), Some(&Amf0Value::Number(0.0)));
1552    }
1553
1554    #[test]
1555    #[cfg(not(feature = "preserve_order"))]
1556    fn test_keys_non_preserve_order_sorted() {
1557        let mut obj = Amf0Object::new();
1558
1559        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1560        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1561        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1562
1563        let keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1564        assert_eq!(keys, vec!["a", "b", "c"], "Expected keys sorted lexicographically");
1565    }
1566
1567    #[test]
1568    #[cfg(feature = "preserve_order")]
1569    fn test_keys_preserve_order_insertion() {
1570        let mut obj = Amf0Object::new();
1571
1572        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1573        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1574        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1575
1576        let keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1577        assert_eq!(keys, vec!["b", "a", "c"], "Expected keys in insertion order");
1578    }
1579
1580    #[test]
1581    #[cfg(not(feature = "preserve_order"))]
1582    fn test_values_non_preserve_order_sorted_by_key() {
1583        let mut obj = Amf0Object::new();
1584
1585        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1586        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1587        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1588
1589        let values: Vec<&Amf0Value> = obj.values().collect();
1590        assert_eq!(
1591            values,
1592            vec![&Amf0Value::Number(1.0), &Amf0Value::Number(2.0), &Amf0Value::Number(3.0)],
1593            "Expected values in order of sorted keys"
1594        );
1595    }
1596
1597    #[test]
1598    #[cfg(feature = "preserve_order")]
1599    fn test_values_preserve_order_insertion() {
1600        let mut obj = Amf0Object::new();
1601
1602        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1603        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1604        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1605
1606        let values: Vec<&Amf0Value> = obj.values().collect();
1607        assert_eq!(
1608            values,
1609            vec![&Amf0Value::Number(2.0), &Amf0Value::Number(1.0), &Amf0Value::Number(3.0)],
1610            "Expected values in insertion order"
1611        );
1612    }
1613
1614    #[test]
1615    #[cfg(not(feature = "preserve_order"))]
1616    fn test_values_mut_non_preserve_order() {
1617        let mut obj = Amf0Object::new();
1618
1619        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1620        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1621        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1622
1623        for value in obj.values_mut() {
1624            if let Amf0Value::Number(ref mut n) = *value {
1625                *n *= 10.0;
1626            }
1627        }
1628
1629        let sorted_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1630        assert_eq!(sorted_keys, vec!["a", "b", "c"]);
1631
1632        assert_eq!(obj.map.get("a"), Some(&Amf0Value::Number(10.0)));
1633        assert_eq!(obj.map.get("b"), Some(&Amf0Value::Number(20.0)));
1634        assert_eq!(obj.map.get("c"), Some(&Amf0Value::Number(30.0)));
1635    }
1636
1637    #[test]
1638    #[cfg(feature = "preserve_order")]
1639    fn test_values_mut_preserve_order() {
1640        let mut obj = Amf0Object::new();
1641
1642        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1643        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1644        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1645
1646        for value in obj.values_mut() {
1647            *value = Amf0Value::Number(0.0);
1648        }
1649
1650        let keys_in_order: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1651        assert_eq!(keys_in_order, vec!["b", "a", "c"]);
1652
1653        assert_eq!(obj.map.get("b"), Some(&Amf0Value::Number(0.0)));
1654        assert_eq!(obj.map.get("a"), Some(&Amf0Value::Number(0.0)));
1655        assert_eq!(obj.map.get("c"), Some(&Amf0Value::Number(0.0)));
1656    }
1657
1658    #[test]
1659    #[cfg(not(feature = "preserve_order"))]
1660    fn test_into_values_consume_and_return_sorted_values() {
1661        let mut obj = Amf0Object::new();
1662
1663        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1664        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1665        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1666
1667        let values: Vec<Amf0Value> = obj.into_values().collect();
1668        assert_eq!(
1669            values,
1670            vec![Amf0Value::Number(1.0), Amf0Value::Number(2.0), Amf0Value::Number(3.0)],
1671            "into_values should yield values in key‐sorted order for BTreeMap"
1672        );
1673    }
1674
1675    #[test]
1676    #[cfg(feature = "preserve_order")]
1677    fn test_into_values_consume_and_return_insertion_order_values() {
1678        let mut obj = Amf0Object::new();
1679
1680        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1681        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1682        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1683
1684        let values: Vec<Amf0Value> = obj.into_values().collect();
1685        assert_eq!(
1686            values,
1687            vec![Amf0Value::Number(2.0), Amf0Value::Number(1.0), Amf0Value::Number(3.0)],
1688            "into_values should yield values in insertion order for IndexMap"
1689        );
1690    }
1691
1692    #[test]
1693    #[cfg(not(feature = "preserve_order"))]
1694    fn test_retain_non_preserve_order() {
1695        let mut obj = Amf0Object::new();
1696
1697        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1698        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1699        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1700        obj.map.insert(StringCow::from("d"), Amf0Value::Number(4.0));
1701
1702        obj.retain(|_key, value| if let Amf0Value::Number(n) = *value { n > 2.0 } else { false });
1703
1704        let remaining_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1705        assert_eq!(remaining_keys, vec!["c", "d"]);
1706
1707        assert_eq!(obj.map.get("c"), Some(&Amf0Value::Number(3.0)));
1708        assert_eq!(obj.map.get("d"), Some(&Amf0Value::Number(4.0)));
1709
1710        assert!(!obj.map.contains_key("a"));
1711        assert!(!obj.map.contains_key("b"));
1712    }
1713
1714    #[test]
1715    #[cfg(feature = "preserve_order")]
1716    fn test_retain_preserve_order() {
1717        let mut obj = Amf0Object::new();
1718
1719        obj.map.insert(StringCow::from("x1"), Amf0Value::Number(1.0));
1720        obj.map.insert(StringCow::from("x2"), Amf0Value::Number(2.0));
1721        obj.map.insert(StringCow::from("x3"), Amf0Value::Number(3.0));
1722        obj.map.insert(StringCow::from("x4"), Amf0Value::Number(4.0));
1723
1724        obj.retain(|_key, value| {
1725            if let Amf0Value::Number(n) = *value {
1726                (n as i64) % 2 == 0
1727            } else {
1728                false
1729            }
1730        });
1731
1732        let remaining_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1733        assert_eq!(remaining_keys, vec!["x2", "x4"]);
1734
1735        assert_eq!(obj.map.get("x2"), Some(&Amf0Value::Number(2.0)));
1736        assert_eq!(obj.map.get("x4"), Some(&Amf0Value::Number(4.0)));
1737
1738        assert!(!obj.map.contains_key("x1"));
1739        assert!(!obj.map.contains_key("x3"));
1740    }
1741
1742    #[test]
1743    #[cfg(feature = "preserve_order")]
1744    fn test_sort_keys_preserve_order() {
1745        let mut obj = Amf0Object::new();
1746
1747        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1748        obj.map.insert(StringCow::from("d"), Amf0Value::Number(4.0));
1749        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1750        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1751
1752        let before: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1753        assert_eq!(before, vec!["b", "d", "a", "c"]);
1754
1755        obj.sort_keys();
1756
1757        let after: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1758        assert_eq!(after, vec!["a", "b", "c", "d"]);
1759
1760        assert_eq!(obj.map.get("a"), Some(&Amf0Value::Number(1.0)));
1761        assert_eq!(obj.map.get("b"), Some(&Amf0Value::Number(2.0)));
1762        assert_eq!(obj.map.get("c"), Some(&Amf0Value::Number(3.0)));
1763        assert_eq!(obj.map.get("d"), Some(&Amf0Value::Number(4.0)));
1764    }
1765
1766    #[test]
1767    fn test_index_returns_value_for_existing_key() {
1768        let mut obj = Amf0Object::new();
1769        obj.map.insert(StringCow::from("alpha"), Amf0Value::Number(3.21));
1770
1771        let v: &Amf0Value = &obj["alpha"];
1772        assert_eq!(v, &Amf0Value::Number(3.21));
1773    }
1774
1775    #[test]
1776    #[should_panic]
1777    fn test_index_panics_on_missing_key() {
1778        let obj = Amf0Object::new();
1779        // Indexing a non‐existent key should panic
1780        let _ = &obj["nonexistent"];
1781    }
1782
1783    #[test]
1784    fn test_index_mut_modifies_existing_value() {
1785        let mut obj = Amf0Object::new();
1786        obj.map.insert(StringCow::from("key1"), Amf0Value::Number(5.0));
1787
1788        obj["key1"] = Amf0Value::Number(42.0);
1789
1790        assert_eq!(
1791            obj.map.get("key1"),
1792            Some(&Amf0Value::Number(42.0)),
1793            "IndexMut should allow updating the value"
1794        );
1795    }
1796
1797    #[test]
1798    #[should_panic(expected = "no entry found for key")]
1799    fn test_index_mut_panics_on_missing_key() {
1800        let mut obj = Amf0Object::new();
1801        obj["nonexistent"] = Amf0Value::Boolean(true);
1802    }
1803
1804    #[cfg(not(feature = "preserve_order"))]
1805    #[test]
1806    fn test_debug_formats_sorted_map_non_preserve_order() {
1807        let mut obj = Amf0Object::new();
1808
1809        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1810        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1811
1812        insta::assert_debug_snapshot!(obj, @r#"
1813        {
1814            Ref(
1815                "b",
1816            ): Number(
1817                2.0,
1818            ),
1819            Ref(
1820                "a",
1821            ): Number(
1822                1.0,
1823            ),
1824        }
1825        "#);
1826    }
1827
1828    #[cfg(feature = "preserve_order")]
1829    #[test]
1830    fn test_debug_formats_insertion_order_preserve_order() {
1831        let mut obj = Amf0Object::new();
1832
1833        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1834        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1835
1836        insta::assert_debug_snapshot!(obj, @r#"
1837        {
1838            Ref(
1839                "b",
1840            ): Number(
1841                2.0,
1842            ),
1843            Ref(
1844                "a",
1845            ): Number(
1846                1.0,
1847            ),
1848        }
1849        "#);
1850    }
1851
1852    #[cfg(feature = "serde")]
1853    #[test]
1854    fn test_visit_unit_returns_empty_object() {
1855        use serde::de::value::{Error as DeError, UnitDeserializer};
1856
1857        // Using Serde's built-in UnitDeserializer, which directly calls visit_unit()
1858        let deser: UnitDeserializer<DeError> = UnitDeserializer::new();
1859        let obj = Amf0Object::deserialize(deser).unwrap();
1860
1861        assert!(obj.is_empty(), "visit_unit should produce an empty Amf0Object");
1862    }
1863
1864    #[cfg(feature = "serde")]
1865    #[test]
1866    fn test_expecting_error_message() {
1867        use serde::de::value::Error as DeError;
1868        use serde::de::{self};
1869
1870        struct WrongTypeDeserializer;
1871
1872        impl<'de> de::Deserializer<'de> for WrongTypeDeserializer {
1873            type Error = DeError;
1874
1875            serde::forward_to_deserialize_any! {
1876                bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf
1877                option unit unit_struct newtype_struct seq tuple tuple_struct map struct
1878                enum identifier ignored_any
1879            }
1880
1881            fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
1882            where
1883                V: de::Visitor<'de>,
1884            {
1885                Err(de::Error::invalid_type(de::Unexpected::Bool(true), &visitor))
1886            }
1887        }
1888
1889        let err = Amf0Object::deserialize(WrongTypeDeserializer).unwrap_err();
1890        let msg = err.to_string();
1891
1892        assert!(
1893            msg.contains("a map"),
1894            "expecting() should include 'a map' in the error message, got: '{}'",
1895            msg
1896        );
1897    }
1898
1899    #[cfg(not(feature = "preserve_order"))]
1900    #[test]
1901    fn test_extend_non_preserve_order_inserts_and_sorts() {
1902        let mut obj = Amf0Object::new();
1903
1904        let items = vec![
1905            (StringCow::from("b"), Amf0Value::Number(2.0)),
1906            (StringCow::from("a"), Amf0Value::Number(1.0)),
1907            (StringCow::from("a"), Amf0Value::Number(5.0)),
1908            (StringCow::from("c"), Amf0Value::Number(3.0)),
1909        ];
1910
1911        obj.extend(items);
1912
1913        let keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1914        assert_eq!(
1915            keys,
1916            vec!["a", "b", "c"],
1917            "Non-preserve_order: keys should be sorted lexicographically"
1918        );
1919
1920        assert_eq!(obj.map.get("a"), Some(&Amf0Value::Number(5.0)));
1921        assert_eq!(obj.map.get("b"), Some(&Amf0Value::Number(2.0)));
1922        assert_eq!(obj.map.get("c"), Some(&Amf0Value::Number(3.0)));
1923    }
1924
1925    #[cfg(feature = "preserve_order")]
1926    #[test]
1927    fn test_extend_preserve_order_inserts_and_overwrites() {
1928        let mut obj = Amf0Object::new();
1929
1930        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1931
1932        let items = vec![
1933            (StringCow::from("a"), Amf0Value::Number(5.0)),
1934            (StringCow::from("b"), Amf0Value::Number(2.0)),
1935            (StringCow::from("a"), Amf0Value::Number(7.0)),
1936            (StringCow::from("c"), Amf0Value::Number(3.0)),
1937        ];
1938
1939        obj.extend(items);
1940
1941        let keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
1942        assert_eq!(
1943            keys,
1944            vec!["a", "b", "c"],
1945            "Preserve_order: key 'a' remains at front, then 'b', then 'c'"
1946        );
1947
1948        assert_eq!(obj.map.get("a"), Some(&Amf0Value::Number(7.0)));
1949        assert_eq!(obj.map.get("b"), Some(&Amf0Value::Number(2.0)));
1950        assert_eq!(obj.map.get("c"), Some(&Amf0Value::Number(3.0)));
1951    }
1952
1953    #[cfg(not(feature = "preserve_order"))]
1954    #[test]
1955    fn test_keys_iterator_next_back_and_len_non_preserve_order() {
1956        let mut obj = Amf0Object::new();
1957
1958        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1959        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1960        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1961
1962        let mut keys_iter = obj.keys();
1963
1964        assert_eq!(keys_iter.len(), 3);
1965
1966        let last = keys_iter.next_back().expect("Expected a last key");
1967        assert_eq!(last.as_ref(), "c");
1968
1969        assert_eq!(keys_iter.len(), 2);
1970
1971        let first = keys_iter.next().expect("Expected a first key");
1972        assert_eq!(first.as_ref(), "a");
1973
1974        assert_eq!(keys_iter.len(), 1);
1975    }
1976
1977    #[cfg(feature = "preserve_order")]
1978    #[test]
1979    fn test_keys_iterator_next_back_and_len_preserve_order() {
1980        let mut obj = Amf0Object::new();
1981
1982        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
1983        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
1984        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
1985
1986        let mut keys_iter = obj.keys();
1987
1988        assert_eq!(keys_iter.len(), 3);
1989
1990        let last = keys_iter.next_back().expect("Expected a last key");
1991        assert_eq!(last.as_ref(), "c");
1992
1993        assert_eq!(keys_iter.len(), 2);
1994
1995        let first = keys_iter.next().expect("Expected a first key");
1996        assert_eq!(first.as_ref(), "b");
1997        assert_eq!(keys_iter.len(), 1);
1998    }
1999
2000    #[cfg(feature = "serde")]
2001    #[test]
2002    fn test_into_deserializer_returns_self() {
2003        use serde::de::IntoDeserializer;
2004
2005        use crate::Amf0Error;
2006
2007        let obj = Amf0Object::new();
2008
2009        let deser: &Amf0Object = <&Amf0Object as IntoDeserializer<Amf0Error>>::into_deserializer(&obj);
2010        assert!(
2011            std::ptr::eq(deser, &obj),
2012            "into_deserializer should return the exact same &Amf0Object reference"
2013        );
2014    }
2015
2016    #[cfg(feature = "serde")]
2017    #[test]
2018    fn test_into_deserializer_as_deserializer_errors_on_primitive() {
2019        use serde::Deserialize;
2020        use serde::de::IntoDeserializer;
2021
2022        let obj = Amf0Object::new();
2023        let deser = obj.into_deserializer();
2024
2025        let result = <bool as Deserialize>::deserialize(&deser);
2026        assert!(result.is_err(), "Deserializing a bool from an Amf0Object should error");
2027    }
2028
2029    #[derive(Debug, Deserialize, PartialEq)]
2030    struct TestObject {
2031        string: String,
2032        number: u32,
2033    }
2034
2035    #[cfg(feature = "serde")]
2036    #[test]
2037    fn test_deserialize_any_for_struct() {
2038        let mut obj = Amf0Object::new();
2039        obj.map
2040            .insert(StringCow::from("string"), Amf0Value::String(StringCow::from("apple")));
2041        obj.map.insert(StringCow::from("number"), Amf0Value::Number(30.0));
2042
2043        let testobj: TestObject = Deserialize::deserialize(&obj).unwrap();
2044        assert_eq!(
2045            testobj,
2046            TestObject {
2047                string: "apple".into(),
2048                number: 30,
2049            }
2050        );
2051    }
2052
2053    #[cfg(feature = "serde")]
2054    #[test]
2055    fn test_deserialize_any_errors_on_missing_field() {
2056        let mut obj = Amf0Object::new();
2057        obj.map
2058            .insert(StringCow::from("string"), Amf0Value::String(StringCow::from("banana")));
2059
2060        let result: Result<TestObject, _> = Deserialize::deserialize(&obj);
2061        assert!(result.is_err(), "Missing required field should cause an error");
2062    }
2063
2064    #[test]
2065    fn test_entry_key_occupied() {
2066        let mut obj = Amf0Object::new();
2067        obj.map.insert(StringCow::from("serde"), Amf0Value::Number(42.0));
2068        let entry = obj.entry("serde");
2069
2070        assert_eq!(entry.key(), &StringCow::from("serde"));
2071    }
2072
2073    #[test]
2074    fn test_or_insert_vacant_and_occupied() {
2075        let mut obj = Amf0Object::new();
2076
2077        let v = obj.entry("k").or_insert(Amf0Value::Number(10.0));
2078        assert_eq!(*v, Amf0Value::Number(10.0));
2079        assert_eq!(
2080            obj.map.get("k"),
2081            Some(&Amf0Value::Number(10.0)),
2082            "Value should be inserted for vacant entry"
2083        );
2084
2085        let v2 = obj.entry("k").or_insert(Amf0Value::Number(20.0));
2086        assert_eq!(*v2, Amf0Value::Number(10.0));
2087
2088        *v2 = Amf0Value::Number(30.0);
2089        assert_eq!(
2090            obj.map.get("k"),
2091            Some(&Amf0Value::Number(30.0)),
2092            "Value should be updated to 30.0 via the occupied branch"
2093        );
2094    }
2095
2096    #[test]
2097    fn test_or_insert_with_vacant_and_occupied() {
2098        use std::cell::Cell;
2099
2100        let mut obj = Amf0Object::new();
2101
2102        let called = Cell::new(false);
2103        let default_closure = || {
2104            called.set(true);
2105            Amf0Value::Number(5.0)
2106        };
2107
2108        let v = obj.entry("key1").or_insert_with(default_closure);
2109        assert!(called.get(), "Closure should have been called for vacant entry");
2110        assert_eq!(*v, Amf0Value::Number(5.0));
2111        assert_eq!(
2112            obj.map.get("key1"),
2113            Some(&Amf0Value::Number(5.0)),
2114            "Value for 'key1' should be inserted as 5.0"
2115        );
2116
2117        called.set(false);
2118        let v2 = obj.entry("key1").or_insert_with(|| {
2119            called.set(true);
2120            Amf0Value::Number(10.0)
2121        });
2122        assert!(!called.get(), "Closure should not be called for occupied entry");
2123        assert_eq!(*v2, Amf0Value::Number(5.0));
2124
2125        *v2 = Amf0Value::Number(7.0);
2126        assert_eq!(
2127            obj.map.get("key1"),
2128            Some(&Amf0Value::Number(7.0)),
2129            "Value for 'key1' should be updated to 7.0 via occupied branch"
2130        );
2131    }
2132
2133    #[test]
2134    fn test_and_modify_on_occupied_entry() {
2135        let mut obj = Amf0Object::new();
2136        obj.map.insert(StringCow::from("key1"), Amf0Value::Number(1.0));
2137
2138        obj.entry("key1").and_modify(|v| {
2139            if let Amf0Value::Number(n) = v {
2140                *n = 5.0;
2141            }
2142        });
2143
2144        assert_eq!(
2145            obj.map.get("key1"),
2146            Some(&Amf0Value::Number(5.0)),
2147            "and_modify should change the existing value from 1.0 to 5.0"
2148        );
2149    }
2150
2151    #[test]
2152    fn test_and_modify_on_vacant_entry() {
2153        let mut obj = Amf0Object::new();
2154        assert!(!obj.map.contains_key("missing"));
2155
2156        obj.entry("missing").and_modify(|v| {
2157            if let Amf0Value::Number(n) = v {
2158                *n = 100.0;
2159            }
2160        });
2161
2162        assert!(
2163            !obj.map.contains_key("missing"),
2164            "and_modify on a vacant entry should not insert anything"
2165        );
2166    }
2167
2168    #[test]
2169    fn test_occupied_entry_key_and_get() {
2170        let mut obj = Amf0Object::new();
2171
2172        obj.map.insert(StringCow::from("my_key"), Amf0Value::Number(123.0));
2173
2174        match obj.entry("my_key") {
2175            Entry::Occupied(occupied) => {
2176                let key_ref: &StringCow = occupied.key();
2177                assert_eq!(key_ref.as_ref(), "my_key");
2178
2179                let value_ref: &Amf0Value = occupied.get();
2180                assert_eq!(value_ref, &Amf0Value::Number(123.0));
2181            }
2182            Entry::Vacant(_) => panic!("Expected Occupied variant for an existing key"),
2183        }
2184    }
2185
2186    #[test]
2187    fn test_occupied_entry_into_mut_and_insert() {
2188        let mut obj = Amf0Object::new();
2189
2190        obj.map.insert(StringCow::from("key1"), Amf0Value::Number(10.0));
2191
2192        if let Entry::Occupied(occ) = obj.entry("key1") {
2193            let value_ref: &mut Amf0Value = occ.into_mut();
2194            if let Amf0Value::Number(n) = value_ref {
2195                *n = 20.0;
2196            }
2197        } else {
2198            panic!("Expected Occupied variant");
2199        }
2200
2201        assert_eq!(
2202            obj.map.get("key1"),
2203            Some(&Amf0Value::Number(20.0)),
2204            "into_mut should allow modifying the existing value"
2205        );
2206
2207        if let Entry::Occupied(mut occ2) = obj.entry("key1") {
2208            let old = occ2.insert(Amf0Value::Number(30.0));
2209            assert_eq!(old, Amf0Value::Number(20.0), "insert should return the old value");
2210        } else {
2211            panic!("Expected Occupied variant for insert test");
2212        }
2213
2214        assert_eq!(
2215            obj.map.get("key1"),
2216            Some(&Amf0Value::Number(30.0)),
2217            "insert should replace with the new value"
2218        );
2219    }
2220
2221    #[cfg(not(feature = "preserve_order"))]
2222    #[test]
2223    fn test_occupied_entry_remove_non_preserve_order() {
2224        let mut obj = Amf0Object::new();
2225
2226        obj.map.insert(StringCow::from("key1"), Amf0Value::Number(1.0));
2227
2228        if let Entry::Occupied(occ) = obj.entry("key1") {
2229            let removed_value = occ.remove();
2230            assert_eq!(removed_value, Amf0Value::Number(1.0), "remove should return the old value");
2231        } else {
2232            panic!("Expected Occupied variant");
2233        }
2234
2235        assert!(!obj.map.contains_key("key1"), "Key should be removed after calling remove()");
2236    }
2237
2238    #[cfg(feature = "preserve_order")]
2239    #[test]
2240    fn test_occupied_entry_remove_preserve_order() {
2241        let mut obj = Amf0Object::new();
2242
2243        obj.map.insert(StringCow::from("a"), Amf0Value::Number(10.0));
2244        obj.map.insert(StringCow::from("b"), Amf0Value::Number(20.0));
2245        obj.map.insert(StringCow::from("c"), Amf0Value::Number(30.0));
2246
2247        if let Entry::Occupied(occ) = obj.entry("b") {
2248            let removed_value = occ.remove();
2249            assert_eq!(removed_value, Amf0Value::Number(20.0), "remove should return the old value");
2250        } else {
2251            panic!("Expected Occupied variant");
2252        }
2253
2254        let keys_after: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
2255        assert_eq!(
2256            keys_after,
2257            vec!["a", "c"],
2258            "After remove, key 'b' should be gone and 'c' should occupy its position"
2259        );
2260        assert!(!obj.map.contains_key("b"), "Key 'b' should be removed");
2261    }
2262
2263    #[cfg(feature = "preserve_order")]
2264    #[test]
2265    fn test_occupied_entry_swap_remove_preserve_order() {
2266        let mut obj = Amf0Object::new();
2267
2268        obj.map.insert(StringCow::from("x"), Amf0Value::Number(1.0));
2269        obj.map.insert(StringCow::from("y"), Amf0Value::Number(2.0));
2270        obj.map.insert(StringCow::from("z"), Amf0Value::Number(3.0));
2271
2272        if let Entry::Occupied(occ) = obj.entry("y") {
2273            let removed = occ.swap_remove();
2274            assert_eq!(
2275                removed,
2276                Amf0Value::Number(2.0),
2277                "swap_remove should return the old value for 'y'"
2278            );
2279        } else {
2280            panic!("Expected Occupied variant for key 'y'");
2281        }
2282
2283        let keys_after: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
2284        assert_eq!(
2285            keys_after,
2286            vec!["x", "z"],
2287            "After swap_remove, 'y' should be gone and 'z' should occupy its slot"
2288        );
2289        assert!(!obj.map.contains_key("y"), "Key 'y' should be removed");
2290        assert!(obj.map.contains_key("z"), "Key 'z' should still be present");
2291    }
2292
2293    #[cfg(feature = "preserve_order")]
2294    #[test]
2295    fn test_occupied_entry_shift_remove_preserve_order() {
2296        let mut obj = Amf0Object::new();
2297
2298        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
2299        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
2300        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
2301        obj.map.insert(StringCow::from("d"), Amf0Value::Number(4.0));
2302
2303        if let Entry::Occupied(occ) = obj.entry("b") {
2304            let removed = occ.shift_remove();
2305            assert_eq!(
2306                removed,
2307                Amf0Value::Number(2.0),
2308                "shift_remove should return the old value for 'b'"
2309            );
2310        } else {
2311            panic!("Expected Occupied variant for key 'b'");
2312        }
2313
2314        let keys_after: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
2315        assert_eq!(
2316            keys_after,
2317            vec!["a", "c", "d"],
2318            "After shift_remove, 'b' should be gone and order should be [\"a\", \"c\", \"d\"]"
2319        );
2320        assert!(!obj.map.contains_key("b"), "Key 'b' should have been removed");
2321        assert!(obj.map.contains_key("c"), "Key 'c' should still be present");
2322        assert!(obj.map.contains_key("d"), "Key 'd' should still be present");
2323    }
2324
2325    #[cfg(not(feature = "preserve_order"))]
2326    #[test]
2327    fn test_occupied_entry_remove_entry_non_preserve_order() {
2328        let mut obj = Amf0Object::new();
2329
2330        obj.map.insert(StringCow::from("key1"), Amf0Value::Number(10.0));
2331
2332        if let Entry::Occupied(occ) = obj.entry("key1") {
2333            let (removed_key, removed_value) = occ.remove_entry();
2334            assert_eq!(removed_key, StringCow::from("key1"));
2335            assert_eq!(removed_value, Amf0Value::Number(10.0));
2336        } else {
2337            panic!("Expected Occupied variant for 'key1'");
2338        }
2339
2340        assert!(!obj.map.contains_key("key1"));
2341    }
2342
2343    #[cfg(feature = "preserve_order")]
2344    #[test]
2345    fn test_occupied_entry_remove_entry_preserve_order() {
2346        let mut obj = Amf0Object::new();
2347
2348        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
2349        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
2350        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
2351
2352        if let Entry::Occupied(occ) = obj.entry("b") {
2353            let (removed_key, removed_value) = occ.remove_entry();
2354            assert_eq!(removed_key, StringCow::from("b"));
2355            assert_eq!(removed_value, Amf0Value::Number(2.0));
2356        } else {
2357            panic!("Expected Occupied variant for 'b'");
2358        }
2359
2360        let remaining_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
2361        assert_eq!(
2362            remaining_keys,
2363            vec!["a", "c"],
2364            "After remove_entry on 'b', keys should be [\"a\", \"c\"]"
2365        );
2366        assert!(!obj.map.contains_key("b"), "Key 'b' should be gone");
2367        assert!(obj.map.contains_key("c"), "Key 'c' should still be present");
2368    }
2369
2370    #[cfg(feature = "preserve_order")]
2371    #[test]
2372    fn test_swap_remove_entry_preserve_order_occupied_entry() {
2373        let mut obj = Amf0Object::new();
2374
2375        // Insert multiple entries in insertion order: ["a", "b", "c", "d"]
2376        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
2377        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
2378        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
2379        obj.map.insert(StringCow::from("d"), Amf0Value::Number(4.0));
2380
2381        // Remove "b" via OccupiedEntry::swap_remove_entry()
2382        if let Entry::Occupied(occ) = obj.entry("b") {
2383            let (removed_key, removed_value) = occ.swap_remove_entry();
2384            assert_eq!(removed_key, StringCow::from("b"));
2385            assert_eq!(removed_value, Amf0Value::Number(2.0));
2386        } else {
2387            panic!("Expected Occupied variant for key 'b'");
2388        }
2389
2390        // After swap_remove_entry, "d" should replace "b"'s position; remaining keys: ["a", "d", "c"]
2391        let remaining_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
2392        assert_eq!(
2393            remaining_keys,
2394            vec!["a", "d", "c"],
2395            "After swap_remove_entry on 'b', keys should be [\"a\", \"d\", \"c\"]"
2396        );
2397        assert!(!obj.map.contains_key("b"), "Key 'b' should have been removed");
2398        assert!(obj.map.contains_key("d"), "Key 'd' should still be present");
2399        assert!(obj.map.contains_key("c"), "Key 'c' should still be present");
2400    }
2401
2402    #[test]
2403    #[cfg(feature = "preserve_order")]
2404    fn test_occupied_entry_shift_remove_entry_preserve_order() {
2405        let mut obj = Amf0Object::new();
2406
2407        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
2408        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
2409        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
2410        obj.map.insert(StringCow::from("d"), Amf0Value::Number(4.0));
2411
2412        if let Entry::Occupied(occ) = obj.entry("b") {
2413            let (removed_key, removed_value) = occ.shift_remove_entry();
2414            assert_eq!(
2415                removed_key,
2416                StringCow::from("b"),
2417                "shift_remove_entry should return the removed key 'b'"
2418            );
2419            assert_eq!(
2420                removed_value,
2421                Amf0Value::Number(2.0),
2422                "shift_remove_entry should return the correct value for 'b'"
2423            );
2424        } else {
2425            panic!("Expected Occupied variant for key 'b'");
2426        }
2427
2428        let remaining_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect();
2429        assert_eq!(
2430            remaining_keys,
2431            vec!["a", "c", "d"],
2432            "After shift_remove_entry on 'b', keys should be [\"a\", \"c\", \"d\"]"
2433        );
2434        assert!(!obj.map.contains_key("b"), "Key 'b' should have been removed");
2435        assert!(obj.map.contains_key("c"), "Key 'c' should still be present");
2436        assert!(obj.map.contains_key("d"), "Key 'd' should still be present");
2437    }
2438
2439    #[test]
2440    fn test_into_iterator_mutates_values_non_preserve_order() {
2441        let mut obj = Amf0Object::new();
2442
2443        obj.map.insert(StringCow::from("b"), Amf0Value::Number(2.0));
2444        obj.map.insert(StringCow::from("a"), Amf0Value::Number(1.0));
2445        obj.map.insert(StringCow::from("c"), Amf0Value::Number(3.0));
2446
2447        for (_, value) in &mut obj {
2448            if let Amf0Value::Number(n) = value {
2449                *n += 10.0;
2450            }
2451        }
2452
2453        assert_eq!(obj.map.get("a"), Some(&Amf0Value::Number(11.0)));
2454        assert_eq!(obj.map.get("b"), Some(&Amf0Value::Number(12.0)));
2455        assert_eq!(obj.map.get("c"), Some(&Amf0Value::Number(13.0)));
2456    }
2457
2458    #[test]
2459    #[cfg(feature = "preserve_order")]
2460    fn test_into_iterator_preserve_order_counts_and_mutates() {
2461        let mut obj = Amf0Object::new();
2462
2463        obj.map.insert(StringCow::from("x"), Amf0Value::Number(5.0));
2464        obj.map.insert(StringCow::from("y"), Amf0Value::Number(6.0));
2465        obj.map.insert(StringCow::from("z"), Amf0Value::Number(7.0));
2466
2467        let mut seen_keys = Vec::new();
2468        for (key, value) in &mut obj {
2469            seen_keys.push(key.as_ref().to_string());
2470            *value = Amf0Value::Number(0.0);
2471        }
2472
2473        assert_eq!(seen_keys, vec!["x", "y", "z"]);
2474        assert_eq!(obj.map.get("x"), Some(&Amf0Value::Number(0.0)));
2475        assert_eq!(obj.map.get("y"), Some(&Amf0Value::Number(0.0)));
2476        assert_eq!(obj.map.get("z"), Some(&Amf0Value::Number(0.0)));
2477    }
2478}