pipecircuit 0.0.15

Correct. Robust. Fast. Portable.
Documentation
use super::{SlotSet, StableSlot};

#[derive(Debug)]
pub enum SlotSetInsertError {
    AlreadyPresent { slot: StableSlot },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum SlotSetInsertOutcome {
    Inserted { slot: StableSlot },
}

impl SlotSet {
    pub fn try_prepare_insert(
        &mut self,
        slot: StableSlot,
    ) -> Result<PreparedSlotSetInsert<'_>, SlotSetInsertError> {
        let insertion = self.try_apply_insert(slot)?;
        Ok(PreparedSlotSetInsert {
            set: self,
            insertion: Some(insertion),
            slot,
        })
    }

    pub(in crate::storage::warp_table::secondary_index) fn try_apply_insert(
        &mut self,
        slot: StableSlot,
    ) -> Result<AppliedSlotSetInsert, SlotSetInsertError> {
        if !self.0.insert(slot.value()) {
            return Err(SlotSetInsertError::AlreadyPresent { slot });
        }
        Ok(AppliedSlotSetInsert)
    }
}

pub(in crate::storage::warp_table::secondary_index) struct AppliedSlotSetInsert;

impl AppliedSlotSetInsert {
    pub(in crate::storage::warp_table::secondary_index) fn commit(self) {}

    pub(in crate::storage::warp_table::secondary_index) fn rollback(
        self,
        set: &mut SlotSet,
        slot: StableSlot,
    ) {
        match set.remove(slot) {
            super::SlotSetRemoveOutcome::Removed { .. }
            | super::SlotSetRemoveOutcome::Absent { .. } => {}
        }
    }
}

pub struct PreparedSlotSetInsert<'set> {
    set: &'set mut SlotSet,
    insertion: Option<AppliedSlotSetInsert>,
    slot: StableSlot,
}

impl PreparedSlotSetInsert<'_> {
    pub const fn slot(&self) -> StableSlot {
        self.slot
    }

    pub fn commit(mut self) -> SlotSetInsertOutcome {
        if let Some(insertion) = self.insertion.take() {
            insertion.commit();
        }
        SlotSetInsertOutcome::Inserted { slot: self.slot }
    }
}

impl Drop for PreparedSlotSetInsert<'_> {
    fn drop(&mut self) {
        if let Some(insertion) = self.insertion.take() {
            insertion.rollback(self.set, self.slot);
        }
    }
}