shadow_counted

Crates.ioshadow_counted
lib.rsshadow_counted
version0.7.0
created_at2024-10-24 12:52:13.581095+00
updated_at2025-10-29 04:42:35.680221+00
descriptionAn iterator that counts every iteration in a hidden counter, nested iterators may commit the count to parents
homepage
repositoryhttps://seed.pipapo.org/nodes/seed.pipapo.org/rad:zuUvsqfRdsC1NraTegYHBMtCmm2Z
max_upload_size
id1421302
size263,365
(cehteh)

documentation

https://docs.rs/shadow_counted

README

This crate provides a [ShadowCountedIter] which counts every iteration to a hidden counter. It is possible to create nested iterators which can commit their counter to their parent iterator. Additionally, iterators can carry supplemental data through the iteration process.

Unlike the std [std::iter::Enumerate] iterator, the [ShadowCountedIter] does not return the counter to the user, instead it has to be queried with the [ShadowCountedIter::counter()] method.

We also provide a [IntoShadowCounted] extension trait which converts any iterator into a [ShadowCountedIter].

Features

  • Basic counting: Track iteration progress without returning indices
  • Nested iteration: Create child iterators that inherit parent state
  • Commit mechanism: Propagate counts from nested iterators to parents
  • Supplemental data: Carry arbitrary data through iteration with optional commit logic

Examples

Basic Counting

use shadow_counted::{ShadowCountedIter, IntoShadowCounted};

let vec = vec![1, 2, 3];
let mut iter = vec.into_iter().shadow_counted();
while let Some(_) = iter.next() {}
assert_eq!(iter.counter(), 3);

Nested Counting

use shadow_counted::{ShadowCountedIter, IntoShadowCounted};

// Make a datastructure that may hold nested elements.
#[derive(Debug, PartialEq)]
enum Nodes<'a, T> {
    Leaf(T),
    Nested(&'a [Nodes<'a, T>]),
}

let items = &[
    Nodes::Leaf(1),
    Nodes::Nested(&[Nodes::Leaf(2), Nodes::Leaf(3)]),
    Nodes::Leaf(4),
];

// iterate over the outer
let mut sc_iter = items.into_iter().shadow_counted();
assert_eq!(sc_iter.next(), Some(&Nodes::Leaf(1)));

// the 2nd element is `Node::Nested(..)'
let element = sc_iter.next().unwrap();
# assert_eq!(element, &Nodes::Nested(&[Nodes::Leaf(2), Nodes::Leaf(3)]));

// since we dont want to count `Nested` we substract one from the counter
sc_iter.add(-1);
let Nodes::Nested(nested) = element else {unreachable!()};
let mut nested_iter = nested.into_iter().nested_shadow_counted(&mut sc_iter);

# assert_eq!(nested_iter.counter(), 1);
assert_eq!(nested_iter.next(), Some(&Nodes::Leaf(2)));
# assert_eq!(nested_iter.counter(), 2);
assert_eq!(nested_iter.next(), Some(&Nodes::Leaf(3)));
# assert_eq!(nested_iter.counter(), 3);
// reaching the end, commit to the parent iter
assert_eq!(nested_iter.next(), None);

// eventually a nested iter must be committed when its progress should be counted
nested_iter.commit();

// back to the outer
assert_eq!(sc_iter.counter(), 3);
assert_eq!(sc_iter.next(), Some(&Nodes::Leaf(4)));
# assert_eq!(sc_iter.counter(), 4);
# assert_eq!(sc_iter.next(), None);
assert_eq!(sc_iter.counter(), 4);

Supplemental Data

You can attach supplemental data to iterators that gets cloned when nesting and can be committed back to the parent. The parent data must use interior mutability (like Cell) to allow updates during commit:

use shadow_counted::{Commit, ShadowCountedIter, IntoShadowCounted};
use std::cell::Cell;

#[derive(Clone, Default, Debug)]
struct Stats {
    count: Cell<u32>,
}

impl Commit for Stats {
    fn commit(&self, from: Self) {
        self.count.set(self.count.get() + from.count.get());
    }
}

let mut parent = ShadowCountedIter::new_with(
    vec![1, 2].into_iter(),
    Stats::default()
);

let mut nested = vec![3, 4].into_iter().nested_shadow_counted(&mut parent);
nested.supplement_mut().count.set(5);
nested.commit().unwrap();

// Stats were committed from nested to parent
assert_eq!(parent.supplement().count.get(), 5);

Development

shadow_counted is distributed via radicle its identifier is rad:zuUvsqfRdsC1NraTegYHBMtCmm2Z

You can clone the repository using git by:
git clone https://seed.pipapo.org/zuUvsqfRdsC1NraTegYHBMtCmm2Z.git shadow_counted

When you spot a problem or need a new feature feel free to open an issue or (prefered!) send a PR.

Commits and other git operations are augmented and validated with bar. For contributors it is recommened to enable bar too by calling ./bar activate within a checked out unsynn repository.

Contribution/Coding Guidelines

Chances to get contributions merged increase when you:

  • Include documentation following the existing documentation practice. Write examples/doctests.
  • Passing ./bar lints is a absolute requirement, I am not even looking at contributions that fail basic lint and formatting checks. Hint: try ./bar dwim to apply formatting and trivial fixes.
  • Ideally passing ./bar without errors or warnings. Although if some problems and errors remain to be discussed then a WIP-PR failing tests is temporary acceptable.
  • Passing test-coverage with ./bar cargo_mutants.
  • When you activated the githooks with './bar activate' then the policies for viable commits are enforced automatically.
  • Implement reasonable complete things. Not everything needs to be included in a first version, but it must be usable.
Commit count: 0

cargo fmt