y-octo 0.0.3

High-performance and thread-safe CRDT implementation compatible with Yjs
Documentation
use std::{
    fmt::Display,
    hash::Hash,
    ops::{Add, Sub},
};

pub type Client = u64;
pub type Clock = u64;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
#[cfg_attr(fuzzing, derive(arbitrary::Arbitrary))]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct Id {
    pub client: Client,
    pub clock: Clock,
}

impl Id {
    pub fn new(client: Client, clock: Clock) -> Self {
        Self { client, clock }
    }
}

impl From<(Client, Clock)> for Id {
    fn from((client, clock): (Client, Clock)) -> Self {
        Id::new(client, clock)
    }
}

impl Sub<Clock> for Id {
    type Output = Id;

    fn sub(self, rhs: Clock) -> Self::Output {
        (self.client, self.clock - rhs).into()
    }
}

impl Add<Clock> for Id {
    type Output = Id;

    fn add(self, rhs: Clock) -> Self::Output {
        (self.client, self.clock + rhs).into()
    }
}

impl Display for Id {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "({}, {})", self.client, self.clock)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn basic_id_operation() {
        let id_with_different_client_1 = Id::new(1, 1);
        let id_with_different_client_2 = Id::new(2, 1);

        assert_ne!(id_with_different_client_1, id_with_different_client_2);
        assert_eq!(Id::new(1, 1), Id::new(1, 1));

        let clock = 2;
        assert_eq!(Id::new(1, 1) + clock, (1, 3).into());
        assert_eq!(Id::new(1, 3) - clock, (1, 1).into());
    }
}