Skip to main content

noyalib/value/
mapping.rs

1//! YAML mapping types (`Mapping`, `MappingAny`).
2
3// SPDX-License-Identifier: MIT OR Apache-2.0
4// Copyright (c) 2026 Noyalib. All rights reserved.
5
6use super::Value;
7use crate::prelude::FxBuildHasher;
8use crate::prelude::IndexMap;
9use crate::prelude::*;
10use core::cmp::Ordering;
11use core::hash::{Hash, Hasher};
12use core::ops::{Index, IndexMut};
13use indexmap::map::{IntoIter, Iter, IterMut, Keys, Values, ValuesMut};
14
15/// Fast IndexMap using FxBuildHasher.
16type FxIndexMap<K, V> = IndexMap<K, V, FxBuildHasher>;
17
18/// Hosted builds use a randomized hasher for mappings populated from
19/// untrusted YAML. Bare-metal builds retain the deterministic Fx hasher
20/// because `RandomState` requires the standard library.
21#[cfg(feature = "std")]
22type ValueIndexMap<K, V> = IndexMap<K, V>;
23#[cfg(not(feature = "std"))]
24type ValueIndexMap<K, V> = FxIndexMap<K, V>;
25
26/// A YAML mapping (dictionary/object).
27///
28/// This is an ordered map that preserves insertion order, wrapping
29/// `IndexMap<String, Value>`. It provides a comprehensive API for working with
30/// YAML mappings.
31///
32/// # Examples
33///
34/// ```rust
35/// use noyalib::{Mapping, Value};
36///
37/// let mut map = Mapping::new();
38/// map.insert("name", Value::from("test"));
39/// map.insert("value", Value::from(42));
40///
41/// assert_eq!(map.len(), 2);
42/// assert_eq!(map.get("name").unwrap().as_str(), Some("test"));
43/// ```
44#[derive(Debug, Clone, PartialEq, Eq, Default)]
45pub struct Mapping(ValueIndexMap<String, Value>);
46
47impl Mapping {
48    /// Creates an empty mapping.
49    ///
50    /// # Examples
51    ///
52    /// ```
53    /// use noyalib::Mapping;
54    /// let m = Mapping::new();
55    /// assert!(m.is_empty());
56    /// ```
57    #[must_use]
58    pub fn new() -> Self {
59        Self(ValueIndexMap::default())
60    }
61
62    /// Creates an empty mapping with the specified capacity.
63    ///
64    /// Pre-allocates room for `capacity` entries to avoid
65    /// rehashing during the first inserts.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// use noyalib::Mapping;
71    /// let m = Mapping::with_capacity(16);
72    /// assert!(m.capacity() >= 16);
73    /// ```
74    #[must_use]
75    pub fn with_capacity(capacity: usize) -> Self {
76        #[cfg(feature = "std")]
77        {
78            Self(ValueIndexMap::with_capacity(capacity))
79        }
80        #[cfg(not(feature = "std"))]
81        {
82            Self(ValueIndexMap::with_capacity_and_hasher(
83                capacity,
84                FxBuildHasher,
85            ))
86        }
87    }
88
89    /// Returns the number of key-value pairs the mapping can hold without
90    /// reallocating.
91    ///
92    /// # Examples
93    ///
94    /// ```
95    /// use noyalib::Mapping;
96    /// let m = Mapping::with_capacity(8);
97    /// assert!(m.capacity() >= 8);
98    /// ```
99    #[must_use]
100    pub fn capacity(&self) -> usize {
101        self.0.capacity()
102    }
103
104    /// Reserves capacity for at least `additional` more key-value pairs.
105    ///
106    /// # Examples
107    ///
108    /// ```
109    /// use noyalib::Mapping;
110    /// let mut m = Mapping::new();
111    /// m.reserve(64);
112    /// assert!(m.capacity() >= 64);
113    /// ```
114    pub fn reserve(&mut self, additional: usize) {
115        self.0.reserve(additional);
116    }
117
118    /// Shrinks the capacity of the mapping as much as possible.
119    ///
120    /// # Examples
121    ///
122    /// ```
123    /// use noyalib::Mapping;
124    /// let mut m = Mapping::with_capacity(64);
125    /// m.shrink_to_fit();
126    /// // capacity may now be 0 or any small implementation-defined value.
127    /// ```
128    pub fn shrink_to_fit(&mut self) {
129        self.0.shrink_to_fit();
130    }
131
132    /// Returns the number of key-value pairs in the mapping.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// use noyalib::{Mapping, Value};
138    /// let mut m = Mapping::new();
139    /// m.insert("a", Value::from(1_i64));
140    /// assert_eq!(m.len(), 1);
141    /// ```
142    #[must_use]
143    pub fn len(&self) -> usize {
144        self.0.len()
145    }
146
147    /// Returns `true` if the mapping contains no key-value pairs.
148    ///
149    /// # Examples
150    ///
151    /// ```
152    /// use noyalib::Mapping;
153    /// assert!(Mapping::new().is_empty());
154    /// ```
155    #[must_use]
156    pub fn is_empty(&self) -> bool {
157        self.0.is_empty()
158    }
159
160    /// Clears the mapping, removing all key-value pairs.
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// use noyalib::{Mapping, Value};
166    /// let mut m = Mapping::new();
167    /// m.insert("a", Value::from(1_i64));
168    /// m.clear();
169    /// assert!(m.is_empty());
170    /// ```
171    pub fn clear(&mut self) {
172        self.0.clear();
173    }
174
175    /// Inserts a key-value pair into the mapping.
176    ///
177    /// If the mapping already had this key present, the value is updated,
178    /// and the old value is returned.
179    ///
180    /// # Examples
181    ///
182    /// ```
183    /// use noyalib::{Mapping, Value};
184    /// let mut m = Mapping::new();
185    /// assert_eq!(m.insert("a", Value::from(1_i64)), None);
186    /// assert_eq!(m.insert("a", Value::from(2_i64)).and_then(|v| v.as_i64()), Some(1));
187    /// ```
188    pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
189        self.0.insert(key.into(), value)
190    }
191
192    /// Returns `true` if the mapping contains the specified key.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use noyalib::{Mapping, Value};
198    /// let mut m = Mapping::new();
199    /// m.insert("a", Value::from(1_i64));
200    /// assert!(m.contains_key("a"));
201    /// assert!(!m.contains_key("b"));
202    /// ```
203    #[must_use]
204    pub fn contains_key(&self, key: &str) -> bool {
205        self.0.contains_key(key)
206    }
207
208    /// Returns a reference to the value corresponding to the key.
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// use noyalib::{Mapping, Value};
214    /// let mut m = Mapping::new();
215    /// m.insert("a", Value::from(1_i64));
216    /// assert_eq!(m.get("a").and_then(Value::as_i64), Some(1));
217    /// assert!(m.get("b").is_none());
218    /// ```
219    #[must_use]
220    pub fn get(&self, key: &str) -> Option<&Value> {
221        self.0.get(key)
222    }
223
224    /// Returns a mutable reference to the value corresponding to the key.
225    ///
226    /// # Examples
227    ///
228    /// ```
229    /// use noyalib::{Mapping, Value};
230    /// let mut m = Mapping::new();
231    /// m.insert("a", Value::from(1_i64));
232    /// if let Some(v) = m.get_mut("a") {
233    ///     *v = Value::from(2_i64);
234    /// }
235    /// assert_eq!(m.get("a").and_then(Value::as_i64), Some(2));
236    /// ```
237    #[must_use]
238    pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
239        self.0.get_mut(key)
240    }
241
242    /// Returns a reference to the key-value pair at the given index.
243    ///
244    /// Indexing follows insertion order (this is an `IndexMap`).
245    ///
246    /// # Examples
247    ///
248    /// ```
249    /// use noyalib::{Mapping, Value};
250    /// let mut m = Mapping::new();
251    /// m.insert("first", Value::from(1_i64));
252    /// m.insert("second", Value::from(2_i64));
253    /// assert_eq!(m.get_index(0).map(|(k, _)| k.as_str()), Some("first"));
254    /// ```
255    #[must_use]
256    pub fn get_index(&self, index: usize) -> Option<(&String, &Value)> {
257        self.0.get_index(index)
258    }
259
260    /// Returns a mutable reference to the key-value pair at the given index.
261    ///
262    /// # Examples
263    ///
264    /// ```
265    /// use noyalib::{Mapping, Value};
266    /// let mut m = Mapping::new();
267    /// m.insert("a", Value::from(1_i64));
268    /// if let Some((_, v)) = m.get_index_mut(0) {
269    ///     *v = Value::from(99_i64);
270    /// }
271    /// assert_eq!(m.get("a").and_then(Value::as_i64), Some(99));
272    /// ```
273    #[must_use]
274    pub fn get_index_mut(&mut self, index: usize) -> Option<(&String, &mut Value)> {
275        self.0.get_index_mut(index)
276    }
277
278    /// Returns the index of the given key, if present.
279    ///
280    /// Indexing follows insertion order (this is an `IndexMap`); a key
281    /// keeps its original index when its value is overwritten by a
282    /// later [`Mapping::insert`].
283    ///
284    /// # Examples
285    ///
286    /// ```
287    /// use noyalib::{Mapping, Value};
288    /// let mut m = Mapping::new();
289    /// m.insert("first", Value::from(1_i64));
290    /// m.insert("second", Value::from(2_i64));
291    /// assert_eq!(m.get_index_of("second"), Some(1));
292    /// assert_eq!(m.get_index_of("absent"), None);
293    /// ```
294    #[must_use]
295    pub fn get_index_of(&self, key: &str) -> Option<usize> {
296        self.0.get_index_of(key)
297    }
298
299    /// Removes a key from the mapping, returning the value if the key was
300    /// present.
301    ///
302    /// This operation preserves the order of remaining elements
303    /// (uses `shift_remove` semantics, `O(n)`). For order-agnostic
304    /// `O(1)` removal, see [`Mapping::swap_remove`].
305    ///
306    /// # Examples
307    ///
308    /// ```
309    /// use noyalib::{Mapping, Value};
310    /// let mut m = Mapping::new();
311    /// m.insert("a", Value::from(1_i64));
312    /// assert_eq!(m.remove("a").and_then(|v| v.as_i64()), Some(1));
313    /// assert!(m.remove("a").is_none());
314    /// ```
315    pub fn remove(&mut self, key: &str) -> Option<Value> {
316        self.0.shift_remove(key)
317    }
318
319    /// Removes a key from the mapping, returning the key-value pair if present.
320    ///
321    /// This operation preserves the order of remaining elements.
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// use noyalib::{Mapping, Value};
327    /// let mut m = Mapping::new();
328    /// m.insert("a", Value::from(1_i64));
329    /// let (k, v) = m.remove_entry("a").unwrap();
330    /// assert_eq!(k, "a");
331    /// assert_eq!(v.as_i64(), Some(1));
332    /// ```
333    pub fn remove_entry(&mut self, key: &str) -> Option<(String, Value)> {
334        self.0.shift_remove_entry(key)
335    }
336
337    /// Removes a key by swapping it with the last element.
338    ///
339    /// This is `O(1)` but does not preserve order. For
340    /// order-preserving removal, see [`Mapping::remove`] or
341    /// [`Mapping::shift_remove`].
342    ///
343    /// # Examples
344    ///
345    /// ```
346    /// use noyalib::{Mapping, Value};
347    /// let mut m = Mapping::new();
348    /// m.insert("a", Value::from(1_i64));
349    /// m.insert("b", Value::from(2_i64));
350    /// m.insert("c", Value::from(3_i64));
351    /// m.swap_remove("a");
352    /// // Order is no longer guaranteed; "c" might now sit where "a" was.
353    /// assert_eq!(m.len(), 2);
354    /// ```
355    pub fn swap_remove(&mut self, key: &str) -> Option<Value> {
356        self.0.swap_remove(key)
357    }
358
359    /// Removes a key by shifting all elements after it.
360    ///
361    /// This preserves order but is `O(n)`. Equivalent to
362    /// [`Mapping::remove`].
363    ///
364    /// # Examples
365    ///
366    /// ```
367    /// use noyalib::{Mapping, Value};
368    /// let mut m = Mapping::new();
369    /// m.insert("a", Value::from(1_i64));
370    /// m.insert("b", Value::from(2_i64));
371    /// m.shift_remove("a");
372    /// assert_eq!(m.iter().next().map(|(k, _)| k.as_str()), Some("b"));
373    /// ```
374    pub fn shift_remove(&mut self, key: &str) -> Option<Value> {
375        self.0.shift_remove(key)
376    }
377
378    /// Gets the entry for the given key for in-place manipulation.
379    ///
380    /// # Examples
381    ///
382    /// ```
383    /// use noyalib::{Mapping, Value};
384    /// let mut m = Mapping::new();
385    /// m.entry("counter").or_insert(Value::from(0_i64));
386    /// if let Some(Value::Number(n)) = m.get_mut("counter") {
387    ///     if let Some(c) = n.as_i64() { *n = noyalib::Number::Integer(c + 1); }
388    /// }
389    /// assert_eq!(m.get("counter").and_then(Value::as_i64), Some(1));
390    /// ```
391    pub fn entry(&mut self, key: impl Into<String>) -> indexmap::map::Entry<'_, String, Value> {
392        self.0.entry(key.into())
393    }
394
395    /// Retains only the key-value pairs specified by the predicate.
396    ///
397    /// # Examples
398    ///
399    /// ```
400    /// use noyalib::{Mapping, Value};
401    /// let mut m = Mapping::new();
402    /// m.insert("a", Value::from(1_i64));
403    /// m.insert("b", Value::from(2_i64));
404    /// m.insert("c", Value::from(3_i64));
405    /// m.retain(|_k, v| v.as_i64().unwrap_or(0) >= 2);
406    /// assert_eq!(m.len(), 2);
407    /// assert!(!m.contains_key("a"));
408    /// ```
409    pub fn retain<F>(&mut self, f: F)
410    where
411        F: FnMut(&String, &mut Value) -> bool,
412    {
413        self.0.retain(f);
414    }
415
416    /// Returns an iterator over the key-value pairs in insertion order.
417    ///
418    /// # Examples
419    ///
420    /// ```
421    /// use noyalib::{Mapping, Value};
422    /// let mut m = Mapping::new();
423    /// m.insert("a", Value::from(1_i64));
424    /// m.insert("b", Value::from(2_i64));
425    /// let total: i64 = m.iter().filter_map(|(_, v)| v.as_i64()).sum();
426    /// assert_eq!(total, 3);
427    /// ```
428    #[must_use]
429    pub fn iter(&self) -> Iter<'_, String, Value> {
430        self.0.iter()
431    }
432
433    /// Returns a mutable iterator over the key-value pairs in insertion order.
434    ///
435    /// # Examples
436    ///
437    /// ```
438    /// use noyalib::{Mapping, Number, Value};
439    /// let mut m = Mapping::new();
440    /// m.insert("a", Value::from(1_i64));
441    /// for (_, v) in m.iter_mut() {
442    ///     if let Value::Number(Number::Integer(n)) = v { *n *= 2; }
443    /// }
444    /// assert_eq!(m.get("a").and_then(Value::as_i64), Some(2));
445    /// ```
446    pub fn iter_mut(&mut self) -> IterMut<'_, String, Value> {
447        self.0.iter_mut()
448    }
449
450    /// Returns an iterator over the keys in insertion order.
451    ///
452    /// # Examples
453    ///
454    /// ```
455    /// use noyalib::{Mapping, Value};
456    /// let mut m = Mapping::new();
457    /// m.insert("a", Value::from(1_i64));
458    /// m.insert("b", Value::from(2_i64));
459    /// let keys: Vec<&str> = m.keys().map(String::as_str).collect();
460    /// assert_eq!(keys, &["a", "b"]);
461    /// ```
462    #[must_use]
463    pub fn keys(&self) -> Keys<'_, String, Value> {
464        self.0.keys()
465    }
466
467    /// Returns an iterator over the values in insertion order.
468    ///
469    /// # Examples
470    ///
471    /// ```
472    /// use noyalib::{Mapping, Value};
473    /// let mut m = Mapping::new();
474    /// m.insert("a", Value::from(1_i64));
475    /// m.insert("b", Value::from(2_i64));
476    /// let sum: i64 = m.values().filter_map(Value::as_i64).sum();
477    /// assert_eq!(sum, 3);
478    /// ```
479    #[must_use]
480    pub fn values(&self) -> Values<'_, String, Value> {
481        self.0.values()
482    }
483
484    /// Returns a mutable iterator over the values in insertion order.
485    ///
486    /// # Examples
487    ///
488    /// ```
489    /// use noyalib::{Mapping, Number, Value};
490    /// let mut m = Mapping::new();
491    /// m.insert("a", Value::from(10_i64));
492    /// m.insert("b", Value::from(20_i64));
493    /// for v in m.values_mut() {
494    ///     if let Value::Number(Number::Integer(n)) = v { *n /= 10; }
495    /// }
496    /// assert_eq!(m.get("a").and_then(Value::as_i64), Some(1));
497    /// ```
498    pub fn values_mut(&mut self) -> ValuesMut<'_, String, Value> {
499        self.0.values_mut()
500    }
501
502    /// Returns the first key-value pair in insertion order.
503    ///
504    /// # Examples
505    ///
506    /// ```
507    /// use noyalib::{Mapping, Value};
508    /// let mut m = Mapping::new();
509    /// m.insert("a", Value::from(1_i64));
510    /// m.insert("b", Value::from(2_i64));
511    /// assert_eq!(m.first().map(|(k, _)| k.as_str()), Some("a"));
512    /// ```
513    #[must_use]
514    pub fn first(&self) -> Option<(&String, &Value)> {
515        self.0.first()
516    }
517
518    /// Returns a mutable reference to the first key-value pair.
519    ///
520    /// # Examples
521    ///
522    /// ```
523    /// use noyalib::{Mapping, Value};
524    /// let mut m = Mapping::new();
525    /// m.insert("a", Value::from(1_i64));
526    /// if let Some((_, v)) = m.first_mut() { *v = Value::from(99_i64); }
527    /// assert_eq!(m.get("a").and_then(Value::as_i64), Some(99));
528    /// ```
529    #[must_use]
530    pub fn first_mut(&mut self) -> Option<(&String, &mut Value)> {
531        self.0.first_mut()
532    }
533
534    /// Returns the last key-value pair in insertion order.
535    ///
536    /// # Examples
537    ///
538    /// ```
539    /// use noyalib::{Mapping, Value};
540    /// let mut m = Mapping::new();
541    /// m.insert("a", Value::from(1_i64));
542    /// m.insert("b", Value::from(2_i64));
543    /// assert_eq!(m.last().map(|(k, _)| k.as_str()), Some("b"));
544    /// ```
545    #[must_use]
546    pub fn last(&self) -> Option<(&String, &Value)> {
547        self.0.last()
548    }
549
550    /// Returns a mutable reference to the last key-value pair.
551    ///
552    /// # Examples
553    ///
554    /// ```
555    /// use noyalib::{Mapping, Value};
556    /// let mut m = Mapping::new();
557    /// m.insert("a", Value::from(1_i64));
558    /// m.insert("b", Value::from(2_i64));
559    /// if let Some((_, v)) = m.last_mut() { *v = Value::from(99_i64); }
560    /// assert_eq!(m.get("b").and_then(Value::as_i64), Some(99));
561    /// ```
562    #[must_use]
563    pub fn last_mut(&mut self) -> Option<(&String, &mut Value)> {
564        self.0.last_mut()
565    }
566
567    /// Removes and returns the first key-value pair.
568    ///
569    /// # Examples
570    ///
571    /// ```
572    /// use noyalib::{Mapping, Value};
573    /// let mut m = Mapping::new();
574    /// m.insert("a", Value::from(1_i64));
575    /// m.insert("b", Value::from(2_i64));
576    /// let (k, _) = m.pop_first().unwrap();
577    /// assert_eq!(k, "a");
578    /// assert_eq!(m.len(), 1);
579    /// ```
580    pub fn pop_first(&mut self) -> Option<(String, Value)> {
581        self.0.shift_remove_index(0)
582    }
583
584    /// Removes and returns the last key-value pair.
585    ///
586    /// # Examples
587    ///
588    /// ```
589    /// use noyalib::{Mapping, Value};
590    /// let mut m = Mapping::new();
591    /// m.insert("a", Value::from(1_i64));
592    /// m.insert("b", Value::from(2_i64));
593    /// let (k, _) = m.pop_last().unwrap();
594    /// assert_eq!(k, "b");
595    /// ```
596    pub fn pop_last(&mut self) -> Option<(String, Value)> {
597        self.0.pop()
598    }
599
600    /// Sorts the mapping by keys (lexicographic order).
601    ///
602    /// # Examples
603    ///
604    /// ```
605    /// use noyalib::{Mapping, Value};
606    /// let mut m = Mapping::new();
607    /// m.insert("c", Value::from(3_i64));
608    /// m.insert("a", Value::from(1_i64));
609    /// m.insert("b", Value::from(2_i64));
610    /// m.sort_keys();
611    /// let keys: Vec<&str> = m.keys().map(String::as_str).collect();
612    /// assert_eq!(keys, &["a", "b", "c"]);
613    /// ```
614    pub fn sort_keys(&mut self) {
615        self.0.sort_keys();
616    }
617
618    /// Reverses the order of key-value pairs.
619    ///
620    /// # Examples
621    ///
622    /// ```
623    /// use noyalib::{Mapping, Value};
624    /// let mut m = Mapping::new();
625    /// m.insert("a", Value::from(1_i64));
626    /// m.insert("b", Value::from(2_i64));
627    /// m.reverse();
628    /// assert_eq!(m.first().map(|(k, _)| k.as_str()), Some("b"));
629    /// ```
630    pub fn reverse(&mut self) {
631        self.0.reverse();
632    }
633
634    /// Extends the mapping with the contents of an iterator.
635    ///
636    /// # Examples
637    ///
638    /// ```
639    /// use noyalib::{Mapping, Value};
640    /// let mut m = Mapping::new();
641    /// m.extend([
642    ///     ("a".to_owned(), Value::from(1_i64)),
643    ///     ("b".to_owned(), Value::from(2_i64)),
644    /// ]);
645    /// assert_eq!(m.len(), 2);
646    /// ```
647    pub fn extend<I>(&mut self, iter: I)
648    where
649        I: IntoIterator<Item = (String, Value)>,
650    {
651        self.0.extend(iter);
652    }
653
654    /// Consumes the mapping and returns its contents as an `IndexMap`.
655    ///
656    /// # Examples
657    ///
658    /// ```
659    /// use noyalib::{Mapping, Value};
660    /// let mut m = Mapping::new();
661    /// m.insert("a", Value::from(1_i64));
662    /// let inner = m.into_inner();
663    /// assert_eq!(inner.len(), 1);
664    /// ```
665    #[must_use]
666    pub fn into_inner(self) -> IndexMap<String, Value> {
667        // Convert from FxIndexMap to standard IndexMap for public API stability
668        self.0.into_iter().collect()
669    }
670
671    /// Creates a mapping from an `IndexMap`.
672    ///
673    /// # Examples
674    ///
675    /// ```
676    /// use indexmap::IndexMap;
677    /// use noyalib::{Mapping, Value};
678    /// let mut src = IndexMap::new();
679    /// src.insert("a".to_owned(), Value::from(1_i64));
680    /// let m = Mapping::from_inner(src);
681    /// assert_eq!(m.get("a").and_then(Value::as_i64), Some(1));
682    /// ```
683    #[must_use]
684    pub fn from_inner(map: IndexMap<String, Value>) -> Self {
685        Self(map.into_iter().collect())
686    }
687}
688
689impl Index<&str> for Mapping {
690    type Output = Value;
691
692    /// Index into the mapping by key.
693    ///
694    /// # Panics
695    ///
696    /// Panics if the key is not present in the mapping.
697    #[track_caller]
698    fn index(&self, key: &str) -> &Self::Output {
699        self.0.get(key).expect("key not found in mapping")
700    }
701}
702
703impl IndexMut<&str> for Mapping {
704    /// Mutably index into the mapping by key.
705    ///
706    /// # Panics
707    ///
708    /// Panics if the key is not present in the mapping.
709    #[track_caller]
710    fn index_mut(&mut self, key: &str) -> &mut Self::Output {
711        self.0.get_mut(key).expect("key not found in mapping")
712    }
713}
714
715impl IntoIterator for Mapping {
716    type Item = (String, Value);
717    type IntoIter = IntoIter<String, Value>;
718
719    fn into_iter(self) -> Self::IntoIter {
720        self.0.into_iter()
721    }
722}
723
724impl<'a> IntoIterator for &'a Mapping {
725    type Item = (&'a String, &'a Value);
726    type IntoIter = Iter<'a, String, Value>;
727
728    fn into_iter(self) -> Self::IntoIter {
729        self.0.iter()
730    }
731}
732
733impl<'a> IntoIterator for &'a mut Mapping {
734    type Item = (&'a String, &'a mut Value);
735    type IntoIter = IterMut<'a, String, Value>;
736
737    fn into_iter(self) -> Self::IntoIter {
738        self.0.iter_mut()
739    }
740}
741
742impl FromIterator<(String, Value)> for Mapping {
743    fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
744        Self(ValueIndexMap::from_iter(iter))
745    }
746}
747
748impl<const N: usize> From<[(String, Value); N]> for Mapping {
749    fn from(arr: [(String, Value); N]) -> Self {
750        let mut map = Self::with_capacity(N);
751        for (k, v) in arr {
752            let _ = map.0.insert(k, v);
753        }
754        map
755    }
756}
757
758// See the note on the sibling impl: identical to the `FxIndexMap`
759// version once no_std defaults the hasher. #210.
760#[cfg(feature = "std")]
761impl From<IndexMap<String, Value>> for Mapping {
762    fn from(map: IndexMap<String, Value>) -> Self {
763        Self(map.into_iter().collect())
764    }
765}
766
767impl From<FxIndexMap<String, Value>> for Mapping {
768    fn from(map: FxIndexMap<String, Value>) -> Self {
769        Self(map.into_iter().collect())
770    }
771}
772
773// On no_std the prelude defaults `IndexMap`'s hasher to
774// `FxBuildHasher`, which makes this identical to the `FxIndexMap`
775// impl below. Gated so the two do not collide there. See #210.
776#[cfg(feature = "std")]
777impl From<Mapping> for IndexMap<String, Value> {
778    fn from(map: Mapping) -> Self {
779        map.0.into_iter().collect()
780    }
781}
782
783impl From<Mapping> for FxIndexMap<String, Value> {
784    fn from(map: Mapping) -> Self {
785        map.0.into_iter().collect()
786    }
787}
788
789impl From<Vec<(String, Value)>> for Mapping {
790    fn from(v: Vec<(String, Value)>) -> Self {
791        Self(v.into_iter().collect())
792    }
793}
794
795impl Hash for Mapping {
796    fn hash<H: Hasher>(&self, state: &mut H) {
797        self.0.len().hash(state);
798        for (k, v) in &self.0 {
799            k.hash(state);
800            v.hash(state);
801        }
802    }
803}
804
805impl PartialOrd for Mapping {
806    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
807        Some(self.cmp(other))
808    }
809}
810
811impl Ord for Mapping {
812    fn cmp(&self, other: &Self) -> Ordering {
813        self.len().cmp(&other.len()).then_with(|| {
814            for ((ak, av), (bk, bv)) in self.iter().zip(other.iter()) {
815                match ak.cmp(bk) {
816                    Ordering::Equal => {}
817                    ord => return ord,
818                }
819                match av.cmp(bv) {
820                    Ordering::Equal => continue,
821                    ord => return ord,
822                }
823            }
824            Ordering::Equal
825        })
826    }
827}
828
829impl fmt::Display for Mapping {
830    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
831        write!(f, "{{")?;
832        for (i, (k, v)) in self.iter().enumerate() {
833            if i > 0 {
834                write!(f, ", ")?;
835            }
836            write!(f, "{k}: {v}")?;
837        }
838        write!(f, "}}")
839    }
840}
841
842impl serde_core::Serialize for Mapping {
843    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
844    where
845        S: serde_core::Serializer,
846    {
847        use serde_core::ser::SerializeMap as _;
848        let mut map = serializer.serialize_map(Some(self.len()))?;
849        for (k, v) in self {
850            map.serialize_entry(k, v)?;
851        }
852        map.end()
853    }
854}
855
856impl<'de> serde_core::Deserialize<'de> for Mapping {
857    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
858    where
859        D: serde_core::Deserializer<'de>,
860    {
861        struct MappingVisitor;
862
863        impl<'de> serde_core::de::Visitor<'de> for MappingVisitor {
864            type Value = Mapping;
865
866            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
867                formatter.write_str("a YAML mapping")
868            }
869
870            fn visit_map<A>(self, mut map: A) -> Result<Mapping, A::Error>
871            where
872                A: serde_core::de::MapAccess<'de>,
873            {
874                let mut mapping = Mapping::with_capacity(map.size_hint().unwrap_or(0));
875                while let Some((key, value)) = map.next_entry::<String, Value>()? {
876                    let _ = mapping.insert(key, value);
877                }
878                Ok(mapping)
879            }
880        }
881
882        deserializer.deserialize_map(MappingVisitor)
883    }
884}
885
886/// A YAML mapping with `Value` keys.
887///
888/// Unlike [`Mapping`] which only supports `String` keys, `MappingAny` allows
889/// any [`Value`] as a key. This is useful for representing YAML mappings where
890/// keys might be numbers, booleans, or even nested structures.
891///
892/// # Examples
893///
894/// ```rust
895/// use noyalib::{MappingAny, Value};
896///
897/// let mut map = MappingAny::new();
898/// map.insert(Value::from(1), Value::from("one"));
899/// map.insert(Value::from("two"), Value::from(2));
900/// map.insert(Value::Bool(true), Value::from("yes"));
901///
902/// assert_eq!(map.len(), 3);
903/// assert_eq!(map.get(&Value::from(1)).unwrap().as_str(), Some("one"));
904/// ```
905///
906/// # YAML Example
907///
908/// This type can represent YAML like:
909///
910/// ```yaml
911/// 1: one
912/// "two": 2
913/// true: yes
914/// [1, 2]: nested key
915/// ```
916#[derive(Debug, Clone, PartialEq, Eq, Default)]
917pub struct MappingAny(ValueIndexMap<Value, Value>);
918
919impl MappingAny {
920    /// Creates an empty mapping.
921    #[must_use]
922    pub fn new() -> Self {
923        Self(ValueIndexMap::default())
924    }
925
926    /// Creates an empty mapping with the specified capacity.
927    #[must_use]
928    pub fn with_capacity(capacity: usize) -> Self {
929        #[cfg(feature = "std")]
930        {
931            Self(ValueIndexMap::with_capacity(capacity))
932        }
933        #[cfg(not(feature = "std"))]
934        {
935            Self(ValueIndexMap::with_capacity_and_hasher(
936                capacity,
937                FxBuildHasher,
938            ))
939        }
940    }
941
942    /// Returns the number of key-value pairs the mapping can hold without
943    /// reallocating.
944    #[must_use]
945    pub fn capacity(&self) -> usize {
946        self.0.capacity()
947    }
948
949    /// Reserves capacity for at least `additional` more key-value pairs.
950    pub fn reserve(&mut self, additional: usize) {
951        self.0.reserve(additional);
952    }
953
954    /// Shrinks the capacity of the mapping as much as possible.
955    pub fn shrink_to_fit(&mut self) {
956        self.0.shrink_to_fit();
957    }
958
959    /// Returns the number of key-value pairs in the mapping.
960    #[must_use]
961    pub fn len(&self) -> usize {
962        self.0.len()
963    }
964
965    /// Returns `true` if the mapping contains no key-value pairs.
966    #[must_use]
967    pub fn is_empty(&self) -> bool {
968        self.0.is_empty()
969    }
970
971    /// Clears the mapping, removing all key-value pairs.
972    pub fn clear(&mut self) {
973        self.0.clear();
974    }
975
976    /// Inserts a key-value pair into the mapping.
977    ///
978    /// If the mapping already had this key present, the value is updated,
979    /// and the old value is returned.
980    pub fn insert(&mut self, key: Value, value: Value) -> Option<Value> {
981        self.0.insert(key, value)
982    }
983
984    /// Returns `true` if the mapping contains the specified key.
985    #[must_use]
986    pub fn contains_key(&self, key: &Value) -> bool {
987        self.0.contains_key(key)
988    }
989
990    /// Returns a reference to the value corresponding to the key.
991    #[must_use]
992    pub fn get(&self, key: &Value) -> Option<&Value> {
993        self.0.get(key)
994    }
995
996    /// Returns a mutable reference to the value corresponding to the key.
997    #[must_use]
998    pub fn get_mut(&mut self, key: &Value) -> Option<&mut Value> {
999        self.0.get_mut(key)
1000    }
1001
1002    /// Returns a reference to the key-value pair at the given index.
1003    #[must_use]
1004    pub fn get_index(&self, index: usize) -> Option<(&Value, &Value)> {
1005        self.0.get_index(index)
1006    }
1007
1008    /// Returns a mutable reference to the key-value pair at the given index.
1009    #[must_use]
1010    pub fn get_index_mut(&mut self, index: usize) -> Option<(&Value, &mut Value)> {
1011        self.0.get_index_mut(index)
1012    }
1013
1014    /// Removes a key from the mapping, returning the value if the key was
1015    /// present.
1016    ///
1017    /// This operation preserves the order of remaining elements.
1018    pub fn remove(&mut self, key: &Value) -> Option<Value> {
1019        self.0.shift_remove(key)
1020    }
1021
1022    /// Removes a key from the mapping, returning the key-value pair if present.
1023    ///
1024    /// This operation preserves the order of remaining elements.
1025    pub fn remove_entry(&mut self, key: &Value) -> Option<(Value, Value)> {
1026        self.0.shift_remove_entry(key)
1027    }
1028
1029    /// Removes a key by swapping it with the last element.
1030    ///
1031    /// This is faster than `remove` but does not preserve order.
1032    pub fn swap_remove(&mut self, key: &Value) -> Option<Value> {
1033        self.0.swap_remove(key)
1034    }
1035
1036    /// Removes a key by shifting all elements after it.
1037    ///
1038    /// This preserves order but is slower than `swap_remove`.
1039    pub fn shift_remove(&mut self, key: &Value) -> Option<Value> {
1040        self.0.shift_remove(key)
1041    }
1042
1043    /// Gets the entry for the given key for in-place manipulation.
1044    pub fn entry(&mut self, key: Value) -> indexmap::map::Entry<'_, Value, Value> {
1045        self.0.entry(key)
1046    }
1047
1048    /// Retains only the key-value pairs specified by the predicate.
1049    pub fn retain<F>(&mut self, f: F)
1050    where
1051        F: FnMut(&Value, &mut Value) -> bool,
1052    {
1053        self.0.retain(f);
1054    }
1055
1056    /// Returns an iterator over the key-value pairs.
1057    #[must_use]
1058    pub fn iter(&self) -> Iter<'_, Value, Value> {
1059        self.0.iter()
1060    }
1061
1062    /// Returns a mutable iterator over the key-value pairs.
1063    pub fn iter_mut(&mut self) -> IterMut<'_, Value, Value> {
1064        self.0.iter_mut()
1065    }
1066
1067    /// Returns an iterator over the keys.
1068    #[must_use]
1069    pub fn keys(&self) -> Keys<'_, Value, Value> {
1070        self.0.keys()
1071    }
1072
1073    /// Returns an iterator over the values.
1074    #[must_use]
1075    pub fn values(&self) -> Values<'_, Value, Value> {
1076        self.0.values()
1077    }
1078
1079    /// Returns a mutable iterator over the values.
1080    pub fn values_mut(&mut self) -> ValuesMut<'_, Value, Value> {
1081        self.0.values_mut()
1082    }
1083
1084    /// Returns the first key-value pair.
1085    #[must_use]
1086    pub fn first(&self) -> Option<(&Value, &Value)> {
1087        self.0.first()
1088    }
1089
1090    /// Returns a mutable reference to the first key-value pair.
1091    #[must_use]
1092    pub fn first_mut(&mut self) -> Option<(&Value, &mut Value)> {
1093        self.0.first_mut()
1094    }
1095
1096    /// Returns the last key-value pair.
1097    #[must_use]
1098    pub fn last(&self) -> Option<(&Value, &Value)> {
1099        self.0.last()
1100    }
1101
1102    /// Returns a mutable reference to the last key-value pair.
1103    #[must_use]
1104    pub fn last_mut(&mut self) -> Option<(&Value, &mut Value)> {
1105        self.0.last_mut()
1106    }
1107
1108    /// Removes and returns the first key-value pair.
1109    pub fn pop_first(&mut self) -> Option<(Value, Value)> {
1110        self.0.shift_remove_index(0)
1111    }
1112
1113    /// Removes and returns the last key-value pair.
1114    pub fn pop_last(&mut self) -> Option<(Value, Value)> {
1115        self.0.pop()
1116    }
1117
1118    /// Sorts the mapping by keys.
1119    pub fn sort_keys(&mut self) {
1120        self.0.sort_keys();
1121    }
1122
1123    /// Reverses the order of key-value pairs.
1124    pub fn reverse(&mut self) {
1125        self.0.reverse();
1126    }
1127
1128    /// Extends the mapping with the contents of an iterator.
1129    pub fn extend<I>(&mut self, iter: I)
1130    where
1131        I: IntoIterator<Item = (Value, Value)>,
1132    {
1133        self.0.extend(iter);
1134    }
1135
1136    /// Returns the inner `IndexMap`.
1137    #[must_use]
1138    pub fn into_inner(self) -> IndexMap<Value, Value> {
1139        self.0.into_iter().collect()
1140    }
1141
1142    /// Creates a mapping from an `IndexMap`.
1143    #[must_use]
1144    pub fn from_inner(map: IndexMap<Value, Value>) -> Self {
1145        Self(map.into_iter().collect())
1146    }
1147
1148    /// Converts this `MappingAny` to a `Mapping` if all keys are strings.
1149    ///
1150    /// Returns `None` if any key is not a string value.
1151    ///
1152    /// # Examples
1153    ///
1154    /// ```rust
1155    /// use noyalib::{Mapping, MappingAny, Value};
1156    ///
1157    /// let mut map = MappingAny::new();
1158    /// map.insert(Value::from("key1"), Value::from(1));
1159    /// map.insert(Value::from("key2"), Value::from(2));
1160    ///
1161    /// let mapping = map.into_mapping().unwrap();
1162    /// assert_eq!(mapping.len(), 2);
1163    /// ```
1164    #[must_use]
1165    pub fn into_mapping(self) -> Option<Mapping> {
1166        let mut mapping = Mapping::with_capacity(self.len());
1167        for (k, v) in self.0 {
1168            if let Value::String(s) = k {
1169                let _ = mapping.insert(s, v);
1170            } else {
1171                return None;
1172            }
1173        }
1174        Some(mapping)
1175    }
1176}
1177
1178impl Index<&Value> for MappingAny {
1179    type Output = Value;
1180
1181    /// Index into the mapping by key.
1182    ///
1183    /// # Panics
1184    ///
1185    /// Panics if the key is not present in the mapping.
1186    #[track_caller]
1187    fn index(&self, key: &Value) -> &Self::Output {
1188        self.0.get(key).expect("key not found in mapping")
1189    }
1190}
1191
1192impl IndexMut<&Value> for MappingAny {
1193    /// Mutably index into the mapping by key.
1194    ///
1195    /// # Panics
1196    ///
1197    /// Panics if the key is not present in the mapping.
1198    #[track_caller]
1199    fn index_mut(&mut self, key: &Value) -> &mut Self::Output {
1200        self.0.get_mut(key).expect("key not found in mapping")
1201    }
1202}
1203
1204impl IntoIterator for MappingAny {
1205    type Item = (Value, Value);
1206    type IntoIter = IntoIter<Value, Value>;
1207
1208    fn into_iter(self) -> Self::IntoIter {
1209        self.0.into_iter()
1210    }
1211}
1212
1213impl<'a> IntoIterator for &'a MappingAny {
1214    type Item = (&'a Value, &'a Value);
1215    type IntoIter = Iter<'a, Value, Value>;
1216
1217    fn into_iter(self) -> Self::IntoIter {
1218        self.0.iter()
1219    }
1220}
1221
1222impl<'a> IntoIterator for &'a mut MappingAny {
1223    type Item = (&'a Value, &'a mut Value);
1224    type IntoIter = IterMut<'a, Value, Value>;
1225
1226    fn into_iter(self) -> Self::IntoIter {
1227        self.0.iter_mut()
1228    }
1229}
1230
1231impl FromIterator<(Value, Value)> for MappingAny {
1232    fn from_iter<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
1233        Self(IndexMap::from_iter(iter))
1234    }
1235}
1236
1237impl<const N: usize> From<[(Value, Value); N]> for MappingAny {
1238    fn from(arr: [(Value, Value); N]) -> Self {
1239        let mut map = Self::with_capacity(N);
1240        for (k, v) in arr {
1241            let _ = map.0.insert(k, v);
1242        }
1243        map
1244    }
1245}
1246
1247// See the note on the sibling impl: identical to the `FxIndexMap`
1248// version once no_std defaults the hasher. #210.
1249#[cfg(feature = "std")]
1250impl From<IndexMap<Value, Value>> for MappingAny {
1251    fn from(map: IndexMap<Value, Value>) -> Self {
1252        Self(map.into_iter().collect())
1253    }
1254}
1255
1256impl From<FxIndexMap<Value, Value>> for MappingAny {
1257    fn from(map: FxIndexMap<Value, Value>) -> Self {
1258        Self(map.into_iter().collect())
1259    }
1260}
1261
1262// On no_std the prelude defaults `IndexMap`'s hasher to
1263// `FxBuildHasher`, which makes this identical to the `FxIndexMap`
1264// impl below. Gated so the two do not collide there. See #210.
1265#[cfg(feature = "std")]
1266impl From<MappingAny> for IndexMap<Value, Value> {
1267    fn from(map: MappingAny) -> Self {
1268        map.0.into_iter().collect()
1269    }
1270}
1271
1272impl From<MappingAny> for FxIndexMap<Value, Value> {
1273    fn from(map: MappingAny) -> Self {
1274        map.0.into_iter().collect()
1275    }
1276}
1277
1278impl From<Mapping> for MappingAny {
1279    /// Converts a `Mapping` (with `String` keys) into a `MappingAny`.
1280    fn from(map: Mapping) -> Self {
1281        let mut any = Self::with_capacity(map.len());
1282        for (k, v) in map {
1283            let _ = any.insert(Value::String(k), v);
1284        }
1285        any
1286    }
1287}
1288
1289impl Hash for MappingAny {
1290    fn hash<H: Hasher>(&self, state: &mut H) {
1291        self.0.len().hash(state);
1292        for (k, v) in &self.0 {
1293            k.hash(state);
1294            v.hash(state);
1295        }
1296    }
1297}
1298
1299impl PartialOrd for MappingAny {
1300    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1301        Some(self.cmp(other))
1302    }
1303}
1304
1305impl Ord for MappingAny {
1306    fn cmp(&self, other: &Self) -> Ordering {
1307        self.len().cmp(&other.len()).then_with(|| {
1308            for ((ak, av), (bk, bv)) in self.iter().zip(other.iter()) {
1309                match ak.cmp(bk) {
1310                    Ordering::Equal => {}
1311                    ord => return ord,
1312                }
1313                match av.cmp(bv) {
1314                    Ordering::Equal => continue,
1315                    ord => return ord,
1316                }
1317            }
1318            Ordering::Equal
1319        })
1320    }
1321}
1322
1323impl fmt::Display for MappingAny {
1324    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1325        write!(f, "{{")?;
1326        for (i, (k, v)) in self.iter().enumerate() {
1327            if i > 0 {
1328                write!(f, ", ")?;
1329            }
1330            write!(f, "{k}: {v}")?;
1331        }
1332        write!(f, "}}")
1333    }
1334}
1335
1336impl serde_core::Serialize for MappingAny {
1337    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1338    where
1339        S: serde_core::Serializer,
1340    {
1341        use serde_core::ser::SerializeMap as _;
1342        let mut map = serializer.serialize_map(Some(self.len()))?;
1343        for (k, v) in self {
1344            map.serialize_entry(k, v)?;
1345        }
1346        map.end()
1347    }
1348}
1349
1350impl<'de> serde_core::Deserialize<'de> for MappingAny {
1351    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1352    where
1353        D: serde_core::Deserializer<'de>,
1354    {
1355        struct MappingAnyVisitor;
1356
1357        impl<'de> serde_core::de::Visitor<'de> for MappingAnyVisitor {
1358            type Value = MappingAny;
1359
1360            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1361                formatter.write_str("a YAML mapping")
1362            }
1363
1364            fn visit_map<A>(self, mut map: A) -> Result<MappingAny, A::Error>
1365            where
1366                A: serde_core::de::MapAccess<'de>,
1367            {
1368                let mut mapping = MappingAny::with_capacity(map.size_hint().unwrap_or(0));
1369                while let Some((key, value)) = map.next_entry::<Value, Value>()? {
1370                    let _ = mapping.insert(key, value);
1371                }
1372                Ok(mapping)
1373            }
1374        }
1375
1376        deserializer.deserialize_map(MappingAnyVisitor)
1377    }
1378}