use crate::Value;
pub struct Cell<V: Value> {
pub(crate) revert: EbrCell<Option<V>>,
pub(crate) blocks: EbrCell<V>,
}
impl<V: Value> Cell<V> {
pub fn new(v: V) -> Self {
Self {
revert: EbrCell::new(None),
blocks: EbrCell::new(v),
}
}
pub fn view(&self) -> View<'_, V> {
View {
blocks: self.blocks.read(),
_marker: core::marker::PhantomData,
}
}
pub fn block(&self) -> Block<'_, V> {
let mut revert = self.revert.write();
let blocks = self.blocks.write();
*revert.get_mut() = None;
Block { revert, blocks }
}
pub fn block_and_revert(&self) -> Block<'_, V> {
let mut revert = self.revert.write();
let mut blocks = self.blocks.write();
{
let revert = core::mem::take(revert.get_mut());
if let Some(revert) = revert {
*blocks.get_mut() = revert;
}
}
Block { revert, blocks }
}
}
impl<V: Value + Default> Default for Cell<V> {
fn default() -> Self {
Self::new(V::default())
}
}
mod view {
use std::ops::Deref;
use concread::ebrcell::EbrCellReadTxn;
use super::*;
pub struct View<'storage, V: Value> {
pub(crate) blocks: EbrCellReadTxn<V>,
pub(crate) _marker: core::marker::PhantomData<&'storage V>,
}
impl<V: Value> View<'_, V> {
pub fn get(&self) -> &V {
&self.blocks
}
}
impl<V: Value> Deref for View<'_, V> {
type Target = V;
fn deref(&self) -> &Self::Target {
self.get()
}
}
}
use concread::EbrCell;
pub use view::View;
mod block {
use std::ops::{Deref, DerefMut};
use concread::ebrcell::EbrCellWriteTxn;
use super::*;
pub struct Block<'storage, V: Value> {
pub(crate) revert: EbrCellWriteTxn<'storage, Option<V>>,
pub(crate) blocks: EbrCellWriteTxn<'storage, V>,
}
impl<'storage, V: Value> Block<'storage, V> {
pub fn transaction<'block>(&'block mut self) -> Transaction<'block, 'storage, V>
where
'storage: 'block,
{
Transaction {
block: self,
revert: None,
}
}
pub fn commit(self) {
self.blocks.commit();
self.revert.commit();
}
pub fn get_mut(&mut self) -> &mut V {
let value = self.blocks.get_mut();
self.revert.get_or_insert(value.clone());
value
}
pub fn get(&self) -> &V {
&self.blocks
}
}
impl<V: Value> Deref for Block<'_, V> {
type Target = V;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl<V: Value> DerefMut for Block<'_, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_mut()
}
}
pub struct Transaction<'block, 'storage, V: Value> {
pub(crate) revert: Option<V>,
pub(crate) block: &'block mut Block<'storage, V>,
}
impl<'block, 'storage: 'block, V: Value> Transaction<'block, 'storage, V> {
pub fn apply(mut self) {
if let Some(prev_value) = core::mem::take(&mut self.revert) {
self.block.revert.get_or_insert(prev_value);
}
}
pub fn get_mut(&mut self) -> &mut V {
let value = self.block.blocks.get_mut();
self.revert.get_or_insert(value.clone());
value
}
pub fn get(&self) -> &V {
&self.block.blocks
}
}
impl<'block, 'store: 'block, V: Value> Drop for Transaction<'block, 'store, V> {
fn drop(&mut self) {
if let Some(prev_value) = core::mem::take(&mut self.revert) {
*self.block.blocks.get_mut() = prev_value;
}
}
}
impl<V: Value> Deref for Transaction<'_, '_, V> {
type Target = V;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl<V: Value> DerefMut for Transaction<'_, '_, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_mut()
}
}
}
pub use block::{Block, Transaction};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get() {
let cell = Cell::new(0_u64);
let view0 = cell.view();
{
let mut block = cell.block();
*block.get_mut() = 1;
block.commit()
}
let view1 = cell.view();
{
let mut block = cell.block();
*block.get_mut() = 2;
block.commit()
}
let view2 = cell.view();
{
let mut block = cell.block();
*block.get_mut() = 3;
block.commit()
}
let view3 = cell.view();
assert_eq!(view0.get(), &0);
assert_eq!(view1.get(), &1);
assert_eq!(view2.get(), &2);
assert_eq!(view3.get(), &3);
}
#[test]
fn transaction_step() {
let cell = Cell::new(0_u64);
let mut block = cell.block();
{
let mut transaction = block.transaction();
*transaction.get_mut() = 1;
transaction.apply();
}
{
let mut transaction = block.transaction();
*transaction.get_mut() = 2;
}
{
let transaction = block.transaction();
assert_eq!(transaction.get(), &1);
}
block.commit();
{
let view = cell.view();
assert_eq!(view.get(), &1);
}
}
#[test]
fn revert() {
let cell = Cell::new(0_u64);
{
let mut block = cell.block();
*block.get_mut() = 1;
block.commit()
}
{
let mut block = cell.block();
*block.get_mut() = 2;
block.commit()
}
let view1 = cell.view();
{
let block = cell.block_and_revert();
block.commit();
}
let view2 = cell.view();
assert_eq!(view1.get(), &2);
assert_eq!(view2.get(), &1);
}
}