shadow_counted 0.7.0

An iterator that counts every iteration in a hidden counter, nested iterators may commit the count to parents
Documentation
use shadow_counted::{Commit, IntoShadowCounted, ShadowCountedIter};
use std::cell::Cell;

#[derive(Debug, Clone, Default, PartialEq)]
struct TestData {
    value: u32,
}

impl Commit for TestData {
    fn commit(&self, _from: Self) {}
}

#[derive(Debug, Clone, Default)]
struct AccumulatingData {
    sum: Cell<i32>,
}

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

/// Test basic supplemental data creation
#[test]
fn test_new_with_data() {
    let data = TestData { value: 42 };
    let iter = ShadowCountedIter::new_with(vec![1, 2, 3].into_iter(), data);

    assert_eq!(iter.supplement().value, 42);
}

/// Test supplement returns correct reference
#[test]
fn test_supplement_access() {
    let iter = ShadowCountedIter::new_with(vec![1, 2].into_iter(), TestData { value: 100 });

    let data_ref = iter.supplement();
    assert_eq!(data_ref.value, 100);
}

/// Test supplement_mut allows modification
#[test]
fn test_supplement_mut_modification() {
    let mut iter = ShadowCountedIter::new_with(vec![1, 2].into_iter(), TestData { value: 10 });

    assert_eq!(iter.supplement().value, 10);

    iter.supplement_mut().value = 20;
    assert_eq!(iter.supplement().value, 20);

    iter.supplement_mut().value += 5;
    assert_eq!(iter.supplement().value, 25);
}

/// Test data is cloned to nested iterator
#[test]
fn test_data_cloned_to_nested() {
    let mut parent = ShadowCountedIter::new_with(vec![1, 2].into_iter(), TestData { value: 99 });

    let nested = vec![3, 4].into_iter().nested_shadow_counted(&mut parent);

    assert_eq!(nested.supplement().value, 99);
}

/// Test nested data modification doesn't affect parent before commit
#[test]
fn test_nested_data_isolation() {
    let mut parent = ShadowCountedIter::new_with(vec![1].into_iter(), TestData { value: 50 });

    let mut nested = vec![2].into_iter().nested_shadow_counted(&mut parent);

    nested.supplement_mut().value = 75;

    // Nested has modified value
    assert_eq!(nested.supplement().value, 75);

    nested.commit().unwrap();

    // Parent still has original value (Commit doesn't update it)
    assert_eq!(parent.supplement().value, 50);
}

/// Test Commit trait with accumulating data
#[test]
fn test_commit_trait_accumulation() {
    let mut parent =
        ShadowCountedIter::new_with(vec![1].into_iter(), AccumulatingData { sum: Cell::new(10) });

    let mut nested = vec![2, 3].into_iter().nested_shadow_counted(&mut parent);

    nested.supplement_mut().sum.set(25);
    nested.commit().unwrap();

    // Parent should have accumulated value
    assert_eq!(parent.supplement().sum.get(), 35);
}

/// Test Commit trait called on commit
#[test]
fn test_commit_trait_invoked() {
    #[derive(Debug, Clone, Default)]
    struct CallCounter {
        commits: Cell<u32>,
    }

    impl Commit for CallCounter {
        fn commit(&self, _from: Self) {
            // Just increment the parent's counter
            self.commits.set(self.commits.get() + 1);
        }
    }

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

    let nested = vec![2].into_iter().nested_shadow_counted(&mut parent);
    nested.commit().unwrap();

    assert_eq!(parent.supplement().commits.get(), 1);

    let nested2 = vec![3].into_iter().nested_shadow_counted(&mut parent);
    nested2.commit().unwrap();

    assert_eq!(parent.supplement().commits.get(), 2);
}

/// Test unit type default behavior
#[test]
fn test_unit_type_default() {
    let mut iter = vec![1, 2, 3].into_iter().shadow_counted();

    // supplement() returns &()
    let _ = iter.supplement();

    // supplement_mut() returns &mut ()
    let _ = iter.supplement_mut();

    for _ in iter.by_ref() {}
    assert_eq!(iter.counter(), 3);
}

/// Test Rc<T> supplemental data
#[test]
fn test_rc_supplement() {
    use std::rc::Rc;

    let data = Rc::new(vec![1, 2, 3]);
    let mut iter = ShadowCountedIter::new_with(vec![10, 20].into_iter(), data.clone());

    assert_eq!(iter.supplement().len(), 3);

    let nested = vec![30].into_iter().nested_shadow_counted(&mut iter);
    assert_eq!(nested.supplement().len(), 3);

    nested.commit().unwrap();
}

/// Test Arc<T> supplemental data
#[test]
fn test_arc_supplement() {
    use std::sync::Arc;

    let data = Arc::new(String::from("test"));
    let mut iter = ShadowCountedIter::new_with(vec![1].into_iter(), data.clone());

    assert_eq!(iter.supplement().as_str(), "test");

    let nested = vec![2].into_iter().nested_shadow_counted(&mut iter);
    assert_eq!(nested.supplement().as_str(), "test");

    nested.commit().unwrap();
}

/// Test supplemental data persists through iteration
#[test]
fn test_data_persists_through_iteration() {
    let mut iter =
        ShadowCountedIter::new_with(vec![1, 2, 3, 4, 5].into_iter(), TestData { value: 123 });

    for _ in 0..3 {
        iter.next();
        assert_eq!(iter.supplement().value, 123);
    }
}

/// Test multiple levels of nesting with data
#[test]
fn test_multilevel_nesting_with_data() {
    let mut level1 =
        ShadowCountedIter::new_with(vec![1].into_iter(), AccumulatingData { sum: Cell::new(1) });

    let mut level2 = vec![2].into_iter().nested_shadow_counted(&mut level1);
    let current = level2.supplement().sum.get();
    level2.supplement_mut().sum.set(current + 2); // Now sum = 3 (1 + 2)

    let mut level3 = vec![3].into_iter().nested_shadow_counted(&mut level2);
    let current = level3.supplement().sum.get();
    level3.supplement_mut().sum.set(current + 3); // Now sum = 6 (3 + 3)

    level3.commit().unwrap();
    assert_eq!(level2.supplement().sum.get(), 9); // 3 + 6 = 9

    level2.commit().unwrap();
    assert_eq!(level1.supplement().sum.get(), 10); // 1 + 9 = 10
}