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}