pipecircuit 0.0.11

Correct. Robust. Fast. Portable.
Documentation
use super::{
    StableSlot, StableSlotInsertError, StableSlotRemoveOutcome, StableSlotResolveOutcome,
    StableSlotRowRelocation, StableSlots, StableSlotsInconsistency,
};
use crate::storage::warp_table::secondary_index::SlotSet;

#[test]
fn stable_slots_follow_dense_relocation_and_reuse() -> Result<(), &'static str> {
    let mut slots = StableSlots::try_new(3).map_err(|_| "slot storage unavailable")?;
    let first = slots
        .try_prepare_insert()
        .map_err(|_| "first slot unavailable")?
        .commit();
    let second = slots
        .try_prepare_insert()
        .map_err(|_| "second slot unavailable")?
        .commit();
    let third = slots
        .try_prepare_insert()
        .map_err(|_| "third slot unavailable")?
        .commit();

    assert_eq!(
        (first, second, third),
        (StableSlot::new(0), StableSlot::new(1), StableSlot::new(2))
    );
    {
        let prepared = slots
            .try_prepare_remove(1)
            .map_err(|_| "second slot removal unavailable")?;
        assert_eq!(prepared.slot(), second);
    }
    assert_eq!(
        slots.resolve(second),
        Ok(StableSlotResolveOutcome::Resolved {
            slot: second,
            dense_row: 1,
        })
    );
    assert_eq!(slots.slot(1), Ok(second));
    assert_eq!(
        slots
            .try_prepare_remove(1)
            .map_err(|_| "second slot removal unavailable")?
            .commit(),
        StableSlotRemoveOutcome::Removed {
            slot: second,
            relocation: StableSlotRowRelocation::Relocated {
                slot: third,
                from: 2,
                to: 1,
            },
        }
    );
    assert_eq!(
        slots.resolve(third),
        Ok(StableSlotResolveOutcome::Resolved {
            slot: third,
            dense_row: 1,
        })
    );
    assert_eq!(slots.slot(1), Ok(third));
    assert_eq!(
        slots.resolve_slots(&SlotSet::one(second)).next(),
        Some(Err(StableSlotsInconsistency::SlotVacant { slot: second }))
    );

    let retained = SlotSet::one(first).union(&SlotSet::one(third));
    let mut retained = slots.resolve_slots(&retained);
    assert_eq!(retained.size_hint(), (2, Some(2)));
    #[cfg(target_pointer_width = "64")]
    assert_eq!(retained.len(), 2);
    assert_eq!(
        retained.next_back(),
        Some(Ok(StableSlotResolveOutcome::Resolved {
            slot: third,
            dense_row: 1,
        }))
    );
    assert_eq!(
        retained.next(),
        Some(Ok(StableSlotResolveOutcome::Resolved {
            slot: first,
            dense_row: 0,
        }))
    );
    assert_eq!(retained.size_hint(), (0, Some(0)));
    #[cfg(target_pointer_width = "64")]
    assert_eq!(retained.len(), 0);
    assert_eq!(retained.next(), None);
    assert_eq!(retained.next_back(), None);

    let reused = slots
        .try_prepare_insert()
        .map_err(|_| "reused slot unavailable")?
        .commit();
    assert_eq!(reused, second);
    assert_eq!(
        slots.resolve(reused),
        Ok(StableSlotResolveOutcome::Resolved {
            slot: reused,
            dense_row: 2,
        })
    );
    assert_eq!(
        slots.try_prepare_insert().map(|prepared| prepared.slot()),
        Err(StableSlotInsertError::Full { maximum_rows: 3 })
    );
    assert_eq!(
        slots.remove(2),
        Ok(StableSlotRemoveOutcome::Removed {
            slot: reused,
            relocation: StableSlotRowRelocation::Stable,
        })
    );
    assert_eq!(
        slots.resolve(reused),
        Err(StableSlotsInconsistency::SlotVacant { slot: reused })
    );
    Ok(())
}

#[test]
fn abandoned_preparation_publishes_nothing() -> Result<(), &'static str> {
    let mut slots = StableSlots::try_new(1).map_err(|_| "slot storage unavailable")?;
    let reserved = {
        let prepared = slots
            .try_prepare_insert()
            .map_err(|_| "prepared slot unavailable")?;
        prepared.slot()
    };

    let committed = slots
        .try_prepare_insert()
        .map_err(|_| "slot changed after abandonment")?
        .commit();
    assert_eq!(committed, reserved);
    assert_eq!(
        slots.resolve(committed),
        Ok(StableSlotResolveOutcome::Resolved {
            slot: committed,
            dense_row: 0,
        })
    );
    Ok(())
}