From 01b7686659356abd60d71169cc54b05d80b238b6 Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Thu, 24 Nov 2022 19:02:45 +0100 Subject: [PATCH] Turn `Redactable` into a semilattice Signed-off-by: Alexis Sellier --- radicle-cob/src/history/entry.rs | 1 + radicle-crdt/src/lib.rs | 1 + radicle-crdt/src/redactable.rs | 60 ++++++++++++++++++++++++++++++++ radicle-crdt/src/thread.rs | 11 +----- 4 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 radicle-crdt/src/redactable.rs diff --git a/radicle-cob/src/history/entry.rs b/radicle-cob/src/history/entry.rs index 427ffa5a..2fbc03e0 100644 --- a/radicle-cob/src/history/entry.rs +++ b/radicle-cob/src/history/entry.rs @@ -39,6 +39,7 @@ pub struct Entry { /// The identifier for this entry pub(super) id: EntryId, /// The content-address for this entry's author. + /// TODO: This shouldn't be here? pub(super) author: Option, /// The content-address for the resource this entry lives under. pub(super) resource: Oid, diff --git a/radicle-crdt/src/lib.rs b/radicle-crdt/src/lib.rs index 9f1a2fe0..e6d46cda 100644 --- a/radicle-crdt/src/lib.rs +++ b/radicle-crdt/src/lib.rs @@ -6,6 +6,7 @@ pub mod lwwmap; pub mod lwwreg; pub mod lwwset; pub mod ord; +pub mod redactable; pub mod thread; #[cfg(test)] diff --git a/radicle-crdt/src/redactable.rs b/radicle-crdt/src/redactable.rs new file mode 100644 index 00000000..73ffbd62 --- /dev/null +++ b/radicle-crdt/src/redactable.rs @@ -0,0 +1,60 @@ +use crate::Semilattice; + +/// An object that can be either present or removed. +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +pub enum Redactable { + /// When the object is present. + Present(T), + /// When the object has been removed. + #[default] + Redacted, +} + +impl From> for Redactable { + fn from(option: Option) -> Self { + match option { + Some(v) => Self::Present(v), + None => Self::Redacted, + } + } +} + +impl Redactable { + pub fn merge(&mut self, other: Self) { + match (&self, other) { + (Self::Redacted, _) => {} + (Self::Present(_), Self::Redacted) => { + *self = Self::Redacted; + } + (Self::Present(a), Self::Present(b)) => { + if &b > a { + *self = Self::Present(b); + } + } + } + } +} + +impl Semilattice for Redactable { + fn join(mut self, other: Self) -> Self { + self.merge(other); + self + } +} + +#[cfg(test)] +mod test { + use quickcheck_macros::quickcheck; + + use super::*; + use crate::test; + + #[quickcheck] + fn prop_invariants(a: Option, b: Option, c: Option) { + let a = Redactable::from(a); + let b = Redactable::from(b); + let c = Redactable::from(c); + + test::assert_laws(&a, &b, &c); + } +} diff --git a/radicle-crdt/src/thread.rs b/radicle-crdt/src/thread.rs index 7fc9f760..71b2cb70 100644 --- a/radicle-crdt/src/thread.rs +++ b/radicle-crdt/src/thread.rs @@ -11,6 +11,7 @@ use radicle::hash; use crate::clock::LClock; use crate::lwwreg::LWWReg; use crate::lwwset::LWWSet; +use crate::redactable::Redactable; /// Identifies a change. pub type ChangeId = radicle::hash::Digest; @@ -63,16 +64,6 @@ pub struct Envelope { pub signature: Signature, } -/// An object that can be either present or removed. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] -pub enum Redactable { - /// When the object is present. - Present(T), - /// When the object has been removed. - #[default] - Redacted, -} - /// A comment on a discussion thread. #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Comment {