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