pipecircuit 0.0.11

Correct. Robust. Fast. Portable.
Documentation
use alloc::vec::Vec;

use super::{SlotSet, SlotSetInsertError, SlotSetInsertOutcome, SlotSetRemoveOutcome, StableSlot};

#[test]
fn roaring_slots_preserve_sorted_membership() -> Result<(), &'static str> {
    let first = StableSlot::new(0);
    let mut set = SlotSet::one(first);
    for value in [65_537, 3, 4_096, 1] {
        let slot = StableSlot::new(value);
        assert_eq!(
            set.try_prepare_insert(slot)
                .map_err(|_| "slot insertion failed")?
                .commit(),
            SlotSetInsertOutcome::Inserted { slot }
        );
    }

    let collected = set.slots().map(StableSlot::value).collect::<Vec<_>>();
    assert_eq!(collected, [0, 1, 3, 4_096, 65_537]);
    assert_eq!(set.len(), 5);

    let mut slots = set.slots();
    assert_eq!(slots.size_hint(), (5, Some(5)));
    #[cfg(target_pointer_width = "64")]
    assert_eq!(slots.len(), 5);
    assert_eq!(slots.next(), Some(StableSlot::new(0)));
    assert_eq!(slots.next_back(), Some(StableSlot::new(65_537)));
    assert_eq!(slots.size_hint(), (3, Some(3)));
    #[cfg(target_pointer_width = "64")]
    assert_eq!(slots.len(), 3);
    assert_eq!(slots.by_ref().count(), 3);
    assert_eq!(slots.next(), None);
    assert_eq!(slots.next_back(), None);
    Ok(())
}

#[test]
fn abandoned_insertions_publish_nothing() -> Result<(), &'static str> {
    let mut set = SlotSet::one(StableSlot::new(0));
    {
        let prepared = set
            .try_prepare_insert(StableSlot::new(1))
            .map_err(|_| "preparation failed")?;
        assert_eq!(prepared.slot(), StableSlot::new(1));
    }
    assert!(!set.contains(StableSlot::new(1)));
    Ok(())
}

#[test]
fn duplicate_and_remove_outcomes_preserve_the_slot() -> Result<(), &'static str> {
    let slot = StableSlot::new(7);
    let mut set = SlotSet::one(slot);
    assert!(matches!(
        set.try_prepare_insert(slot),
        Err(SlotSetInsertError::AlreadyPresent { slot: duplicate }) if duplicate == slot
    ));
    assert_eq!(set.remove(slot), SlotSetRemoveOutcome::Removed { slot });
    assert!(set.is_empty());
    assert_eq!(set.remove(slot), SlotSetRemoveOutcome::Absent { slot });
    Ok(())
}

#[test]
fn set_algebra_composes_secondary_memberships() -> Result<(), &'static str> {
    let left = set([1, 2, 4])?;
    let right = set([2, 3, 4])?;

    assert_eq!(values(&left.union(&right)), [1, 2, 3, 4]);
    assert_eq!(values(&left.intersection(&right)), [2, 4]);
    assert_eq!(values(&left.excluding(&right)), [1]);
    assert_eq!(values(&left.union_excluding_overlap(&right)), [1, 3]);
    assert!(!left.is_disjoint(&right));
    assert!(left.intersection(&right).is_subset(&left));
    assert!(set([7])?.is_disjoint(&left));

    let mut assigned = set([1, 2, 4])?;
    assigned.union_assign(&right);
    assert_eq!(values(&assigned), [1, 2, 3, 4]);
    assigned = set([1, 2, 4])?;
    assigned.intersection_assign(&right);
    assert_eq!(values(&assigned), [2, 4]);
    assert_eq!(
        values(&set([1, 2, 4])?.intersection_reusing(&right)),
        [2, 4]
    );
    assert_eq!(
        values(&set([1, 2, 3, 4, 5])?.intersection_reusing(&set([2, 4])?)),
        [2, 4]
    );
    assert_eq!(
        values(&set([1, 2, 3, 4, 5])?.intersection_owned(set([2, 4])?)),
        [2, 4]
    );
    assigned = set([1, 2, 4])?;
    assigned.exclude_assign(&right);
    assert_eq!(values(&assigned), [1]);
    assigned = set([1, 2, 4])?;
    assigned.union_excluding_overlap_assign(&right);
    assert_eq!(values(&assigned), [1, 3]);
    Ok(())
}

fn set<const N: usize>(values: [u32; N]) -> Result<SlotSet, &'static str> {
    let Some((first, remaining)) = values.split_first() else {
        return Err("test set was empty");
    };
    let mut slots = SlotSet::one(StableSlot::new(*first));
    for value in remaining {
        let SlotSetInsertOutcome::Inserted { .. } = slots
            .try_prepare_insert(StableSlot::new(*value))
            .map_err(|_| "test slot was duplicated")?
            .commit();
    }
    Ok(slots)
}

fn values(slots: &SlotSet) -> Vec<u32> {
    slots.slots().map(StableSlot::value).collect()
}