snix_eval/value/
attrs.rs

1//! This module implements Nix attribute sets. They have flexible
2//! backing implementations, as they are used in very versatile
3//! use-cases that are all exposed the same way in the language
4//! surface.
5//!
6//! Due to this, construction and management of attribute sets has
7//! some peculiarities that are encapsulated within this module.
8use std::borrow::Borrow;
9use std::collections::{BTreeMap, hash_map};
10use std::iter::FromIterator;
11use std::rc::Rc;
12use std::sync::LazyLock;
13
14use bstr::{BStr, ByteSlice};
15use itertools::Itertools as _;
16use rustc_hash::FxHashMap;
17use serde::Deserialize;
18use serde::de::{Deserializer, Error, Visitor};
19
20use super::TotalDisplay;
21use super::Value;
22use super::string::NixString;
23use super::thunk::ThunkSet;
24use crate::CatchableErrorKind;
25use crate::errors::ErrorKind;
26
27static NAME: LazyLock<NixString> = LazyLock::new(|| "name".into());
28static VALUE: LazyLock<NixString> = LazyLock::new(|| "value".into());
29
30#[cfg(test)]
31mod tests;
32
33#[derive(Clone, Debug, Deserialize, Default)]
34pub(super) enum AttrsRep {
35    #[default]
36    Empty,
37
38    Map(FxHashMap<NixString, Value>),
39
40    /// Warning: this represents a **two**-attribute attrset, with
41    /// attribute names "name" and "value", like `{name="foo";
42    /// value="bar";}`, *not* `{foo="bar";}`!
43    KV {
44        name: Value,
45        value: Value,
46    },
47}
48
49impl AttrsRep {
50    fn select(&self, key: &BStr) -> Option<&Value> {
51        match self {
52            AttrsRep::Empty => None,
53
54            AttrsRep::KV { name, value } => match &**key {
55                b"name" => Some(name),
56                b"value" => Some(value),
57                _ => None,
58            },
59
60            AttrsRep::Map(map) => map.get(key),
61        }
62    }
63
64    fn contains(&self, key: &BStr) -> bool {
65        match self {
66            AttrsRep::Empty => false,
67            AttrsRep::KV { .. } => key == "name" || key == "value",
68            AttrsRep::Map(map) => map.contains_key(key),
69        }
70    }
71}
72
73#[repr(transparent)]
74#[derive(Clone, Debug, Default)]
75pub struct NixAttrs(pub(super) Rc<AttrsRep>);
76
77impl From<AttrsRep> for NixAttrs {
78    fn from(rep: AttrsRep) -> Self {
79        NixAttrs(Rc::new(rep))
80    }
81}
82
83impl<K, V> FromIterator<(K, V)> for NixAttrs
84where
85    NixString: From<K>,
86    Value: From<V>,
87{
88    fn from_iter<T>(iter: T) -> NixAttrs
89    where
90        T: IntoIterator<Item = (K, V)>,
91    {
92        AttrsRep::Map(
93            iter.into_iter()
94                .map(|(k, v)| (k.into(), v.into()))
95                .collect(),
96        )
97        .into()
98    }
99}
100
101impl From<BTreeMap<NixString, Value>> for NixAttrs {
102    fn from(map: BTreeMap<NixString, Value>) -> Self {
103        AttrsRep::Map(map.into_iter().collect()).into()
104    }
105}
106
107impl From<FxHashMap<NixString, Value>> for NixAttrs {
108    fn from(map: FxHashMap<NixString, Value>) -> Self {
109        AttrsRep::Map(map).into()
110    }
111}
112
113impl TotalDisplay for NixAttrs {
114    fn total_fmt(&self, f: &mut std::fmt::Formatter<'_>, set: &mut ThunkSet) -> std::fmt::Result {
115        if self.is_derivation() {
116            write!(f, "«derivation")?;
117            // We cant use the default TotalDisplay implementation, because nix doesn't put quotes
118            // around the path here.
119            if let Some(Value::Thunk(p)) = self.select("drvPath") {
120                if p.is_forced()
121                    && let Ok(drv) = p.value().to_contextful_str()
122                {
123                    write!(f, " {}", drv.to_str_lossy())?;
124                };
125            }
126            return write!(f, "»");
127        }
128
129        f.write_str("{ ")?;
130
131        for (name, value) in self.iter_sorted() {
132            write!(f, "{} = ", name.ident_str())?;
133            value.total_fmt(f, set)?;
134            f.write_str("; ")?;
135        }
136
137        f.write_str("}")
138    }
139}
140
141impl<'de> Deserialize<'de> for NixAttrs {
142    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
143    where
144        D: Deserializer<'de>,
145    {
146        struct MapVisitor;
147
148        impl<'de> Visitor<'de> for MapVisitor {
149            type Value = NixAttrs;
150
151            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
152                formatter.write_str("a valid Nix attribute set")
153            }
154
155            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
156            where
157                A: serde::de::MapAccess<'de>,
158            {
159                let mut stack_array = Vec::with_capacity(map.size_hint().unwrap_or(0) * 2);
160
161                while let Some((key, value)) = map.next_entry()? {
162                    stack_array.push(key);
163                    stack_array.push(value);
164                }
165
166                Ok(NixAttrs::construct(stack_array.len() / 2, stack_array)
167                    .map_err(A::Error::custom)?
168                    .expect("Catchable values are unreachable here"))
169            }
170        }
171
172        deserializer.deserialize_map(MapVisitor)
173    }
174}
175
176impl NixAttrs {
177    pub fn empty() -> Self {
178        AttrsRep::Empty.into()
179    }
180
181    /// Compare two attribute sets by pointer equality. Only makes
182    /// sense for some attribute set representations, i.e. returning
183    /// `false` does not mean that the two attribute sets do not have
184    /// equal *content*.
185    pub fn ptr_eq(&self, other: &Self) -> bool {
186        Rc::ptr_eq(&self.0, &other.0)
187    }
188
189    /// Return an attribute set containing the merge of the two
190    /// provided sets. Keys from the `other` set have precedence.
191    pub fn update(self, other: Self) -> Self {
192        // Short-circuit on some optimal cases:
193        match (self.0.as_ref(), other.0.as_ref()) {
194            (AttrsRep::Empty, AttrsRep::Empty) => return self,
195            (AttrsRep::Empty, _) => return other,
196            (_, AttrsRep::Empty) => return self,
197            (AttrsRep::KV { .. }, AttrsRep::KV { .. }) => return other,
198
199            // Explicitly handle all branches instead of falling
200            // through, to ensure that we get at least some compiler
201            // errors if variants are modified.
202            (AttrsRep::Map(_), AttrsRep::Map(_))
203            | (AttrsRep::Map(_), AttrsRep::KV { .. })
204            | (AttrsRep::KV { .. }, AttrsRep::Map(_)) => {}
205        };
206
207        // Slightly more advanced, but still optimised updates
208        match (Rc::unwrap_or_clone(self.0), Rc::unwrap_or_clone(other.0)) {
209            (AttrsRep::Map(mut m), AttrsRep::KV { name, value }) => {
210                m.insert(NAME.clone(), name);
211                m.insert(VALUE.clone(), value);
212                AttrsRep::Map(m).into()
213            }
214
215            (AttrsRep::KV { name, value }, AttrsRep::Map(mut m)) => {
216                match m.entry(NAME.clone()) {
217                    hash_map::Entry::Vacant(e) => {
218                        e.insert(name);
219                    }
220
221                    hash_map::Entry::Occupied(_) => { /* name from `m` has precedence */ }
222                };
223
224                match m.entry(VALUE.clone()) {
225                    hash_map::Entry::Vacant(e) => {
226                        e.insert(value);
227                    }
228
229                    hash_map::Entry::Occupied(_) => { /* value from `m` has precedence */ }
230                };
231
232                AttrsRep::Map(m).into()
233            }
234
235            // Plain merge of maps.
236            (AttrsRep::Map(mut m1), AttrsRep::Map(mut m2)) => {
237                let map = if m1.len() >= m2.len() {
238                    m1.extend(m2);
239                    m1
240                } else {
241                    for (key, val) in m1.into_iter() {
242                        m2.entry(key).or_insert(val);
243                    }
244                    m2
245                };
246                AttrsRep::Map(map).into()
247            }
248
249            // Cases handled above by the borrowing match:
250            _ => unreachable!(),
251        }
252    }
253
254    /// Return the number of key-value entries in an attrset.
255    pub fn len(&self) -> usize {
256        match self.0.as_ref() {
257            AttrsRep::Map(map) => map.len(),
258            AttrsRep::Empty => 0,
259            AttrsRep::KV { .. } => 2,
260        }
261    }
262
263    pub fn is_empty(&self) -> bool {
264        match self.0.as_ref() {
265            AttrsRep::Map(map) => map.is_empty(),
266            AttrsRep::Empty => true,
267            AttrsRep::KV { .. } => false,
268        }
269    }
270
271    /// Select a value from an attribute set by key.
272    pub fn select<K>(&self, key: &K) -> Option<&Value>
273    where
274        K: Borrow<BStr> + ?Sized,
275    {
276        self.0.select(key.borrow())
277    }
278
279    /// Select a required value from an attribute set by key, return
280    /// an `AttributeNotFound` error if it is missing.
281    pub fn select_required<K>(&self, key: &K) -> Result<&Value, ErrorKind>
282    where
283        K: Borrow<BStr> + ?Sized,
284    {
285        self.select(key)
286            .ok_or_else(|| ErrorKind::AttributeNotFound {
287                name: key.borrow().to_string(),
288            })
289    }
290
291    pub fn contains<'a, K: 'a>(&self, key: K) -> bool
292    where
293        &'a BStr: From<K>,
294    {
295        self.0.contains(key.into())
296    }
297
298    /// Construct an iterator over all the key-value pairs in the attribute set.
299    #[allow(clippy::needless_lifetimes)]
300    pub fn iter<'a>(&'a self) -> Iter<KeyValue<'a>> {
301        Iter(match &self.0.as_ref() {
302            AttrsRep::Map(map) => KeyValue::Map(map.iter()),
303            AttrsRep::Empty => KeyValue::Empty,
304
305            AttrsRep::KV { name, value } => KeyValue::KV {
306                name,
307                value,
308                at: IterKV::default(),
309            },
310        })
311    }
312
313    /// Same as iter(), but marks call sites which rely on the
314    /// iteration being lexicographic.
315    pub fn iter_sorted(&self) -> Iter<KeyValue<'_>> {
316        Iter(match self.0.as_ref() {
317            AttrsRep::Empty => KeyValue::Empty,
318            AttrsRep::Map(map) => {
319                let sorted = map.iter().sorted_by_key(|x| x.0);
320                KeyValue::Sorted(sorted)
321            }
322            AttrsRep::KV { name, value } => KeyValue::KV {
323                name,
324                value,
325                at: IterKV::default(),
326            },
327        })
328    }
329
330    /// Same as [IntoIterator::into_iter], but marks call sites which rely on the
331    /// iteration being lexicographic.
332    pub fn into_iter_sorted(self) -> OwnedAttrsIterator {
333        let iter = match Rc::<AttrsRep>::try_unwrap(self.0) {
334            Ok(attrs) => match attrs {
335                AttrsRep::Empty => IntoIterRepr::Empty,
336                AttrsRep::Map(map) => {
337                    IntoIterRepr::Finite(map.into_iter().sorted_by(|(a, _), (b, _)| a.cmp(b)))
338                }
339                AttrsRep::KV { name, value } => IntoIterRepr::Finite(
340                    vec![(NAME.clone(), name), (VALUE.clone(), value)].into_iter(),
341                ),
342            },
343            Err(rc) => match rc.as_ref() {
344                AttrsRep::Empty => IntoIterRepr::Empty,
345                AttrsRep::Map(map) => IntoIterRepr::Finite(
346                    map.iter()
347                        .map(|(k, v)| (k.clone(), v.clone()))
348                        .sorted_by(|(a, _), (b, _)| a.cmp(b)),
349                ),
350                AttrsRep::KV { name, value } => IntoIterRepr::Finite(
351                    vec![(NAME.clone(), name.clone()), (VALUE.clone(), value.clone())].into_iter(),
352                ),
353            },
354        };
355        OwnedAttrsIterator(iter)
356    }
357
358    /// Construct an iterator over all the keys of the attribute set
359    pub fn keys(&self) -> Keys {
360        Keys(match self.0.as_ref() {
361            AttrsRep::Empty => KeysInner::Empty,
362            AttrsRep::KV { .. } => KeysInner::KV(IterKV::default()),
363
364            // TODO(tazjin): only sort when required, not always.
365            AttrsRep::Map(m) => KeysInner::Map(m.keys()),
366        })
367    }
368
369    /// Same as [Self::keys], but marks call sites which rely on the
370    /// iteration being lexicographic.
371    pub fn keys_sorted(&self) -> Keys {
372        Keys(match self.0.as_ref() {
373            AttrsRep::Map(map) => KeysInner::Sorted(map.keys().sorted()),
374            AttrsRep::Empty => KeysInner::Empty,
375            AttrsRep::KV { .. } => KeysInner::KV(IterKV::default()),
376        })
377    }
378
379    /// Implement construction logic of an attribute set, to encapsulate
380    /// logic about attribute set optimisations inside of this module.
381    pub fn construct(
382        count: usize,
383        mut stack_slice: Vec<Value>,
384    ) -> Result<Result<Self, CatchableErrorKind>, ErrorKind> {
385        debug_assert!(
386            stack_slice.len() == count * 2,
387            "construct_attrs called with count == {}, but slice.len() == {}",
388            count,
389            stack_slice.len(),
390        );
391
392        // Optimisation: Empty attribute set
393        if count == 0 {
394            return Ok(Ok(AttrsRep::Empty.into()));
395        }
396
397        // Optimisation: KV pattern
398        if count == 2 {
399            if let Some(kv) = attempt_optimise_kv(&mut stack_slice) {
400                return Ok(Ok(kv));
401            }
402        }
403
404        let mut attrs_map = FxHashMap::with_capacity_and_hasher(count, rustc_hash::FxBuildHasher);
405
406        for _ in 0..count {
407            let value = stack_slice.pop().unwrap();
408            let key = stack_slice.pop().unwrap();
409
410            match key {
411                Value::String(ks) => set_attr(&mut attrs_map, ks, value)?,
412
413                Value::Null => {
414                    // This is in fact valid, but leads to the value
415                    // being ignored and nothing being set, i.e. `{
416                    // ${null} = 1; } => { }`.
417                    continue;
418                }
419
420                Value::Catchable(err) => return Ok(Err(*err)),
421
422                other => return Err(ErrorKind::InvalidAttributeName(other)),
423            }
424        }
425
426        Ok(Ok(AttrsRep::Map(attrs_map).into()))
427    }
428
429    /// Construct an optimized "KV"-style attribute set given the value for the
430    /// `"name"` key, and the value for the `"value"` key
431    pub(crate) fn from_kv(name: Value, value: Value) -> Self {
432        AttrsRep::KV { name, value }.into()
433    }
434
435    /// Calculate the intersection of the attribute sets.
436    /// The right side value is used when the keys match.
437    pub(crate) fn intersect(&self, other: &Self) -> NixAttrs {
438        match (self.0.as_ref(), other.0.as_ref()) {
439            (AttrsRep::Empty, _) | (_, AttrsRep::Empty) => AttrsRep::Empty.into(),
440            (AttrsRep::Map(lhs), AttrsRep::Map(rhs)) => {
441                let mut out = FxHashMap::with_capacity_and_hasher(
442                    std::cmp::min(lhs.len(), rhs.len()),
443                    rustc_hash::FxBuildHasher,
444                );
445                if lhs.len() < rhs.len() {
446                    for key in lhs.keys() {
447                        if let Some(val) = rhs.get(key) {
448                            out.insert(key.clone(), val.clone());
449                        }
450                    }
451                } else {
452                    for (key, val) in rhs.iter() {
453                        if lhs.contains_key(key) {
454                            out.insert(key.clone(), val.clone());
455                        }
456                    }
457                };
458                out.into()
459            }
460            (AttrsRep::Map(map), AttrsRep::KV { name, value }) => {
461                let mut out = FxHashMap::with_capacity_and_hasher(2, rustc_hash::FxBuildHasher);
462                if map.contains_key(NAME.as_bstr()) {
463                    out.insert(NAME.clone(), name.clone());
464                }
465                if map.contains_key(VALUE.as_bstr()) {
466                    out.insert(VALUE.clone(), value.clone());
467                }
468
469                if out.is_empty() {
470                    NixAttrs::empty()
471                } else {
472                    out.into()
473                }
474            }
475            (AttrsRep::KV { .. }, AttrsRep::Map(map)) => {
476                let mut out = FxHashMap::with_capacity_and_hasher(2, rustc_hash::FxBuildHasher);
477                if let Some(name) = map.get(NAME.as_bstr()) {
478                    out.insert(NAME.clone(), name.clone());
479                }
480                if let Some(value) = map.get(VALUE.as_bstr()) {
481                    out.insert(VALUE.clone(), value.clone());
482                }
483
484                if out.is_empty() {
485                    NixAttrs::empty()
486                } else {
487                    out.into()
488                }
489            }
490            (AttrsRep::KV { .. }, AttrsRep::KV { .. }) => other.clone(),
491        }
492    }
493
494    /// Returns whether this attr set is a derivation.
495    pub fn is_derivation(&self) -> bool {
496        let Some(Value::String(kind)) = self.select("type") else {
497            return false;
498        };
499        *kind == "derivation"
500    }
501}
502
503impl IntoIterator for NixAttrs {
504    type Item = (NixString, Value);
505    type IntoIter = OwnedAttrsIterator;
506
507    fn into_iter(self) -> Self::IntoIter {
508        match Rc::unwrap_or_clone(self.0) {
509            AttrsRep::Empty => OwnedAttrsIterator(IntoIterRepr::Empty),
510            AttrsRep::KV { name, value } => OwnedAttrsIterator(IntoIterRepr::Finite(
511                vec![(NAME.clone(), name), (VALUE.clone(), value)].into_iter(),
512            )),
513            AttrsRep::Map(map) => OwnedAttrsIterator(IntoIterRepr::Map(map.into_iter())),
514        }
515    }
516}
517
518/// In Nix, name/value attribute pairs are frequently constructed from
519/// literals. This particular case should avoid allocation of a map,
520/// additional heap values etc. and use the optimised `KV` variant
521/// instead.
522///
523/// ```norust
524/// `slice` is the top of the stack from which the attrset is being
525/// constructed, e.g.
526///
527///   slice: [ "value" 5 "name" "foo" ]
528///   index:   0       1 2      3
529///   stack:   3       2 1      0
530/// ```
531fn attempt_optimise_kv(slice: &mut [Value]) -> Option<NixAttrs> {
532    let (name_idx, value_idx) = {
533        match (&slice[2], &slice[0]) {
534            (Value::String(s1), Value::String(s2)) if (*s1 == *NAME && *s2 == *VALUE) => (3, 1),
535            (Value::String(s1), Value::String(s2)) if (*s1 == *VALUE && *s2 == *NAME) => (1, 3),
536
537            // Technically this branch lets type errors pass,
538            // but they will be caught during normal attribute
539            // set construction instead.
540            _ => return None,
541        }
542    };
543
544    Some(NixAttrs::from_kv(
545        slice[name_idx].clone(),
546        slice[value_idx].clone(),
547    ))
548}
549
550/// Set an attribute on an in-construction attribute set, while
551/// checking against duplicate keys.
552fn set_attr(
553    map: &mut FxHashMap<NixString, Value>,
554    key: NixString,
555    value: Value,
556) -> Result<(), ErrorKind> {
557    match map.entry(key) {
558        hash_map::Entry::Occupied(entry) => Err(ErrorKind::DuplicateAttrsKey {
559            key: entry.key().to_string(),
560        }),
561
562        hash_map::Entry::Vacant(entry) => {
563            entry.insert(value);
564            Ok(())
565        }
566    }
567}
568
569/// Internal helper type to track the iteration status of an iterator
570/// over the name/value representation.
571#[derive(Debug, Default)]
572pub enum IterKV {
573    #[default]
574    Name,
575    Value,
576    Done,
577}
578
579impl IterKV {
580    fn next(&mut self) {
581        match *self {
582            Self::Name => *self = Self::Value,
583            Self::Value => *self = Self::Done,
584            Self::Done => {}
585        }
586    }
587}
588
589/// Iterator representation over the keys *and* values of an attribute
590/// set.
591pub enum KeyValue<'a> {
592    Empty,
593
594    KV {
595        name: &'a Value,
596        value: &'a Value,
597        at: IterKV,
598    },
599
600    Map(hash_map::Iter<'a, NixString, Value>),
601
602    Sorted(std::vec::IntoIter<(&'a NixString, &'a Value)>),
603}
604
605/// Iterator over a Nix attribute set.
606// This wrapper type exists to make the inner "raw" iterator
607// inaccessible.
608#[repr(transparent)]
609pub struct Iter<T>(T);
610
611impl<'a> Iterator for Iter<KeyValue<'a>> {
612    type Item = (&'a NixString, &'a Value);
613
614    fn next(&mut self) -> Option<Self::Item> {
615        match &mut self.0 {
616            KeyValue::Map(inner) => inner.next(),
617            KeyValue::Empty => None,
618            KeyValue::KV { name, value, at } => match at {
619                IterKV::Name => {
620                    at.next();
621                    Some((&NAME, name))
622                }
623
624                IterKV::Value => {
625                    at.next();
626                    Some((&VALUE, value))
627                }
628
629                IterKV::Done => None,
630            },
631            KeyValue::Sorted(inner) => inner.next(),
632        }
633    }
634}
635
636impl ExactSizeIterator for Iter<KeyValue<'_>> {
637    fn len(&self) -> usize {
638        match &self.0 {
639            KeyValue::Empty => 0,
640            KeyValue::KV { .. } => 2,
641            KeyValue::Map(inner) => inner.len(),
642            KeyValue::Sorted(inner) => inner.len(),
643        }
644    }
645}
646
647enum KeysInner<'a> {
648    Empty,
649    KV(IterKV),
650    Map(hash_map::Keys<'a, NixString, Value>),
651    Sorted(std::vec::IntoIter<&'a NixString>),
652}
653
654pub struct Keys<'a>(KeysInner<'a>);
655
656impl<'a> Iterator for Keys<'a> {
657    type Item = &'a NixString;
658
659    fn next(&mut self) -> Option<Self::Item> {
660        match &mut self.0 {
661            KeysInner::Empty => None,
662            KeysInner::KV(at @ IterKV::Name) => {
663                at.next();
664                Some(&NAME)
665            }
666            KeysInner::KV(at @ IterKV::Value) => {
667                at.next();
668                Some(&VALUE)
669            }
670            KeysInner::KV(IterKV::Done) => None,
671            KeysInner::Map(m) => m.next(),
672            KeysInner::Sorted(v) => v.next(),
673        }
674    }
675}
676
677impl<'a> IntoIterator for &'a NixAttrs {
678    type Item = (&'a NixString, &'a Value);
679
680    type IntoIter = Iter<KeyValue<'a>>;
681
682    fn into_iter(self) -> Self::IntoIter {
683        self.iter()
684    }
685}
686
687impl ExactSizeIterator for Keys<'_> {
688    fn len(&self) -> usize {
689        match &self.0 {
690            KeysInner::Empty => 0,
691            KeysInner::KV(_) => 2,
692            KeysInner::Map(m) => m.len(),
693            KeysInner::Sorted(v) => v.len(),
694        }
695    }
696}
697
698/// Internal representation of an owning attrset iterator
699pub enum IntoIterRepr {
700    Empty,
701    Finite(std::vec::IntoIter<(NixString, Value)>),
702    Map(hash_map::IntoIter<NixString, Value>),
703}
704
705/// Wrapper type which hides the internal implementation details from
706/// users.
707#[repr(transparent)]
708pub struct OwnedAttrsIterator(IntoIterRepr);
709
710impl Iterator for OwnedAttrsIterator {
711    type Item = (NixString, Value);
712
713    fn next(&mut self) -> Option<Self::Item> {
714        match &mut self.0 {
715            IntoIterRepr::Empty => None,
716            IntoIterRepr::Finite(inner) => inner.next(),
717            IntoIterRepr::Map(m) => m.next(),
718        }
719    }
720}
721
722impl ExactSizeIterator for OwnedAttrsIterator {
723    fn len(&self) -> usize {
724        match &self.0 {
725            IntoIterRepr::Empty => 0,
726            IntoIterRepr::Finite(inner) => inner.len(),
727            IntoIterRepr::Map(inner) => inner.len(),
728        }
729    }
730}
731
732impl DoubleEndedIterator for OwnedAttrsIterator {
733    fn next_back(&mut self) -> Option<Self::Item> {
734        match &mut self.0 {
735            IntoIterRepr::Empty => None,
736            IntoIterRepr::Finite(inner) => inner.next_back(),
737            // hashmaps have arbitary iteration order, so reversing it would not make a difference
738            IntoIterRepr::Map(inner) => inner.next(),
739        }
740    }
741}