use std::{collections::VecDeque, fmt};
use crate::{action, common::error::RecoverableError, item, record::Records, transaction};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Transactions<Action> {
transactions: VecDeque<Transaction<Action>>,
start_id: transaction::Id,
}
impl<Action> Default for Transactions<Action> {
fn default() -> Self {
Self::new(transaction::Id::new(0))
}
}
impl<Action> Transactions<Action> {
pub(crate) fn new(start_id: transaction::Id) -> Self {
Self {
transactions: Default::default(),
start_id,
}
}
pub(crate) fn into_iter(
self,
) -> impl DoubleEndedIterator<Item = transaction::Confirmed<Action>> {
self.transactions
.into_iter()
.enumerate()
.map(move |(i, tx)| {
transaction::Confirmed::new(
transaction::Id::new(self.start_id.get() + i as u32),
tx,
)
})
}
pub fn next_id(&self) -> transaction::Id {
transaction::Id::new(self.start_id.0 + self.transactions.len() as u32)
}
pub(crate) fn get(&self, id: transaction::Id) -> Option<&Transaction<Action>> {
if let Some(index) = id.index_of(&self.start_id) {
self.transactions.get(index)
} else {
None
}
}
pub(crate) fn push_back(&mut self, transaction: Transaction<Action>) -> transaction::Id {
let id = self.next_id();
self.transactions.push_back(transaction);
id
}
pub(crate) fn trim_start(&mut self, id: transaction::Id) {
if let Some(mut diff) = id.index_of(&self.start_id) {
diff = diff.min(self.transactions.len());
self.transactions.drain(diff..);
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub(crate) struct Transaction<Action> {
records: Records<Action>,
}
impl<Action> Transaction<Action> {
pub(crate) fn new(records: Records<Action>) -> Self {
Self { records }
}
pub(crate) fn apply<Storage>(
&self,
storage: &mut Storage,
) -> action::Result<Transaction<Action>>
where
Storage: item::Storage,
Action: crate::Action<State = Storage::State>,
{
let undo_records = self.records.apply(storage)?;
Ok(Transaction {
records: undo_records,
})
}
pub(crate) fn apply_or_revert<Storage>(
&self,
storage: &mut Storage,
) -> Result<Transaction<Action>, RecoverableError<action::Error>>
where
Storage: item::Storage,
Action: crate::Action<State = Storage::State>,
{
let undo_records = self.records.apply_or_revert(storage)?;
Ok(Transaction {
records: undo_records,
})
}
pub(crate) fn records(&self) -> &Records<Action> {
&self.records
}
pub(crate) fn into_records(self) -> Records<Action> {
self.records
}
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
pub(crate) struct Id(u32);
impl Id {
pub(crate) fn new(index: u32) -> Self {
Self(index)
}
pub(crate) const ZERO: Self = Self(0);
pub(crate) fn get(&self) -> u32 {
self.0
}
pub(crate) fn index_of(&self, start_id: &Self) -> Option<usize> {
self.0.checked_sub(start_id.0).map(|i| i as usize)
}
pub(crate) fn next(&self) -> Self {
Self::new(self.get() + 1)
}
pub(crate) fn into_u32(self) -> u32 {
self.0
}
}
impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "t{}", self.0)
}
}
pub(crate) mod id {
#[derive(Debug, thiserror::Error)]
#[error("Transaction {0} does not exist")]
pub(crate) struct InvalidError(pub(crate) super::Id);
#[derive(Debug, thiserror::Error)]
#[error("Expected transaction {expected} but received {actual}")]
pub(crate) struct MismatchError {
pub(crate) expected: super::Id,
pub(crate) actual: super::Id,
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Confirmed<Action> {
pub id: transaction::Id,
pub transaction: Transaction<Action>,
}
impl<Action> Confirmed<Action> {
pub(crate) fn new(id: transaction::Id, transaction: Transaction<Action>) -> Self {
Self { id, transaction }
}
}