pipecircuit 0.0.18

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::super::dense_key_index::{CommitOutcome, PrepareInsertOutcome, PreparedCommit};
use super::{IndexKey, UniqueIndex, UniqueIndexInconsistency};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum UniqueIndexInsertError<Key> {
    AlreadyPresent {
        key: Key,
        existing_row: usize,
    },
    Full {
        key: Key,
        maximum_keys: usize,
    },
    Inconsistent {
        key: Key,
        reason: UniqueIndexInconsistency,
    },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum UniqueIndexInsertOutcome<Key> {
    Inserted { key: Key, row: usize },
}

pub struct PreparedUniqueIndexInsert<'index, Key: IndexKey> {
    index: &'index mut UniqueIndex<Key>,
    insertion: PreparedCommit,
    key: Key,
}

impl<Key: IndexKey> UniqueIndex<Key> {
    pub fn try_prepare_insert(
        &mut self,
        key: Key,
    ) -> Result<PreparedUniqueIndexInsert<'_, Key>, UniqueIndexInsertError<Key>> {
        let vacancy = match self
            .key_index
            .prepare_insert(key, &self.keys)
            .map_err(|reason| UniqueIndexInsertError::Inconsistent {
                key,
                reason: reason.into(),
            })? {
            PrepareInsertOutcome::Vacant(vacancy) => vacancy,
            PrepareInsertOutcome::Present { row } => {
                return Err(UniqueIndexInsertError::AlreadyPresent {
                    key,
                    existing_row: row,
                });
            }
        };
        if self.keys.len() >= self.maximum_keys {
            return Err(UniqueIndexInsertError::Full {
                key,
                maximum_keys: self.maximum_keys,
            });
        }
        let row = self.keys.len();
        let insertion = self
            .key_index
            .prepare_commit(vacancy, row)
            .map_err(|reason| UniqueIndexInsertError::Inconsistent {
                key,
                reason: reason.into(),
            })?;
        Ok(PreparedUniqueIndexInsert {
            index: self,
            insertion,
            key,
        })
    }
}

impl<Key: IndexKey> PreparedUniqueIndexInsert<'_, Key> {
    pub fn commit(self) -> UniqueIndexInsertOutcome<Key> {
        let CommitOutcome::Committed { row } = self.index.key_index.commit_prepared(self.insertion);
        self.index.keys.push(self.key);
        UniqueIndexInsertOutcome::Inserted { key: self.key, row }
    }
}