#[allow(unused_imports)]
#[macro_use]
extern crate contrail_derive;
#[doc(hidden)]
pub use contrail_derive::*;
pub mod mem;
pub mod storage;
use std::{fmt, marker::PhantomData};
use crate::{
mem::{ArrayPointer, Bytes, Memory, MemoryBuilder, Pointer},
storage::{Backtrackable, NonBacktrackable, StorageMode},
};
pub struct Trail {
backtrackable_mem: Memory,
non_backtrackable_mem: Memory,
trail: Vec<Memory>,
}
impl Trail {
pub fn new_level(&mut self) {
self.trail.push(self.backtrackable_mem.clone());
}
pub fn backtrack(&mut self) {
if let Some(prev) = self.trail.pop() {
self.backtrackable_mem = prev;
}
}
pub fn trail_len(&self) -> usize {
self.trail.len()
}
pub fn is_trail_empty(&self) -> bool {
self.trail.is_empty()
}
}
#[derive(Debug, Default)]
pub struct TrailBuilder {
backtrackable_mem: MemoryBuilder,
non_backtrackable_mem: MemoryBuilder,
}
impl TrailBuilder {
pub fn new() -> Self {
Self {
backtrackable_mem: MemoryBuilder::new(),
non_backtrackable_mem: MemoryBuilder::new(),
}
}
pub fn finish(self) -> Trail {
Trail {
backtrackable_mem: self.backtrackable_mem.finish(),
non_backtrackable_mem: self.non_backtrackable_mem.finish(),
trail: vec![],
}
}
}
pub struct Value<M, T> {
pointer: Pointer<T>,
phantom: PhantomData<M>,
}
impl<M, T> Value<M, T>
where
M: StorageMode,
T: Bytes,
{
pub fn new(builder: &mut TrailBuilder, val: T) -> Self {
Self {
pointer: Pointer::new(M::builder_mut(builder), val),
phantom: PhantomData,
}
}
#[inline]
pub fn get(self, trail: &Trail) -> T {
self.pointer.get(M::memory(trail))
}
#[inline]
pub fn set(self, trail: &mut Trail, new_val: T) {
self.pointer.set(M::memory_mut(trail), new_val);
}
#[inline]
pub fn update(self, trail: &mut Trail, f: impl FnOnce(T) -> T) {
self.pointer.update(M::memory_mut(trail), f);
}
}
impl<M, T> Clone for Value<M, T> {
fn clone(&self) -> Self {
Self {
pointer: self.pointer,
phantom: PhantomData,
}
}
}
impl<M, T> Copy for Value<M, T> {}
impl<M, T> fmt::Debug for Value<M, T>
where
M: StorageMode,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Value")
.field("pointer", &self.pointer)
.field("storage_mode", &M::default())
.finish()
}
}
impl<M, T> Eq for Value<M, T> {}
impl<M, T> PartialEq for Value<M, T> {
fn eq(&self, other: &Self) -> bool {
self.pointer == other.pointer
}
}
pub struct Array<M, T> {
pointer: ArrayPointer<T>,
phantom: PhantomData<M>,
}
impl<M, T> Array<M, T>
where
M: StorageMode,
T: Bytes,
{
pub fn new(builder: &mut TrailBuilder, vals: impl IntoIterator<Item = T>) -> Self {
Self {
pointer: ArrayPointer::new(
M::builder_mut(builder),
&vals.into_iter().collect::<Vec<_>>(),
),
phantom: PhantomData,
}
}
#[inline]
pub fn len(&self) -> usize {
self.pointer.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.pointer.len() == 0
}
pub fn iter<'t>(&self, trail: &'t Trail) -> ArrayIter<'t, M, T> {
ArrayIter {
trail,
index: 0,
array: *self,
}
}
#[inline]
pub fn get(&self, trail: &Trail, i: usize) -> T {
self.pointer.get(M::memory(trail), i)
}
#[inline]
pub fn set(&self, trail: &mut Trail, i: usize, new_val: T) {
self.pointer.set(M::memory_mut(trail), i, new_val);
}
#[inline]
pub fn update(&self, trail: &mut Trail, i: usize, f: impl FnOnce(T) -> T) {
self.pointer.update(M::memory_mut(trail), i, f);
}
#[inline]
pub fn swap(&self, trail: &mut Trail, i: usize, j: usize) {
self.pointer.swap(M::memory_mut(trail), i, j);
}
}
impl<M, T> Clone for Array<M, T> {
fn clone(&self) -> Self {
Self {
pointer: self.pointer,
phantom: PhantomData,
}
}
}
impl<M, T> Copy for Array<M, T> {}
impl<M, T> fmt::Debug for Array<M, T>
where
M: StorageMode,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Array")
.field("pointer", &self.pointer)
.field("storage_mode", &M::default())
.finish()
}
}
impl<M, T> Eq for Array<M, T> {}
impl<M, T> PartialEq for Array<M, T> {
fn eq(&self, other: &Self) -> bool {
self.pointer == other.pointer
}
}
pub struct ArrayIter<'t, M, T> {
trail: &'t Trail,
index: usize,
array: Array<M, T>,
}
impl<'t, M, T> Iterator for ArrayIter<'t, M, T>
where
M: StorageMode,
T: Bytes,
{
type Item = T;
fn next(&mut self) -> Option<T> {
if self.index == self.array.len() {
None
} else {
let to_ret = Some(self.array.get(self.trail, self.index));
self.index += 1;
to_ret
}
}
}
pub type BacktrackableValue<T> = Value<Backtrackable, T>;
pub type NonBacktrackableValue<T> = Value<NonBacktrackable, T>;
pub type BacktrackableArray<T> = Array<Backtrackable, T>;
pub type NonBacktrackableArray<T> = Array<NonBacktrackable, T>;
#[cfg(test)]
mod tests {
use super::*;
mod value {
use super::*;
#[test]
fn debug() {
let mut builder = TrailBuilder::new();
let backtrackable = BacktrackableValue::new(&mut builder, 42);
let non_backtrackable = NonBacktrackableValue::new(&mut builder, 42);
assert_eq!(
format!("{:?}", backtrackable),
"Value { pointer: Pointer { offset: 0 }, storage_mode: Backtrackable }"
);
assert_eq!(
format!("{:?}", non_backtrackable),
"Value { pointer: Pointer { offset: 0 }, storage_mode: NonBacktrackable }"
);
}
#[test]
fn clone_eq() {
let mut builder = TrailBuilder::new();
let value = BacktrackableValue::new(&mut builder, -1);
assert_eq!(value, value.clone());
}
#[test]
fn get_set_roundtrip() {
let init_val = 5;
let new_val = 6;
let mut builder = TrailBuilder::new();
let backtrackable = BacktrackableValue::new(&mut builder, init_val);
let non_backtrackable = NonBacktrackableValue::new(&mut builder, init_val);
let mut trail = builder.finish();
assert_eq!(trail.trail_len(), 0);
assert!(trail.is_trail_empty());
assert_eq!(backtrackable.get(&trail), init_val);
assert_eq!(non_backtrackable.get(&trail), init_val);
trail.new_level();
assert_eq!(trail.trail_len(), 1);
assert!(!trail.is_trail_empty());
assert_eq!(backtrackable.get(&trail), init_val);
assert_eq!(non_backtrackable.get(&trail), init_val);
backtrackable.set(&mut trail, new_val);
non_backtrackable.set(&mut trail, new_val);
assert_eq!(backtrackable.get(&trail), new_val);
assert_eq!(non_backtrackable.get(&trail), new_val);
trail.backtrack();
assert_eq!(trail.trail_len(), 0);
assert!(trail.is_trail_empty());
assert_eq!(backtrackable.get(&trail), init_val);
assert_eq!(non_backtrackable.get(&trail), new_val);
}
#[test]
fn update() {
let mut builder = TrailBuilder::new();
let value = BacktrackableValue::new(&mut builder, 0);
let mut trail = builder.finish();
assert_eq!(value.get(&trail), 0);
value.update(&mut trail, |x| x + 1);
assert_eq!(value.get(&trail), 1);
}
}
mod array {
use super::*;
#[test]
fn debug() {
let mut builder = TrailBuilder::new();
let backtrackable = BacktrackableArray::new(&mut builder, vec![1, 2, 3, 4]);
let non_backtrackable = NonBacktrackableArray::new(&mut builder, vec![1, 2, 3, 4]);
assert_eq!(
format!("{:?}", backtrackable),
"Array { pointer: ArrayPointer { offset: 0, len: 4 }, storage_mode: Backtrackable }"
);
assert_eq!(
format!("{:?}", non_backtrackable),
"Array { pointer: ArrayPointer { offset: 0, len: 4 }, storage_mode: NonBacktrackable }"
);
}
#[test]
fn clone_eq() {
let mut builder = TrailBuilder::new();
let array = BacktrackableArray::new(&mut builder, 0..10);
assert_eq!(array, array.clone());
}
#[test]
fn get_set_roundtrip() {
let init_vals = vec![1, 3, 5, 7];
let new_vals = vec![2, 4, 6, 8];
let mut builder = TrailBuilder::new();
let backtrackable = BacktrackableArray::new(&mut builder, init_vals.clone());
let stored = NonBacktrackableArray::new(&mut builder, init_vals.clone());
let mut trail = builder.finish();
assert_eq!(trail.trail_len(), 0);
assert!(trail.is_trail_empty());
for i in 0..4 {
assert_eq!(backtrackable.get(&trail, i), init_vals[i]);
assert_eq!(stored.get(&trail, i), init_vals[i]);
trail.new_level();
assert_eq!(trail.trail_len(), 1);
assert!(!trail.is_trail_empty());
assert_eq!(backtrackable.get(&trail, i), init_vals[i]);
assert_eq!(stored.get(&trail, i), init_vals[i]);
backtrackable.set(&mut trail, i, new_vals[i]);
stored.set(&mut trail, i, new_vals[i]);
assert_eq!(backtrackable.get(&trail, i), new_vals[i]);
assert_eq!(stored.get(&trail, i), new_vals[i]);
trail.backtrack();
assert_eq!(trail.trail_len(), 0);
assert!(trail.is_trail_empty());
assert_eq!(backtrackable.get(&trail, i), init_vals[i]);
assert_eq!(stored.get(&trail, i), new_vals[i]);
}
}
#[test]
fn update() {
let mut builder = TrailBuilder::new();
let array = BacktrackableArray::new(&mut builder, 0..10);
let mut trail = builder.finish();
assert_eq!(array.get(&trail, 5), 5);
array.update(&mut trail, 5, |x| x * 2);
assert_eq!(array.get(&trail, 5), 10);
}
#[test]
fn iter() {
let vals = vec![1, 3, 5, 7, 9];
let mut builder = TrailBuilder::new();
let array = BacktrackableArray::new(&mut builder, vals.clone());
let trail = builder.finish();
let iter_vals = array.iter(&trail).collect::<Vec<_>>();
assert_eq!(iter_vals, vals);
}
#[test]
fn empty() {
let mut builder = TrailBuilder::new();
let empty = BacktrackableArray::new(&mut builder, 0..0);
let not_empty = BacktrackableArray::new(&mut builder, 0..1);
assert_eq!(empty.len(), 0);
assert!(empty.is_empty());
assert_eq!(not_empty.len(), 1);
assert!(!not_empty.is_empty());
}
#[test]
fn swap() {
let mut builder = TrailBuilder::new();
let array = BacktrackableArray::new(&mut builder, vec![-1, 1]);
let mut trail = builder.finish();
assert_eq!(array.get(&mut trail, 0), -1);
assert_eq!(array.get(&mut trail, 1), 1);
array.swap(&mut trail, 0, 1);
assert_eq!(array.get(&mut trail, 0), 1);
assert_eq!(array.get(&mut trail, 1), -1);
}
}
}