valence_nbt/
compound.rs

1use std::borrow::{Borrow, Cow};
2use std::fmt;
3use std::hash::Hash;
4use std::iter::FusedIterator;
5use std::ops::{Index, IndexMut};
6
7use crate::Value;
8
9/// A map type with [`String`] keys and [`Value`] values.
10#[derive(Clone, Default)]
11pub struct Compound<S = String> {
12    map: Map<S>,
13}
14
15#[cfg(not(feature = "preserve_order"))]
16type Map<S> = std::collections::BTreeMap<S, Value<S>>;
17
18#[cfg(feature = "preserve_order")]
19type Map<S> = indexmap::IndexMap<S, Value<S>>;
20
21impl<S: fmt::Debug> fmt::Debug for Compound<S> {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        self.map.fmt(f)
24    }
25}
26
27impl<S> PartialEq for Compound<S>
28where
29    S: Ord + Hash,
30{
31    fn eq(&self, other: &Self) -> bool {
32        self.map == other.map
33    }
34}
35
36#[cfg(feature = "serde")]
37impl<Str> serde::Serialize for Compound<Str>
38where
39    Str: Ord + Hash + serde::Serialize,
40{
41    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42    where
43        S: serde::Serializer,
44    {
45        self.map.serialize(serializer)
46    }
47}
48
49#[cfg(feature = "serde")]
50impl<'de, S> serde::Deserialize<'de> for Compound<S>
51where
52    S: Ord + Hash + serde::Deserialize<'de>,
53{
54    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
55    where
56        D: serde::Deserializer<'de>,
57    {
58        Map::<S>::deserialize(deserializer).map(|map| Self { map })
59    }
60
61    fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
62    where
63        D: serde::Deserializer<'de>,
64    {
65        Map::<S>::deserialize_in_place(deserializer, &mut place.map)
66    }
67}
68
69impl<S> Compound<S> {
70    pub fn new() -> Self {
71        Self { map: Map::new() }
72    }
73
74    pub fn with_capacity(cap: usize) -> Self {
75        Self {
76            #[cfg(not(feature = "preserve_order"))]
77            map: {
78                // BTreeMap does not have with_capacity.
79                let _ = cap;
80                Map::new()
81            },
82            #[cfg(feature = "preserve_order")]
83            map: Map::with_capacity(cap),
84        }
85    }
86
87    pub fn clear(&mut self) {
88        self.map.clear();
89    }
90}
91
92impl<S> Compound<S>
93where
94    S: Ord + Hash,
95{
96    pub fn get<Q>(&self, k: &Q) -> Option<&Value<S>>
97    where
98        Q: ?Sized + AsBorrowed<S>,
99        <Q as AsBorrowed<S>>::Borrowed: Hash + Ord,
100        S: Borrow<<Q as AsBorrowed<S>>::Borrowed>,
101    {
102        self.map.get(k.as_borrowed())
103    }
104
105    pub fn contains_key<Q>(&self, k: &Q) -> bool
106    where
107        Q: ?Sized + AsBorrowed<S>,
108        <Q as AsBorrowed<S>>::Borrowed: Hash + Ord,
109        S: Borrow<<Q as AsBorrowed<S>>::Borrowed>,
110    {
111        self.map.contains_key(k.as_borrowed())
112    }
113
114    pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut Value<S>>
115    where
116        Q: ?Sized + AsBorrowed<S>,
117        <Q as AsBorrowed<S>>::Borrowed: Hash + Ord,
118        S: Borrow<<Q as AsBorrowed<S>>::Borrowed>,
119    {
120        self.map.get_mut(k.as_borrowed())
121    }
122
123    pub fn get_key_value<Q>(&self, k: &Q) -> Option<(&S, &Value<S>)>
124    where
125        Q: ?Sized + AsBorrowed<S>,
126        <Q as AsBorrowed<S>>::Borrowed: Hash + Ord,
127        S: Borrow<<Q as AsBorrowed<S>>::Borrowed>,
128    {
129        self.map.get_key_value(k.as_borrowed())
130    }
131
132    pub fn insert<K, V>(&mut self, k: K, v: V) -> Option<Value<S>>
133    where
134        K: Into<S>,
135        V: Into<Value<S>>,
136    {
137        self.map.insert(k.into(), v.into())
138    }
139
140    pub fn remove<Q>(&mut self, k: &Q) -> Option<Value<S>>
141    where
142        Q: ?Sized + AsBorrowed<S>,
143        <Q as AsBorrowed<S>>::Borrowed: Hash + Ord,
144        S: Borrow<<Q as AsBorrowed<S>>::Borrowed>,
145    {
146        #[cfg(feature = "preserve_order")]
147        return self.swap_remove(k);
148        #[cfg(not(feature = "preserve_order"))]
149        return self.map.remove(k.as_borrowed());
150    }
151
152    #[cfg(feature = "preserve_order")]
153    pub fn swap_remove<Q>(&mut self, k: &Q) -> Option<Value<S>>
154    where
155        Q: ?Sized + AsBorrowed<S>,
156        <Q as AsBorrowed<S>>::Borrowed: Hash + Ord,
157        S: Borrow<<Q as AsBorrowed<S>>::Borrowed>,
158    {
159        self.map.swap_remove(k.as_borrowed())
160    }
161
162    #[cfg(feature = "preserve_order")]
163    pub fn shift_remove<Q>(&mut self, k: &Q) -> Option<Value<S>>
164    where
165        Q: ?Sized + AsBorrowed<S>,
166        <Q as AsBorrowed<S>>::Borrowed: Hash + Ord,
167        S: Borrow<<Q as AsBorrowed<S>>::Borrowed>,
168    {
169        self.map.shift_remove(k.as_borrowed())
170    }
171
172    pub fn remove_entry<Q>(&mut self, k: &Q) -> Option<(S, Value<S>)>
173    where
174        S: Borrow<Q>,
175        Q: ?Sized + Ord + Hash,
176    {
177        #[cfg(feature = "preserve_order")]
178        return self.swap_remove_entry(k);
179        #[cfg(not(feature = "preserve_order"))]
180        return self.map.remove_entry(k);
181    }
182
183    #[cfg(feature = "preserve_order")]
184    pub fn swap_remove_entry<Q>(&mut self, k: &Q) -> Option<(S, Value<S>)>
185    where
186        S: Borrow<Q>,
187        Q: ?Sized + Ord + Hash,
188    {
189        self.map.swap_remove_entry(k)
190    }
191
192    #[cfg(feature = "preserve_order")]
193    pub fn shift_remove_entry<Q>(&mut self, k: &Q) -> Option<(S, Value<S>)>
194    where
195        S: Borrow<Q>,
196        Q: ?Sized + Ord + Hash,
197    {
198        self.map.shift_remove_entry(k)
199    }
200
201    pub fn append(&mut self, other: &mut Self) {
202        #[cfg(not(feature = "preserve_order"))]
203        self.map.append(&mut other.map);
204
205        #[cfg(feature = "preserve_order")]
206        for (k, v) in std::mem::take(&mut other.map) {
207            self.map.insert(k, v);
208        }
209    }
210
211    pub fn entry<K>(&mut self, k: K) -> Entry<S>
212    where
213        K: Into<S>,
214    {
215        #[cfg(not(feature = "preserve_order"))]
216        use std::collections::btree_map::Entry as EntryImpl;
217
218        #[cfg(feature = "preserve_order")]
219        use indexmap::map::Entry as EntryImpl;
220
221        match self.map.entry(k.into()) {
222            EntryImpl::Vacant(ve) => Entry::Vacant(VacantEntry { entry: ve }),
223            EntryImpl::Occupied(oe) => Entry::Occupied(OccupiedEntry { entry: oe }),
224        }
225    }
226
227    pub fn len(&self) -> usize {
228        self.map.len()
229    }
230
231    pub fn is_empty(&self) -> bool {
232        self.map.is_empty()
233    }
234
235    pub fn iter(&self) -> Iter<S> {
236        Iter {
237            iter: self.map.iter(),
238        }
239    }
240
241    pub fn iter_mut(&mut self) -> IterMut<S> {
242        IterMut {
243            iter: self.map.iter_mut(),
244        }
245    }
246
247    pub fn keys(&self) -> Keys<S> {
248        Keys {
249            iter: self.map.keys(),
250        }
251    }
252
253    pub fn values(&self) -> Values<S> {
254        Values {
255            iter: self.map.values(),
256        }
257    }
258
259    pub fn values_mut(&mut self) -> ValuesMut<S> {
260        ValuesMut {
261            iter: self.map.values_mut(),
262        }
263    }
264
265    pub fn retain<F>(&mut self, f: F)
266    where
267        F: FnMut(&S, &mut Value<S>) -> bool,
268    {
269        self.map.retain(f)
270    }
271
272    /// Inserts all items from `other` into `self` recursively.
273    ///
274    /// # Example
275    ///
276    /// ```
277    /// use valence_nbt::compound;
278    ///
279    /// let mut this = compound! {
280    ///     "foo" => 10,
281    ///     "bar" => compound! {
282    ///         "baz" => 20,
283    ///     }
284    /// };
285    ///
286    /// let other = compound! {
287    ///     "foo" => 15,
288    ///     "bar" => compound! {
289    ///         "quux" => "hello",
290    ///     }
291    /// };
292    ///
293    /// this.merge(other);
294    ///
295    /// assert_eq!(
296    ///     this,
297    ///     compound! {
298    ///         "foo" => 15,
299    ///         "bar" => compound! {
300    ///             "baz" => 20,
301    ///             "quux" => "hello",
302    ///         }
303    ///     }
304    /// );
305    /// ```
306    pub fn merge(&mut self, other: Compound<S>) {
307        for (k, v) in other {
308            match (self.entry(k), v) {
309                (Entry::Occupied(mut oe), Value::Compound(other)) => {
310                    if let Value::Compound(this) = oe.get_mut() {
311                        // Insert compound recursively.
312                        this.merge(other);
313                    }
314                }
315                (Entry::Occupied(mut oe), value) => {
316                    oe.insert(value);
317                }
318                (Entry::Vacant(ve), value) => {
319                    ve.insert(value);
320                }
321            }
322        }
323    }
324}
325
326/// Trait that can be used as a key to query a compound. Basically something
327/// that can be converted to a type `B` such that `S: Borrow<B>`.
328pub trait AsBorrowed<S> {
329    type Borrowed: ?Sized;
330
331    fn as_borrowed(&self) -> &Self::Borrowed;
332}
333
334impl<Q: ?Sized> AsBorrowed<String> for Q
335where
336    String: Borrow<Q>,
337{
338    type Borrowed = Q;
339
340    #[inline]
341    fn as_borrowed(&self) -> &Q {
342        self
343    }
344}
345
346impl<'a, Q: ?Sized> AsBorrowed<Cow<'a, str>> for Q
347where
348    Cow<'a, str>: Borrow<Q>,
349{
350    type Borrowed = Q;
351
352    #[inline]
353    fn as_borrowed(&self) -> &Q {
354        self
355    }
356}
357
358#[cfg(feature = "java_string")]
359impl<Q: ?Sized> AsBorrowed<java_string::JavaString> for Q
360where
361    for<'a> &'a Q: Into<&'a java_string::JavaStr>,
362{
363    type Borrowed = java_string::JavaStr;
364
365    fn as_borrowed(&self) -> &Self::Borrowed {
366        self.into()
367    }
368}
369
370#[cfg(feature = "java_string")]
371impl<Q: ?Sized> AsBorrowed<Cow<'_, java_string::JavaStr>> for Q
372where
373    for<'a> &'a Q: Into<&'a java_string::JavaStr>,
374{
375    type Borrowed = java_string::JavaStr;
376
377    fn as_borrowed(&self) -> &Self::Borrowed {
378        self.into()
379    }
380}
381
382impl<S> Extend<(S, Value<S>)> for Compound<S>
383where
384    S: Ord + Hash,
385{
386    fn extend<T>(&mut self, iter: T)
387    where
388        T: IntoIterator<Item = (S, Value<S>)>,
389    {
390        self.map.extend(iter)
391    }
392}
393
394impl<S> FromIterator<(S, Value<S>)> for Compound<S>
395where
396    S: Ord + Hash,
397{
398    fn from_iter<T>(iter: T) -> Self
399    where
400        T: IntoIterator<Item = (S, Value<S>)>,
401    {
402        Self {
403            map: Map::from_iter(iter),
404        }
405    }
406}
407
408pub enum Entry<'a, S = String> {
409    Vacant(VacantEntry<'a, S>),
410    Occupied(OccupiedEntry<'a, S>),
411}
412
413impl<'a, S> Entry<'a, S>
414where
415    S: Hash + Ord,
416{
417    pub fn key(&self) -> &S {
418        match self {
419            Entry::Vacant(ve) => ve.key(),
420            Entry::Occupied(oe) => oe.key(),
421        }
422    }
423
424    pub fn or_insert<V: Into<Value<S>>>(self, default: V) -> &'a mut Value<S> {
425        match self {
426            Entry::Vacant(ve) => ve.insert(default),
427            Entry::Occupied(oe) => oe.into_mut(),
428        }
429    }
430
431    pub fn or_insert_with<F, V>(self, default: F) -> &'a mut Value<S>
432    where
433        F: FnOnce() -> V,
434        V: Into<Value<S>>,
435    {
436        match self {
437            Entry::Vacant(ve) => ve.insert(default()),
438            Entry::Occupied(oe) => oe.into_mut(),
439        }
440    }
441
442    pub fn and_modify<F>(self, f: F) -> Self
443    where
444        F: FnOnce(&mut Value<S>),
445    {
446        match self {
447            Entry::Vacant(ve) => Entry::Vacant(ve),
448            Entry::Occupied(mut oe) => {
449                f(oe.get_mut());
450                Entry::Occupied(oe)
451            }
452        }
453    }
454}
455
456impl<S> fmt::Debug for Entry<'_, S>
457where
458    S: fmt::Debug + Ord,
459{
460    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461        match self {
462            Self::Vacant(entry) => f.debug_tuple("Vacant").field(entry).finish(),
463            Self::Occupied(entry) => f.debug_tuple("Occupied").field(entry).finish(),
464        }
465    }
466}
467
468pub struct VacantEntry<'a, S = String> {
469    #[cfg(not(feature = "preserve_order"))]
470    entry: std::collections::btree_map::VacantEntry<'a, S, Value<S>>,
471    #[cfg(feature = "preserve_order")]
472    entry: indexmap::map::VacantEntry<'a, S, Value<S>>,
473}
474
475impl<'a, S> VacantEntry<'a, S>
476where
477    S: Ord + Hash,
478{
479    pub fn key(&self) -> &S {
480        self.entry.key()
481    }
482
483    pub fn insert<V: Into<Value<S>>>(self, v: V) -> &'a mut Value<S> {
484        self.entry.insert(v.into())
485    }
486}
487
488impl<S> fmt::Debug for VacantEntry<'_, S>
489where
490    S: fmt::Debug + Ord,
491{
492    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493        f.debug_struct("VacantEntry")
494            .field("entry", &self.entry)
495            .finish()
496    }
497}
498
499pub struct OccupiedEntry<'a, S = String> {
500    #[cfg(not(feature = "preserve_order"))]
501    entry: std::collections::btree_map::OccupiedEntry<'a, S, Value<S>>,
502    #[cfg(feature = "preserve_order")]
503    entry: indexmap::map::OccupiedEntry<'a, S, Value<S>>,
504}
505
506impl<'a, S> OccupiedEntry<'a, S>
507where
508    S: Hash + Ord,
509{
510    pub fn key(&self) -> &S {
511        self.entry.key()
512    }
513
514    pub fn get(&self) -> &Value<S> {
515        self.entry.get()
516    }
517
518    pub fn get_mut(&mut self) -> &mut Value<S> {
519        self.entry.get_mut()
520    }
521
522    pub fn into_mut(self) -> &'a mut Value<S> {
523        self.entry.into_mut()
524    }
525
526    pub fn insert<V: Into<Value<S>>>(&mut self, v: V) -> Value<S> {
527        self.entry.insert(v.into())
528    }
529
530    pub fn remove(self) -> Value<S> {
531        #[cfg(feature = "preserve_order")]
532        return self.swap_remove();
533        #[cfg(not(feature = "preserve_order"))]
534        return self.entry.remove();
535    }
536
537    #[cfg(feature = "preserve_order")]
538    pub fn swap_remove(self) -> Value<S> {
539        self.entry.swap_remove()
540    }
541
542    #[cfg(feature = "preserve_order")]
543    pub fn shift_remove(self) -> Value<S> {
544        self.entry.shift_remove()
545    }
546}
547
548impl<S> fmt::Debug for OccupiedEntry<'_, S>
549where
550    S: fmt::Debug + Ord,
551{
552    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553        f.debug_struct("OccupiedEntry")
554            .field("entry", &self.entry)
555            .finish()
556    }
557}
558
559impl<S, Q> Index<&'_ Q> for Compound<S>
560where
561    S: Borrow<Q> + Ord + Hash,
562    Q: ?Sized + Ord + Hash,
563{
564    type Output = Value<S>;
565
566    fn index(&self, index: &Q) -> &Self::Output {
567        self.map.index(index)
568    }
569}
570
571impl<S, Q> IndexMut<&'_ Q> for Compound<S>
572where
573    S: Borrow<Q> + Hash + Ord,
574    Q: ?Sized + Ord + Hash,
575{
576    fn index_mut(&mut self, index: &Q) -> &mut Self::Output {
577        self.map.get_mut(index).expect("no entry found for key")
578    }
579}
580
581macro_rules! impl_iterator_traits {
582    (($name:ident $($generics:tt)*) => $item:ty) => {
583        impl $($generics)* Iterator for $name $($generics)* {
584            type Item = $item;
585            #[inline]
586            fn next(&mut self) -> Option<Self::Item> {
587                self.iter.next()
588            }
589            #[inline]
590            fn size_hint(&self) -> (usize, Option<usize>) {
591                self.iter.size_hint()
592            }
593        }
594
595        #[cfg(feature = "preserve_order")]
596        impl $($generics)* DoubleEndedIterator for $name $($generics)* {
597            #[inline]
598            fn next_back(&mut self) -> Option<Self::Item> {
599                self.iter.next_back()
600            }
601        }
602
603        impl $($generics)* ExactSizeIterator for $name $($generics)* {
604            #[inline]
605            fn len(&self) -> usize {
606                self.iter.len()
607            }
608        }
609
610        impl $($generics)* FusedIterator for $name $($generics)* {}
611    }
612}
613
614impl<'a, S> IntoIterator for &'a Compound<S> {
615    type Item = (&'a S, &'a Value<S>);
616    type IntoIter = Iter<'a, S>;
617
618    fn into_iter(self) -> Self::IntoIter {
619        Iter {
620            iter: self.map.iter(),
621        }
622    }
623}
624
625#[derive(Clone, Debug)]
626pub struct Iter<'a, S = String> {
627    #[cfg(not(feature = "preserve_order"))]
628    iter: std::collections::btree_map::Iter<'a, S, Value<S>>,
629    #[cfg(feature = "preserve_order")]
630    iter: indexmap::map::Iter<'a, S, Value<S>>,
631}
632
633impl_iterator_traits!((Iter<'a, S>) => (&'a S, &'a Value<S>));
634
635impl<'a, S> IntoIterator for &'a mut Compound<S> {
636    type Item = (&'a S, &'a mut Value<S>);
637    type IntoIter = IterMut<'a, S>;
638
639    fn into_iter(self) -> Self::IntoIter {
640        IterMut {
641            iter: self.map.iter_mut(),
642        }
643    }
644}
645
646#[derive(Debug)]
647pub struct IterMut<'a, S = String> {
648    #[cfg(not(feature = "preserve_order"))]
649    iter: std::collections::btree_map::IterMut<'a, S, Value<S>>,
650    #[cfg(feature = "preserve_order")]
651    iter: indexmap::map::IterMut<'a, S, Value<S>>,
652}
653
654impl_iterator_traits!((IterMut<'a, S>) => (&'a S, &'a mut Value<S>));
655
656impl<S> IntoIterator for Compound<S> {
657    type Item = (S, Value<S>);
658    type IntoIter = IntoIter<S>;
659
660    fn into_iter(self) -> Self::IntoIter {
661        IntoIter {
662            iter: self.map.into_iter(),
663        }
664    }
665}
666
667#[derive(Debug)]
668pub struct IntoIter<S = String> {
669    #[cfg(not(feature = "preserve_order"))]
670    iter: std::collections::btree_map::IntoIter<S, Value<S>>,
671    #[cfg(feature = "preserve_order")]
672    iter: indexmap::map::IntoIter<S, Value<S>>,
673}
674
675impl_iterator_traits!((IntoIter<S>) => (S, Value<S>));
676
677#[derive(Clone, Debug)]
678pub struct Keys<'a, S = String> {
679    #[cfg(not(feature = "preserve_order"))]
680    iter: std::collections::btree_map::Keys<'a, S, Value<S>>,
681    #[cfg(feature = "preserve_order")]
682    iter: indexmap::map::Keys<'a, S, Value<S>>,
683}
684
685impl_iterator_traits!((Keys<'a, S>) => &'a S);
686
687#[derive(Clone, Debug)]
688pub struct Values<'a, S = String> {
689    #[cfg(not(feature = "preserve_order"))]
690    iter: std::collections::btree_map::Values<'a, S, Value<S>>,
691    #[cfg(feature = "preserve_order")]
692    iter: indexmap::map::Values<'a, S, Value<S>>,
693}
694
695impl_iterator_traits!((Values<'a, S>) => &'a Value<S>);
696
697#[derive(Debug)]
698pub struct ValuesMut<'a, S = String> {
699    #[cfg(not(feature = "preserve_order"))]
700    iter: std::collections::btree_map::ValuesMut<'a, S, Value<S>>,
701    #[cfg(feature = "preserve_order")]
702    iter: indexmap::map::ValuesMut<'a, S, Value<S>>,
703}
704
705impl_iterator_traits!((ValuesMut<'a, S>) => &'a mut Value<S>);
706
707#[cfg(test)]
708mod tests {
709    #[cfg(feature = "preserve_order")]
710    #[test]
711    fn compound_preserves_order() {
712        use super::*;
713
714        let letters = ["g", "b", "d", "e", "h", "z", "m", "a", "q"];
715
716        let mut c = Compound::<String>::new();
717        for l in letters {
718            c.insert(l, 0_i8);
719        }
720
721        for (k, l) in c.keys().zip(letters) {
722            assert_eq!(k, l);
723        }
724    }
725}