use super::super::{Capacity, IndexKey, WarpTable, WarpTableRow};
use super::view::creation_error;
use super::{ViewChange, ViewColumnStorageError, ViewCreationError};
use alloc::{collections::VecDeque, vec::Vec};
pub(super) struct Previous<Id, Value> {
pub revision: u64,
pub id: Id,
pub before: Option<(u64, Value)>,
}
pub(super) struct RetainedChanges<Id, Value> {
pub entries: VecDeque<Previous<Id, Value>>,
pub capacity: Capacity,
pub maximum_changes: usize,
pub discarded_through: u64,
}
impl<Id, Value> RetainedChanges<Id, Value> {
pub fn try_new(capacity: Capacity) -> Result<Self, ViewCreationError> {
let maximum_changes = usize::try_from(capacity.value().get())
.map_err(|_| ViewCreationError::CapacityOverflow)?;
let mut entries = VecDeque::new();
entries
.try_reserve_exact(maximum_changes)
.map_err(ViewCreationError::StorageUnavailable)?;
Ok(Self {
entries,
capacity,
maximum_changes,
discarded_through: 0,
})
}
pub fn reset(&mut self, through: u64) {
self.entries.clear();
self.discarded_through = through;
}
pub fn push(&mut self, change: Previous<Id, Value>) {
if self.entries.len() == self.maximum_changes
&& let Some(discarded) = self.entries.pop_front()
{
self.discarded_through = discarded.revision;
}
self.entries.push_back(change);
}
}
#[derive(WarpTableRow)]
#[index(primary = Id)]
pub(super) struct FirstChange<Id: IndexKey> {
pub index: usize,
pub marker: core::marker::PhantomData<Id>,
}
pub struct ViewDeliveryBuffer<Id: IndexKey, Value> {
pub(super) first: WarpTable<FirstChange<Id>>,
pub(super) changes: Vec<ViewChange<Id, Value>>,
pub(super) maximum_rows: usize,
pub(super) maximum_history: usize,
}
impl<Id: IndexKey, Value> ViewDeliveryBuffer<Id, Value> {
pub(super) fn try_new(rows: Capacity, history: Capacity) -> Result<Self, ViewCreationError> {
let first = WarpTable::try_new(history).map_err(|error| {
creation_error(
error,
|FirstChangeColumnsCreationError::StorageUnavailable { column, source }| {
ViewColumnStorageError { column, source }
},
|never| match never {},
)
})?;
let maximum_rows =
usize::try_from(rows.value().get()).map_err(|_| ViewCreationError::CapacityOverflow)?;
let maximum_history = usize::try_from(history.value().get())
.map_err(|_| ViewCreationError::CapacityOverflow)?;
let maximum_changes = maximum_rows
.checked_mul(2)
.ok_or(ViewCreationError::CapacityOverflow)?;
let mut changes = Vec::new();
changes
.try_reserve_exact(maximum_changes)
.map_err(ViewCreationError::StorageUnavailable)?;
Ok(Self {
first,
changes,
maximum_rows,
maximum_history,
})
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ViewDeliveryError {
WrongView,
FutureCursor,
InsufficientBuffer,
}
pub struct ViewSubscription {
pub(super) source: super::SourceId,
pub(super) view: super::ViewId,
pub(super) cursor: Option<super::ViewRevision>,
}
impl ViewSubscription {
pub const fn admitted_through(&self) -> Option<super::ViewRevision> {
self.cursor
}
pub fn require_baseline(&mut self) {
self.cursor = None;
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ViewAdmission {
Admitted,
Backpressured,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ViewTransmitOutcome {
Current { through: super::ViewRevision },
Admitted { through: super::ViewRevision },
Backpressured { through: super::ViewRevision },
}
#[derive(Debug, Eq, PartialEq)]
pub enum ViewTransmitError<TransportError> {
Preparation(ViewDeliveryError),
Transport(TransportError),
}