pub struct LatticeMap<K, V> { /* private fields */ }Expand description
Pointwise map lattice over HashMap.
This is a reusable building block for CRDT states that look like “map from IDs to lattice values”.
Keys are optional; values form a join-semilattice. The induced lattice order is:
m1 ≤ m2 iff for all k, m1[k] ≤ m2[k]
Operationally, join is:
- keys: union of the key sets
- values: pointwise
joinon overlapping keys
Bottom is the empty map.
§Key growth and deletion
Under this lattice, the set of keys grows monotonically under
join (it is the union of key sets). As a result, LatticeMap
does not directly support deletion semantics (there is no
“remove” operation that is monotone w.r.t. this order).
Different applications want different deletion semantics and may
require causal context, so LatticeMap intentionally leaves
deletion policy to composition.
To model deletions, encode them in the value lattice V
(tombstones), or use a dedicated set/map CRDT depending on the
desired semantics. For example, one simple tombstone pattern is:
use algebra::{LatticeMap, LWW};
// Treat `None` as "deleted" at the application layer.
// Conflicts resolve via LWW; a delete can be represented by
// writing `None`.
type Tombstoned<V> = LWW<Option<V>>;
type Map<K, V> = LatticeMap<K, Tombstoned<V>>;(If this pattern becomes common, we can add a small helper wrapper type later, but the policy is intentionally left to composition.)
§Example: Watermark tracking
Track the low watermark across multiple ranks where each rank reports its progress monotonically:
use algebra::JoinSemilattice;
use algebra::LatticeMap;
use algebra::Min;
// Rank 0 reports progress: 100
let mut state1: LatticeMap<u32, Min<u64>> = LatticeMap::new();
state1.insert(0, Min(100));
// Rank 1 reports progress: 200
let mut state2: LatticeMap<u32, Min<u64>> = LatticeMap::new();
state2.insert(1, Min(200));
// Merge: union keys, pointwise min on values
let merged = state1.join(&state2);
// Low watermark is the min across all ranks
let watermark = merged.iter().map(|(_, v)| v.0).min().unwrap();
assert_eq!(watermark, 100); // min(rank0=100, rank1=200)§Commutativity and Idempotence
Unlike a simple HashMap with last-write-wins merge, LatticeMap
provides true commutativity:
use algebra::JoinSemilattice;
use algebra::LatticeMap;
use algebra::Min;
let mut a: LatticeMap<u32, Min<i64>> = LatticeMap::new();
a.insert(0, Min(10));
let mut b: LatticeMap<u32, Min<i64>> = LatticeMap::new();
b.insert(0, Min(20));
// Join is commutative: a ⊔ b = b ⊔ a
assert_eq!(a.join(&b), b.join(&a));
// Join is idempotent: a ⊔ a = a
assert_eq!(a.join(&a), a);Implementations§
Source§impl<K, V> LatticeMap<K, V>
impl<K, V> LatticeMap<K, V>
Sourcepub fn into_inner(self) -> HashMap<K, V>
pub fn into_inner(self) -> HashMap<K, V>
Consume the wrapper and return the underlying HashMap.
Trait Implementations§
Source§impl<K, V> BoundedJoinSemilattice for LatticeMap<K, V>
impl<K, V> BoundedJoinSemilattice for LatticeMap<K, V>
Source§fn join_all_from_bottom<I>(it: I) -> Selfwhere
I: IntoIterator<Item = Self>,
fn join_all_from_bottom<I>(it: I) -> Selfwhere
I: IntoIterator<Item = Self>,
Source§impl<K: Clone, V: Clone> Clone for LatticeMap<K, V>
impl<K: Clone, V: Clone> Clone for LatticeMap<K, V>
Source§fn clone(&self) -> LatticeMap<K, V>
fn clone(&self) -> LatticeMap<K, V>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<K, V> Default for LatticeMap<K, V>
impl<K, V> Default for LatticeMap<K, V>
Source§impl<'de, K, V> Deserialize<'de> for LatticeMap<K, V>
impl<'de, K, V> Deserialize<'de> for LatticeMap<K, V>
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl<K, V> JoinSemilattice for LatticeMap<K, V>
impl<K, V> JoinSemilattice for LatticeMap<K, V>
Source§fn join_assign(&mut self, other: &Self)
fn join_assign(&mut self, other: &Self)
Source§fn leq(&self, other: &Self) -> boolwhere
Self: PartialEq,
fn leq(&self, other: &Self) -> boolwhere
Self: PartialEq,
Source§fn join_all<I>(it: I) -> Option<Self>where
I: IntoIterator<Item = Self>,
fn join_all<I>(it: I) -> Option<Self>where
I: IntoIterator<Item = Self>,
None for empty
iterators.Source§impl<K, V> PartialEq for LatticeMap<K, V>
impl<K, V> PartialEq for LatticeMap<K, V>
Source§impl<K, V> Serialize for LatticeMap<K, V>
impl<K, V> Serialize for LatticeMap<K, V>
impl<K, V> Eq for LatticeMap<K, V>
Auto Trait Implementations§
impl<K, V> Freeze for LatticeMap<K, V>
impl<K, V> RefUnwindSafe for LatticeMap<K, V>where
K: RefUnwindSafe,
V: RefUnwindSafe,
impl<K, V> Send for LatticeMap<K, V>
impl<K, V> Sync for LatticeMap<K, V>
impl<K, V> Unpin for LatticeMap<K, V>
impl<K, V> UnwindSafe for LatticeMap<K, V>where
K: UnwindSafe,
V: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more