summaryrefslogtreecommitdiff
path: root/bzipper_macros/src/discriminant_iter/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'bzipper_macros/src/discriminant_iter/mod.rs')
-rw-r--r--bzipper_macros/src/discriminant_iter/mod.rs71
1 files changed, 71 insertions, 0 deletions
diff --git a/bzipper_macros/src/discriminant_iter/mod.rs b/bzipper_macros/src/discriminant_iter/mod.rs
new file mode 100644
index 0000000..ea34f6d
--- /dev/null
+++ b/bzipper_macros/src/discriminant_iter/mod.rs
@@ -0,0 +1,71 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of bZipper.
+//
+// bZipper is free software: you can redistribute
+// it and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// bZipper is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with bZipper. If
+// not, see <https://www.gnu.org/licenses/>.
+
+use crate::Discriminant;
+
+use std::borrow::Borrow;
+use syn::Variant;
+
+pub struct DiscriminantIter<I: IntoIterator<Item: Borrow<Variant>>> {
+ variants: I::IntoIter,
+ prev: Option<Discriminant>,
+}
+
+impl<I: IntoIterator<Item: Borrow<Variant>>> DiscriminantIter<I> {
+ #[inline(always)]
+ #[must_use]
+ pub fn new(variants: I) -> Self {
+ Self {
+ variants: variants.into_iter(),
+ prev: None,
+ }
+ }
+}
+
+impl<I: IntoIterator<Item: Borrow<Variant>>> Iterator for DiscriminantIter<I> {
+ type Item = (Discriminant, I::Item);
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ let variant = self.variants.next()?;
+
+ let discriminant = if let Some((_, ref discriminant)) = variant.borrow().discriminant {
+ Discriminant::parse(discriminant)
+ } else if let Some(discriminant) = self.prev {
+ let value = discriminant.0
+ .checked_add(0x1)
+ .unwrap_or_else(|| panic!("overflow following discriminant `{discriminant:?}`"));
+
+ Discriminant(value)
+ } else {
+ Default::default()
+ };
+
+ self.prev = Some(discriminant);
+
+ Some((discriminant, variant))
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.variants.size_hint()
+ }
+}