pipecircuit 0.0.14

Correct. Robust. Fast. Portable.
Documentation
use super::dense_key_index::FindOutcome;
use super::inconsistency::invariant_violation;
use super::{
    UniqueIndexInconsistency, UniqueIndexLookupOutcome, WarpTable, WarpTableInconsistency,
    WarpTableRow, WarpTableRowGetOutcome,
};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableUpdateOutcome<Id, Output> {
    Updated { id: Id, row: usize, output: Output },
    Absent { id: Id },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableUpdateWithOutcome<Id, Context, Output> {
    Updated { id: Id, row: usize, output: Output },
    Absent { id: Id, context: Context },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableUniqueUpdateOutcome<Key, Id, Output> {
    Updated {
        key: Key,
        id: Id,
        row: usize,
        output: Output,
    },
    Absent {
        key: Key,
    },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub enum WarpTableUniqueUpdateWithOutcome<Key, Id, Context, Output> {
    Updated {
        key: Key,
        id: Id,
        row: usize,
        output: Output,
    },
    Absent {
        key: Key,
        context: Context,
    },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum WarpTableUniqueUpdateWithError<Key, Context> {
    Inconsistent {
        key: Key,
        context: Context,
        reason: UniqueIndexInconsistency,
    },
}

impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
    pub fn update<'table, Output>(
        &'table mut self,
        id: Row::Id,
        update: impl FnOnce(Row::Mut<'table>) -> Output,
    ) -> WarpTableUpdateOutcome<Row::Id, Output>
    where
        Row: 'table,
    {
        match self.update_with(id, (), |row, ()| update(row)) {
            WarpTableUpdateWithOutcome::Updated { id, row, output } => {
                WarpTableUpdateOutcome::Updated { id, row, output }
            }
            WarpTableUpdateWithOutcome::Absent { id, .. } => WarpTableUpdateOutcome::Absent { id },
        }
    }

    pub fn update_with<'table, Context, Output>(
        &'table mut self,
        id: Row::Id,
        context: Context,
        update: impl FnOnce(Row::Mut<'table>, Context) -> Output,
    ) -> WarpTableUpdateWithOutcome<Row::Id, Context, Output>
    where
        Row: 'table,
    {
        if self.ids.len() != self.len {
            invariant_violation(WarpTableInconsistency::IdColumnLengthMismatch {
                ids: self.ids.len(),
                rows: self.len,
            });
        }
        let row = match self.primary_index.find(id, &self.ids) {
            Ok(FindOutcome::Present { row, .. }) => row,
            Ok(FindOutcome::Absent) => {
                return WarpTableUpdateWithOutcome::Absent { id, context };
            }
            Err(reason) => invariant_violation(WarpTableInconsistency::from(reason)),
        };
        let output = self.update_at(row, |mutable| update(mutable, context));
        WarpTableUpdateWithOutcome::Updated { id, row, output }
    }

    pub(super) fn update_at<'table, Output>(
        &'table mut self,
        row: usize,
        update: impl FnOnce(Row::Mut<'table>) -> Output,
    ) -> Output
    where
        Row: 'table,
    {
        let stored_id = self
            .ids
            .get(row)
            .unwrap_or_else(|| invariant_violation(WarpTableInconsistency::IdUnavailable { row }));
        let WarpTableRowGetOutcome::Present { row: mutable } =
            Row::get_mut(stored_id, &mut self.columns, &mut self.indexes, row)
                .unwrap_or_else(|reason| invariant_violation(WarpTableInconsistency::from(reason)));
        update(mutable)
    }
}

#[doc(hidden)]
pub fn bind_unique_update<'table, Row, Brand, Key, Output>(
    table: &'table mut WarpTable<Row, Brand>,
    lookup: UniqueIndexLookupOutcome<Key>,
    update: impl FnOnce(Row::Mut<'table>) -> Output,
) -> WarpTableUniqueUpdateOutcome<Key, Row::Id, Output>
where
    Row: WarpTableRow + 'table,
{
    match bind_unique_update_with(table, lookup, (), |row, ()| update(row)) {
        WarpTableUniqueUpdateWithOutcome::Updated {
            key,
            id,
            row,
            output,
        } => WarpTableUniqueUpdateOutcome::Updated {
            key,
            id,
            row,
            output,
        },
        WarpTableUniqueUpdateWithOutcome::Absent { key, .. } => {
            WarpTableUniqueUpdateOutcome::Absent { key }
        }
    }
}

#[doc(hidden)]
pub fn bind_unique_update_with<'table, Row, Brand, Key, Context, Output>(
    table: &'table mut WarpTable<Row, Brand>,
    lookup: UniqueIndexLookupOutcome<Key>,
    context: Context,
    update: impl FnOnce(Row::Mut<'table>, Context) -> Output,
) -> WarpTableUniqueUpdateWithOutcome<Key, Row::Id, Context, Output>
where
    Row: WarpTableRow + 'table,
{
    let (key, row) = match lookup {
        UniqueIndexLookupOutcome::Present { key, row } => (key, row),
        UniqueIndexLookupOutcome::Absent { key } => {
            return WarpTableUniqueUpdateWithOutcome::Absent { key, context };
        }
    };
    if table.ids.len() != table.len {
        invariant_violation(WarpTableInconsistency::IdColumnLengthMismatch {
            ids: table.ids.len(),
            rows: table.len,
        });
    }
    let id = *table
        .ids
        .get(row)
        .unwrap_or_else(|| invariant_violation(WarpTableInconsistency::IdUnavailable { row }));
    let output = table.update_at(row, |mutable| update(mutable, context));
    WarpTableUniqueUpdateWithOutcome::Updated {
        key,
        id,
        row,
        output,
    }
}