mergable 0.43.0

A library for user-friendly and efficient CRDTs.
Documentation
pub struct Cell<T, Seq> {
	sequence: Seq,
	value: T,
}

impl<T, SequenceFactory: crate::SequenceFactory> Cell<T, crate::Sequence<SequenceFactory>> {
	pub fn new(ctx: &mut crate::Context<SequenceFactory>, value: T) -> Self {
		Cell {
			sequence: ctx.next_sequence(),
			value,
		}
	}

	pub fn set(&mut self, ctx: &mut crate::Context<SequenceFactory>, value: T) {
		*self.borrow_mut(ctx) = value;
	}

	pub fn last_modified(&self) -> &crate::Sequence<SequenceFactory> {
		&self.sequence
	}

	/** Mutably borrow the cell.
	 *
	 * Note that the following lines are equivalent. The benefit of `borrow_mut()` is for values that are not (cheaply) clonable.
	 *
	 * ```
	 * # let mut ctx = mergable::Context::default();
	 * # let mut cell = mergable::Cell::new(&mut ctx, 0);
	 * *cell.borrow_mut(&mut ctx) += 1;
	 * cell.set(&mut ctx, *cell.clone() + 1);
	 * ```
	 */
	pub fn borrow_mut(&mut self, ctx: &mut crate::Context<SequenceFactory>) -> &mut T {
		self.sequence = ctx.next_sequence();
		&mut self.value
	}

	pub fn into(self) -> T {
		self.value
	}
}

#[derive(Clone,Debug)]
pub struct CellDiff<T, Seq>(Option<Update<T, Seq>>);

#[derive(Clone,Debug)]
struct Update<T, Seq> {
	new: Cell<T, Seq>,
	old: T,
}

impl<
	T: Clone,
	SequenceFactory: crate::SequenceFactory,
> crate::Mergable
for Cell<T, crate::Sequence<SequenceFactory>> {
	type Diff = CellDiff<T, crate::Sequence<SequenceFactory>>;
	type Seq = crate::Sequence<SequenceFactory>;

	fn merge(&mut self, other: Self) {
		if other.sequence > self.sequence {
			*self = other
		}

		// TODO: If the sequences are equal the values *must* be identical. It would be nice to add an assert but I don't want to force `T: PartialEq`.
	}

	fn diff(&self, other: &Self) -> Self::Diff {
		CellDiff(if self.sequence > other.sequence {
			Some(Update{
				new: self.clone(),
				old: other.value.clone(),
			})
		} else {
			None
		})
	}

	fn apply(&mut self, diff: Self::Diff) -> Result<(), crate::ApplyError> {
		if let Some(diff) = diff.0 {
			self.merge(diff.new);
		}

		Ok(())
	}

	fn clean(&mut self, _cutoff: &Self::Seq) {
		// Cell doesn't keep history.

		// TODO: It would be nice if we could propagate `clean()` to our child if it is Mergable. This could form some sort of "resettable" container. However that requires specialization
		// https://github.com/rust-lang/rust/issues/31844
	}
}


impl<T, SequenceFactory: crate::SequenceFactory> crate::Diff
for CellDiff<T, crate::Sequence<SequenceFactory>> {
	fn is_empty(&self) -> bool {
		self.0.is_none()
	}

	fn revert(mut self) -> Result<Self, crate::RevertError> {
		if let Some(ref mut diff) = self.0 {
			diff.new.sequence = diff.new.sequence.undo()?;
			std::mem::swap(&mut diff.new.value, &mut diff.old);
		}
		Ok(self)
	}
}

impl<T: Clone, SF: Clone> Clone for Cell<T, SF> {
	fn clone(&self) -> Self {
		Cell {
			sequence: self.sequence.clone(),
			value: self.value.clone(),
		}
	}
}

impl<T, SF> std::ops::Deref for Cell<T, SF> {
	type Target = T;

	fn deref(&self) -> &T {
		&self.value
	}
}

impl<T: PartialEq, Seq> PartialEq for Cell<T, Seq> {
	fn eq(&self, other: &Self) -> bool {
		self.value == other.value
	}
}

impl<T: std::fmt::Debug, Seq> std::fmt::Debug for Cell<T, Seq> {
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
		self.value.fmt(f)
	}
}

#[test]
fn test_merge() {
	let mut ctx = crate::Context::default();

	let result = crate::test::test_merge(&mut [
		&Cell::new(&mut ctx, "one"),
		&Cell::new(&mut ctx, "two"),
		&Cell::new(&mut ctx, "six"),
	]);
	assert_eq!(result.value, "six");
}

#[test]
fn test_update() {
	let mut ctx = crate::Context::default();

	let initial = Cell::new(&mut ctx, "old");
	let mut update = initial.clone();
	update.set(&mut ctx, "new");

	let result = crate::test::test_merge(&mut [&initial, &update]);
	assert_eq!(result.value, "new");
}

#[test]
fn test_revert() {
	let mut ctx = crate::Context::default();

	let initial = Cell::new(&mut ctx, "old");
	let mut update = initial.clone();
	update.set(&mut ctx, "new");

	let diff = crate::Mergable::diff(&update, &initial);
	let revert = crate::Diff::revert(diff).unwrap();
	crate::Mergable::apply(&mut update, revert).unwrap();

	assert_eq!(update.value, "old");
}

#[test]
fn test_revert_stale() {
	let mut ctx = crate::Context::default();

	let orig = Cell::new(&mut ctx, "old");

	let mut base = orig.clone();

	let mut updated = base.clone();
	updated.set(&mut ctx, "new");

	let diff_new = crate::Mergable::diff(&updated, &base);
	crate::Mergable::apply(&mut base, diff_new.clone()).unwrap();

	updated.set(&mut ctx, "newer");

	let diff_newer = crate::Mergable::diff(&updated, &base);
	crate::Mergable::apply(&mut base, diff_newer.clone()).unwrap();

	let revert = crate::Diff::revert(diff_new.clone()).unwrap();

	let result = crate::test::test_apply(orig, &mut [
		diff_new,
		diff_newer,
		revert,
	]);

	assert_eq!(result.value, "newer");
}