Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
Implement `LWWReg` in terms of `Max`
Alexis Sellier committed 3 years ago
commit 0482757ce91cec74dddafaff44a4d6f342a47763
parent b11826b11396efa0802a0055f5a4d3128fce5da7
3 files changed +52 -19
modified radicle-crdt/src/lib.rs
@@ -13,7 +13,7 @@ mod test;
////////////////////////////////////////////////////////////////////////////////

/// A join-semilattice.
-
pub trait Semilattice: Default {
+
pub trait Semilattice {
    /// Join or "merge" two semilattices into one.
    fn join(self, other: Self) -> Self;
}
@@ -21,7 +21,7 @@ pub trait Semilattice: Default {
/// Reduce an iterator of semilattice values to its least upper bound.
pub fn fold<S>(i: impl IntoIterator<Item = S>) -> S
where
-
    S: Semilattice,
+
    S: Semilattice + Default,
{
    i.into_iter().fold(S::default(), S::join)
}
modified radicle-crdt/src/lwwreg.rs
@@ -1,40 +1,41 @@
+
use crate::ord::Max;
use crate::Semilattice;

/// Last-Write-Wins Register.
///
/// In case of conflict, biased towards larger values.
-
#[derive(Debug, Clone, Default, PartialEq, Eq)]
+
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LWWReg<T, C> {
-
    value: T,
-
    clock: C,
+
    /// Nb. the order of the tuple types ensures we bias towards the clock before the value.
+
    inner: Max<(C, T)>,
}

impl<T: PartialOrd, C: PartialOrd> LWWReg<T, C> {
    pub fn new(value: T, clock: C) -> Self {
-
        Self { value, clock }
+
        Self {
+
            inner: Max::from((clock, value)),
+
        }
    }

    pub fn set(&mut self, value: T, clock: C) {
-
        if clock > self.clock || (clock == self.clock && value > self.value) {
-
            self.value = value;
-
            self.clock = clock;
-
        }
+
        self.inner.merge(Max::from((clock, value)));
    }

    pub fn get(&self) -> &T {
-
        &self.value
+
        &self.inner.get().1
    }

    pub fn clock(&self) -> &C {
-
        &self.clock
+
        &self.inner.get().0
    }

    pub fn into_inner(self) -> (T, C) {
-
        (self.value, self.clock)
+
        let (t, c) = self.inner.into_inner();
+
        (c, t)
    }

    pub fn merge(&mut self, other: Self) {
-
        self.set(other.value, other.clock);
+
        self.inner.merge(other.inner);
    }
}

@@ -43,9 +44,10 @@ where
    T: PartialOrd + Default,
    C: PartialOrd + Default,
{
-
    fn join(mut self, other: Self) -> Self {
-
        self.merge(other);
-
        self
+
    fn join(self, other: Self) -> Self {
+
        Self {
+
            inner: self.inner.join(other.inner),
+
        }
    }
}

modified radicle-crdt/src/ord.rs
@@ -1,10 +1,31 @@
use std::{cmp, ops};

+
use num_traits::Bounded;
use serde::{Deserialize, Serialize};

+
use crate::Semilattice;
+

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Max<T>(T);

+
impl<T> Max<T> {
+
    pub fn get(&self) -> &T {
+
        &self.0
+
    }
+

+
    pub fn into_inner(self) -> T {
+
        self.0
+
    }
+
}
+

+
impl<T: PartialOrd> Max<T> {
+
    pub fn merge(&mut self, other: Self) {
+
        if other.0 > self.0 {
+
            self.0 = other.0;
+
        }
+
    }
+
}
+

impl<T: num_traits::SaturatingAdd + num_traits::One> Max<T> {
    pub fn incr(&mut self) {
        self.0 = self.0.saturating_add(&T::one());
@@ -13,7 +34,7 @@ impl<T: num_traits::SaturatingAdd + num_traits::One> Max<T> {

impl<T> Default for Max<T>
where
-
    T: num_traits::bounds::Bounded,
+
    T: Bounded,
{
    fn default() -> Self {
        Self(T::min_value())
@@ -34,13 +55,23 @@ impl<T> From<T> for Max<T> {
    }
}

+
impl<T: PartialOrd> Semilattice for Max<T> {
+
    fn join(self, other: Self) -> Self {
+
        if other.0 > self.0 {
+
            other
+
        } else {
+
            self
+
        }
+
    }
+
}
+

#[allow(clippy::derive_ord_xor_partial_ord)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, Serialize, Deserialize)]
pub struct Min<T>(pub T);

impl<T> Default for Min<T>
where
-
    T: num_traits::bounds::Bounded,
+
    T: Bounded,
{
    fn default() -> Self {
        Self(T::max_value())