From de89dc9cfc63f6f02c02d382c73482429e845e72 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Mon, 21 Nov 2022 21:20:28 -0800 Subject: feat(tvix/eval): add NixAttrs::into_iter() Signed-off-by: Adam Joseph Change-Id: Ib813d794177c623bf2f12fc2e6a6f304089607d1 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7356 Reviewed-by: tazjin Tested-by: BuildkiteCI --- tvix/eval/src/value/attrs.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tvix/eval/src/value/attrs.rs b/tvix/eval/src/value/attrs.rs index d8e3001f4a..6e839798d4 100644 --- a/tvix/eval/src/value/attrs.rs +++ b/tvix/eval/src/value/attrs.rs @@ -246,6 +246,26 @@ impl NixAttrs { }) } + pub fn into_iter(self) -> IntoIter { + match self.0 { + AttrsRep::Empty => IntoIter(IntoIterRepr::Empty), + AttrsRep::KV { name, value } => IntoIter(IntoIterRepr::Finite( + vec![ + (NixString::NAME_REF.clone(), name), + (NixString::VALUE_REF.clone(), value), + ] + .into_iter(), + )), + AttrsRep::Map(map) => IntoIter(IntoIterRepr::Map(map.into_iter())), + } + } + + /// Same as into_iter(), but marks call sites which rely on the + /// iteration being lexicographic. + pub fn into_iter_sorted(self) -> IntoIter { + self.into_iter() + } + /// Construct an iterator over all the keys of the attribute set pub fn keys(&self) -> Keys { Keys(match &self.0 { @@ -541,3 +561,35 @@ impl<'a> IntoIterator for &'a NixAttrs { self.iter() } } + +/// Internal representation of an owning attrset iterator +pub enum IntoIterRepr { + Empty, + Finite(std::vec::IntoIter<(NixString, Value)>), + Map(std::collections::btree_map::IntoIter), +} + +#[repr(transparent)] +pub struct IntoIter(IntoIterRepr); + +impl Iterator for IntoIter { + type Item = (NixString, Value); + + fn next(&mut self) -> Option { + match &mut self.0 { + IntoIterRepr::Empty => None, + IntoIterRepr::Map(inner) => inner.next(), + IntoIterRepr::Finite(inner) => inner.next(), + } + } +} + +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + match &self.0 { + IntoIterRepr::Empty => 0, + IntoIterRepr::Map(inner) => inner.len(), + IntoIterRepr::Finite(inner) => inner.len(), + } + } +} -- cgit 1.4.1