use crate::block::ClientID;
use crate::encoding::read::Error;
use crate::updates::decoder::{Decode, Decoder};
use crate::updates::encoder::{Encode, Encoder};
use crate::utils::client_hasher::ClientHasher;
use crate::{DeleteSet, ID};
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::iter::FromIterator;
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct StateVector(HashMap<ClientID, u32, BuildHasherDefault<ClientHasher>>);
impl StateVector {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn new(map: HashMap<ClientID, u32, BuildHasherDefault<ClientHasher>>) -> Self {
StateVector(map)
}
pub fn contains(&self, id: &ID) -> bool {
id.clock <= self.get(&id.client)
}
pub fn contains_client(&self, client_id: &ClientID) -> bool {
self.0.contains_key(client_id)
}
pub fn get(&self, client_id: &ClientID) -> u32 {
match self.0.get(client_id) {
Some(state) => *state,
None => 0,
}
}
pub fn inc_by(&mut self, client: ClientID, delta: u32) {
if delta > 0 {
let e = self.0.entry(client).or_default();
*e = *e + delta;
}
}
pub fn set_min(&mut self, client: ClientID, clock: u32) {
match self.0.entry(client) {
Entry::Occupied(e) => {
let value = e.into_mut();
*value = (*value).min(clock);
}
Entry::Vacant(e) => {
e.insert(clock);
}
}
}
pub fn set_max(&mut self, client: ClientID, clock: u32) {
let e = self.0.entry(client).or_default();
*e = (*e).max(clock);
}
pub fn iter(&self) -> std::collections::hash_map::Iter<ClientID, u32> {
self.0.iter()
}
pub fn merge(&mut self, other: Self) {
for (client, clock) in other.0 {
let e = self.0.entry(client).or_default();
*e = (*e).max(clock);
}
}
}
impl FromIterator<(ClientID, u32)> for StateVector {
fn from_iter<T: IntoIterator<Item = (ClientID, u32)>>(iter: T) -> Self {
StateVector::new(
HashMap::<ClientID, u32, BuildHasherDefault<ClientHasher>>::from_iter(iter),
)
}
}
impl Decode for StateVector {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, Error> {
let len = decoder.read_var::<u32>()? as usize;
let mut sv = HashMap::with_capacity_and_hasher(len, BuildHasherDefault::default());
let mut i = 0;
while i < len {
let client = decoder.read_var()?;
let clock = decoder.read_var()?;
sv.insert(client, clock);
i += 1;
}
Ok(StateVector(sv))
}
}
impl Encode for StateVector {
fn encode<E: Encoder>(&self, encoder: &mut E) {
encoder.write_var(self.len());
for (&client, &clock) in self.iter() {
encoder.write_var(client);
encoder.write_var(clock);
}
}
}
impl PartialOrd for StateVector {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let mut result = Some(Ordering::Equal);
for (client, clock) in self.iter() {
let other_clock = other.get(client);
match clock.cmp(&other_clock) {
Ordering::Less if result == Some(Ordering::Greater) => return None,
Ordering::Greater if result == Some(Ordering::Less) => return None,
Ordering::Equal => { }
other => result = Some(other),
}
}
for (other_client, other_clock) in other.iter() {
let clock = self.get(other_client);
match clock.cmp(&other_clock) {
Ordering::Less if result == Some(Ordering::Greater) => return None,
Ordering::Greater if result == Some(Ordering::Less) => return None,
Ordering::Equal => { }
other => result = Some(other),
}
}
result
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Snapshot {
pub delete_set: DeleteSet,
pub state_map: StateVector,
}
impl Snapshot {
pub fn new(state_map: StateVector, delete_set: DeleteSet) -> Self {
Snapshot {
state_map,
delete_set,
}
}
pub(crate) fn is_visible(&self, id: &ID) -> bool {
self.state_map.get(&id.client) > id.clock && !self.delete_set.is_deleted(id)
}
}
impl Encode for Snapshot {
fn encode<E: Encoder>(&self, encoder: &mut E) {
self.delete_set.encode(encoder);
self.state_map.encode(encoder)
}
}
impl Decode for Snapshot {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, Error> {
let ds = DeleteSet::decode(decoder)?;
let sm = StateVector::decode(decoder)?;
Ok(Snapshot::new(sm, ds))
}
}
#[cfg(test)]
mod test {
use crate::{Doc, ReadTxn, StateVector, Text, Transact, WriteTxn};
use std::cmp::Ordering;
use std::iter::FromIterator;
#[test]
fn ordering() {
fn s(a: u32, b: u32, c: u32) -> StateVector {
StateVector::from_iter([(1, a), (2, b), (3, c)])
}
assert_eq!(s(1, 2, 3).partial_cmp(&s(1, 2, 3)), Some(Ordering::Equal));
assert_eq!(s(1, 2, 2).partial_cmp(&s(1, 2, 3)), Some(Ordering::Less));
assert_eq!(s(2, 2, 3).partial_cmp(&s(1, 2, 3)), Some(Ordering::Greater));
assert_eq!(s(3, 2, 1).partial_cmp(&s(1, 2, 3)), None);
}
#[test]
fn ordering_missing_fields() {
let a = StateVector::from_iter([(1, 1), (2, 2)]);
let b = StateVector::from_iter([(2, 1), (3, 2)]);
assert_eq!(a.partial_cmp(&b), None);
let a = StateVector::from_iter([(1, 1), (2, 2)]);
let b = StateVector::from_iter([(1, 1), (2, 1), (3, 2)]);
assert_eq!(a.partial_cmp(&b), None);
let a = StateVector::from_iter([(1, 1), (2, 2), (3, 3)]);
let b = StateVector::from_iter([(2, 2), (3, 3)]);
assert_eq!(a.partial_cmp(&b), Some(Ordering::Greater));
let a = StateVector::from_iter([(2, 2), (3, 2)]);
let b = StateVector::from_iter([(1, 1), (2, 2), (3, 2)]);
assert_eq!(a.partial_cmp(&b), Some(Ordering::Less));
let a = StateVector::default();
let b = StateVector::default();
assert_eq!(a.partial_cmp(&b), Some(Ordering::Equal));
}
#[test]
fn ordering_one_of() {
let doc = Doc::with_client_id(1);
let mut txn = doc.transact_mut();
let txt = txn.get_or_insert_text("text");
txt.insert(&mut txn, 0, "a");
let a = txn.state_vector();
let b = StateVector::default();
assert_eq!(a.partial_cmp(&b), Some(Ordering::Greater));
}
}