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}