pipecircuit 0.0.18

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::super::WarpTableRow;
use super::{
    MaintainedView, ObservedTable, ViewCreationError, ViewDefinition, ViewId, ViewRefreshError,
    ViewRevision,
};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CountPublication {
    pub through: ViewRevision,
    pub count: usize,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CountRefreshOutcome {
    Unchanged,
    Published(CountPublication),
}

/// Maintains membership internally and exposes only its cardinality.
/// A selector returns `Some(())` for membership and `None` for exclusion.
pub struct MaintainedCount<
    Row: WarpTableRow,
    Selection: ViewDefinition<Row, Value = ()>,
    Brand = Row,
> {
    membership: MaintainedView<Row, Selection, Brand>,
    published: CountPublication,
}

impl<Row: WarpTableRow, Brand> ObservedTable<Row, Brand> {
    pub fn maintain_count<Selection: ViewDefinition<Row, Value = ()>>(
        &self,
        id: ViewId,
        selection: Selection,
    ) -> Result<MaintainedCount<Row, Selection, Brand>, ViewCreationError> {
        let membership = self.maintain(id, selection)?;
        let published = CountPublication {
            through: membership.revision(),
            count: membership.len(),
        };
        Ok(MaintainedCount {
            membership,
            published,
        })
    }
}

impl<Row: WarpTableRow, Selection: ViewDefinition<Row, Value = ()>, Brand>
    MaintainedCount<Row, Selection, Brand>
{
    pub const fn publication(&self) -> CountPublication {
        self.published
    }

    pub fn refresh(
        &mut self,
        source: &ObservedTable<Row, Brand>,
    ) -> Result<CountRefreshOutcome, ViewRefreshError> {
        let Some(revision) = self.published.through.revision.checked_add(1) else {
            return Err(ViewRefreshError::RevisionExhausted);
        };
        self.membership.refresh(source)?;
        let count = self.membership.len();
        if count == self.published.count {
            return Ok(CountRefreshOutcome::Unchanged);
        }
        self.published.count = count;
        self.published.through.revision = revision;
        Ok(CountRefreshOutcome::Published(self.published))
    }

    pub fn replace_selection(
        &mut self,
        source: &ObservedTable<Row, Brand>,
        selection: Selection,
    ) -> Result<CountRefreshOutcome, (Selection, ViewRefreshError)> {
        self.membership.replace_definition(source, selection)?;
        self.published = CountPublication {
            through: self.membership.revision(),
            count: self.membership.len(),
        };
        Ok(CountRefreshOutcome::Published(self.published))
    }
}