crdt: Remove some `Semilattice` instances

These instances were not safe to have around, as they allow
removal of items in a non-commutative way.

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
Alexis Sellier 2022-12-07 17:46:56 +01:00
parent 06d658dba4
commit 56f9af650e
No known key found for this signature in database
2 changed files with 14 additions and 75 deletions

View File

@ -25,9 +25,6 @@ pub use redactable::Redactable;
////////////////////////////////////////////////////////////////////////////////
use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
/// A join-semilattice.
pub trait Semilattice: Sized {
/// Merge an other semilattice into this one.
@ -43,40 +40,6 @@ pub trait Semilattice: Sized {
}
}
impl<K: Ord, V: Semilattice> Semilattice for BTreeMap<K, V> {
fn merge(&mut self, other: Self) {
use std::collections::btree_map::Entry;
for (k, v) in other {
match self.entry(k) {
Entry::Occupied(mut e) => {
e.get_mut().merge(v);
}
Entry::Vacant(e) => {
e.insert(v);
}
}
}
}
}
impl<K: Hash + PartialEq + Eq, V: Semilattice> Semilattice for HashMap<K, V> {
fn merge(&mut self, other: Self) {
use std::collections::hash_map::Entry;
for (k, v) in other {
match self.entry(k) {
Entry::Occupied(mut e) => {
e.get_mut().merge(v);
}
Entry::Vacant(e) => {
e.insert(v);
}
}
}
}
}
impl<T: Semilattice> Semilattice for Option<T> {
fn merge(&mut self, other: Self) {
match (self, other) {

View File

@ -1,5 +1,4 @@
use std::cmp::Ordering;
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
use std::ops::{ControlFlow, Deref, DerefMut};
use std::str::FromStr;
@ -15,6 +14,7 @@ use crate::cob::{ActorId, History, Op, OpId, TypeName};
use crate::crypto::Signer;
use crdt::clock::Lamport;
use crdt::gmap::GMap;
use crdt::lwwset::LWWSet;
use crdt::redactable::Redactable;
use crdt::Semilattice;
@ -85,9 +85,9 @@ pub enum Action {
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Thread {
/// The comments under the thread.
comments: BTreeMap<CommentId, Redactable<Comment>>,
comments: GMap<CommentId, Redactable<Comment>>,
/// Reactions to changes.
reactions: BTreeMap<CommentId, LWWSet<(ActorId, Reaction), Lamport>>,
reactions: GMap<CommentId, LWWSet<(ActorId, Reaction), Lamport>>,
}
impl store::FromHistory for Thread {
@ -126,10 +126,6 @@ impl Deref for Thread {
}
impl Thread {
pub fn clear(&mut self) {
self.comments.clear();
}
pub fn comment(&self, id: &CommentId) -> Option<&Comment> {
if let Some(Redactable::Present(comment)) = self.comments.get(id) {
Some(comment)
@ -179,45 +175,25 @@ impl Thread {
Action::Comment { body, reply_to } => {
let present =
Redactable::Present(Comment::new(body, reply_to, change.timestamp));
match self.comments.entry(id) {
Entry::Vacant(e) => {
e.insert(present);
}
Entry::Occupied(mut e) => {
e.get_mut().merge(present);
}
}
self.comments.insert(id, present);
}
Action::Redact { id } => {
self.comments
.entry(id)
.and_modify(|e| e.merge(Redactable::Redacted))
.or_insert(Redactable::Redacted);
self.comments.insert(id, Redactable::Redacted);
}
Action::React {
to,
reaction,
active,
} => {
self.reactions
.entry(to)
.and_modify(|reactions| {
if active {
reactions.insert((change.author, reaction), change.clock);
} else {
reactions.remove((change.author, reaction), change.clock);
}
})
.or_insert_with(|| {
if active {
LWWSet::singleton((change.author, reaction), change.clock)
} else {
let mut set = LWWSet::default();
set.remove((change.author, reaction), change.clock);
set
}
});
let key = (change.author, reaction);
let reactions = if active {
LWWSet::singleton(key, change.clock)
} else {
let mut set = LWWSet::default();
set.remove(key, change.clock);
set
};
self.reactions.insert(to, reactions);
}
}
}