#[cfg(feature = "bigint")]
pub mod bigint {
pub use num_bigint::BigUint;
}
#[cfg(feature = "bigint")]
use crate::bigint::BigUint;
use std::clone::Clone;
use std::cmp::Eq;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hash;
use std::ops::{Add, AddAssign};
pub type VClock8<K> = VClock<K, u8>;
pub type VClock16<K> = VClock<K, u16>;
pub type VClock32<K> = VClock<K, u32>;
pub type VClock64<K> = VClock<K, u64>;
pub type VClock128<K> = VClock<K, u128>;
#[cfg(feature = "bigint")]
pub type VClockBig<K> = VClock<K, BigUint>;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct VClock<K = usize, I = usize>
where
K: Eq + Hash + Clone,
I: Add<I, Output = I> + AddAssign<I> + From<u8> + Ord + Default + Clone,
{
c: HashMap<K, I>,
}
impl<K, I> VClock<K, I>
where
K: Eq + Hash + Clone,
I: Add<I, Output = I> + AddAssign<I> + From<u8> + Ord + Default + Clone,
{
pub fn new(key: K) -> VClock<K, I> {
let mut first = VClock {
c: HashMap::<K, I>::default(),
};
first.c.insert(key, I::default());
first
}
pub fn get(&self, key: &K) -> Option<I> {
match self.c.get(key) {
Some(v) => Some(v.clone()),
None => None,
}
}
pub fn len(&self) -> usize {
return self.c.len();
}
pub fn weight(&self) -> I {
let mut weight = I::default();
for (_, v) in &(self.c) {
weight += v.clone() + I::from(1);
}
weight
}
pub fn max(&self) -> Option<(&K, I)> {
let mut max_value = I::default();
let mut max_key: Option<&K> = None;
for (k, v) in &(self.c) {
if max_value <= v.clone() {
max_key = Some(&k);
max_value = v.clone();
}
}
match max_key {
Some(k) => Some((k, max_value)),
_ => None,
}
}
pub fn incr(&mut self, key: &K) {
let value = match self.c.get(key) {
Some(v) => v.clone() + I::from(1),
None => I::default(),
};
self.c.insert(key.clone(), value);
}
pub fn next(mut self, key: &K) -> VClock<K, I> {
self.incr(key);
self
}
pub fn merge(&mut self, other: &VClock<K, I>) {
for (k, v) in &(other.c) {
if match self.c.get(k) {
Some(v2) => v2 < v,
None => true,
} {
self.c.insert(k.clone(), v.clone());
}
}
}
pub fn combine(mut self, other: &VClock<K, I>) -> VClock<K, I> {
self.merge(other);
self
}
}
impl<K, I> std::cmp::PartialOrd for VClock<K, I>
where
K: Eq + Hash + Clone,
I: Add<I, Output = I> + AddAssign<I> + From<u8> + Ord + Default + Clone,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let mut has_less: bool = false;
let mut has_greater: bool = false;
for (k, v) in &(self.c) {
match other.c.get(k) {
Some(other_v) => {
if v > other_v {
if !has_less {
has_greater = true;
} else {
return None;
}
}
if v < other_v {
if !has_greater {
has_less = true;
} else {
return None;
}
}
}
None => {
if !has_less {
has_greater = true;
} else {
return None;
}
}
}
}
for (k, v) in &(other.c) {
match self.c.get(k) {
Some(self_v) => {
if v > self_v {
if !has_greater {
has_less = true;
} else {
return None;
}
}
if v < self_v {
if !has_less {
has_greater = true;
} else {
return None;
}
}
}
None => {
if !has_greater {
has_less = true;
} else {
return None;
}
}
}
}
if has_less && !has_greater {
return Some(Ordering::Less);
}
if has_greater && !has_less {
return Some(Ordering::Greater);
}
if has_less && has_greater {
return None;
}
Some(Ordering::Equal)
}
}
impl<K, I> From<HashMap<K, I>> for VClock<K, I>
where
K: Eq + Hash + Clone,
I: Add<I, Output = I> + AddAssign<I> + From<u8> + Ord + Default + Clone,
{
fn from(src: HashMap<K, I>) -> VClock<K, I> {
VClock { c: src }
}
}
impl<K, I> From<VClock<K, I>> for HashMap<K, I>
where
K: Eq + Hash + Clone,
I: Add<I, Output = I> + AddAssign<I> + From<u8> + Ord + Default + Clone,
{
fn from(src: VClock<K, I>) -> HashMap<K, I> {
src.c
}
}
impl<K, I> std::fmt::Display for VClock<K, I>
where
K: Eq + Hash + Clone + std::fmt::Display,
I: Add<I, Output = I> + AddAssign<I> + From<u8> + Ord + Default + Clone + std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let weight = self.weight();
let max = self.max();
match max {
Some(m) => write!(
f,
"{{len: {}, weight: {}, max: {{\"{}\": {}}}}}",
self.c.len(),
weight,
m.0,
m.1
),
None => write!(f, "{{len: {}, weight: {}}}", self.c.len(), weight),
}
}
}
impl<K, I> std::default::Default for VClock<K, I>
where
K: Eq + Hash + Clone,
I: Add<I, Output = I> + AddAssign<I> + From<u8> + Ord + Default + Clone,
{
fn default() -> VClock<K, I> {
VClock {
c: HashMap::<K, I>::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use num_bigint::BigUint;
#[test]
fn test_vclock_default() {
let _ = VClock::<i16>::default();
let _ = VClock::<i8, BigUint>::default();
}
#[test]
fn test_vclock_new() {
let vc1 = VClock::new(17);
assert_eq!(None, vc1.get(&0));
assert_eq!(Some(0), vc1.get(&17));
let vc2 = VClock::<u32>::new(17u32);
assert_eq!(None, vc2.get(&0u32));
assert_eq!(Some(0usize), vc2.get(&17u32));
let vc3 = VClock::<i64, u8>::new(17i64);
assert_eq!(None, vc3.get(&0i64));
assert_eq!(Some(0u8), vc3.get(&17i64));
let vc4 = VClock::<i64, i16>::new(17i64);
assert_eq!(None, vc4.get(&0i64));
assert_eq!(Some(0i16), vc4.get(&17i64));
}
#[test]
fn test_vclock_incr() {
let mut vc = VClock::<i16>::default();
assert_eq!(None, vc.get(&0));
vc.incr(&2);
assert_eq!(None, vc.get(&0));
assert_eq!(Some(0), vc.get(&2));
vc.incr(&2);
assert_eq!(None, vc.get(&0));
assert_eq!(Some(1), vc.get(&2));
vc.incr(&3);
assert_eq!(None, vc.get(&0));
assert_eq!(Some(1), vc.get(&2));
assert_eq!(Some(0), vc.get(&3));
}
#[test]
fn test_vclock_next() {
let vc = VClock::<i16>::default();
assert_eq!(None, vc.get(&0));
let vc2 = vc.clone().next(&2);
assert_eq!(None, vc.get(&0));
assert_eq!(None, vc.get(&2));
assert_eq!(Some(0), vc2.get(&2));
let vc3 = vc.clone().next(&3);
assert_eq!(None, vc.get(&0));
assert_eq!(None, vc.get(&2));
assert_eq!(None, vc.get(&3));
assert_eq!(Some(0), vc2.get(&2));
assert_eq!(Some(0), vc3.get(&3));
let vc3i = vc3.clone().next(&3);
assert_eq!(None, vc.get(&0));
assert_eq!(None, vc.get(&2));
assert_eq!(None, vc.get(&3));
assert_eq!(Some(0), vc2.get(&2));
assert_eq!(Some(1), vc3i.get(&3));
}
#[test]
fn test_vclock_debug() {
let vc = VClock::<i16>::default();
let vca = vc.next(&42);
let vcb = vca.next(&42);
let vcc = vcb.next(&42);
let repr = format!("{:?}", vcc);
assert_eq!("VClock { c: {42: 2} }", repr);
}
#[test]
fn test_vclock_compare() {
let mut vca = VClock::<u32>::default();
let mut vcb = VClock::<u32>::default();
assert_eq!(vca, vcb);
assert_eq!(Some(Ordering::Equal), vca.partial_cmp(&vcb));
assert_eq!(Some(Ordering::Equal), vcb.partial_cmp(&vca));
vcb.incr(&2);
assert_eq!(Some(Ordering::Less), vca.partial_cmp(&vcb));
assert_eq!(Some(Ordering::Greater), vcb.partial_cmp(&vca));
vca.incr(&2);
assert_eq!(Some(Ordering::Equal), vca.partial_cmp(&vcb));
assert_eq!(Some(Ordering::Equal), vcb.partial_cmp(&vca));
vca.incr(&2);
assert_eq!(Some(Ordering::Greater), vca.partial_cmp(&vcb));
assert_eq!(Some(Ordering::Less), vcb.partial_cmp(&vca));
vca.incr(&3);
vca.incr(&3);
vca.incr(&3);
vcb.incr(&3);
vcb.incr(&3);
vcb.incr(&3);
assert_eq!(Some(Ordering::Greater), vca.partial_cmp(&vcb));
assert_eq!(Some(Ordering::Less), vcb.partial_cmp(&vca));
vca.incr(&4);
assert_eq!(Some(Ordering::Greater), vca.partial_cmp(&vcb));
assert_eq!(Some(Ordering::Less), vcb.partial_cmp(&vca));
vcb.incr(&4);
vcb.incr(&4);
assert_eq!(None, vca.partial_cmp(&vcb));
assert_eq!(None, vcb.partial_cmp(&vca));
}
#[test]
fn test_vclock_fmt() {
let mut k = VClock::<i32>::default();
assert_eq!(String::from("{len: 0, weight: 0}"), format!("{}", k));
k.incr(&42);
assert_eq!(
String::from("{len: 1, weight: 1, max: {\"42\": 0}}"),
format!("{}", k)
);
k.incr(&421);
k.incr(&421);
k.incr(&421);
assert_eq!(
String::from("{len: 2, weight: 4, max: {\"421\": 2}}"),
format!("{}", k)
);
}
#[cfg(feature = "serde")]
#[test]
fn test_vclock_serde_json() {
let vc = VClock::<i32>::new(42);
let js = serde_json::json!(&vc).to_string();
assert_eq!("{\"c\":{\"42\":0}}", js);
let obj: Result<VClock<i32>, serde_json::Error> = serde_json::from_str(&js);
match obj {
Ok(v) => {
assert_eq!(vc, v);
}
Err(_) => unreachable!(),
}
}
#[cfg(feature = "serde")]
#[test]
fn test_vclock_serde_cbor() {
let vc = VClock::<i32>::new(42);
let buf: Vec<u8> = serde_cbor::to_vec(&vc).unwrap();
let obj: VClock<i32> = serde_cbor::from_slice(&buf).unwrap();
assert_eq!(vc, obj);
}
#[test]
fn test_vclock_bigint() {
let mut vc1 = VClock::<&str, BigUint>::default();
assert_eq!(None, vc1.get(&"not here"));
vc1.incr(&"k1");
vc1.incr(&"k1");
vc1.incr(&"k1");
assert_eq!("{len: 1, weight: 3, max: {\"k1\": 2}}", format!("{}", &vc1));
let vc2 = vc1.clone().next(&"k2");
assert!(vc1 < vc2);
}
#[cfg(feature = "bigint")]
#[test]
fn test_vclock_big_type() {
let mut vc1 = VClockBig::default();
assert_eq!(None, vc1.get(&"not here"));
vc1.incr(&"k1");
vc1.incr(&"k1");
vc1.incr(&"k1");
assert_eq!("{len: 1, weight: 3, max: {\"k1\": 2}}", format!("{}", &vc1));
let vc2 = vc1.clone().next(&"k2");
assert!(vc1 < vc2);
}
#[test]
#[should_panic]
fn test_vclock_overflow() {
let mut vc = VClock8::default();
for _ in 0..1000 {
vc.incr(&"a");
}
}
}