lattice/crdt
A tagged union over all leaf CRDT types with dynamic dispatch.
The Crdt type wraps individual CRDTs (counters, registers, sets) so they
can be stored and merged uniformly — this is how ORMap holds heterogeneous
values. For direct use, prefer the individual modules (e.g., g_counter,
or_set) for type-safe access.
Maps (LWWMap, ORMap) are not included in this union to avoid circular
module dependencies.
Example
import lattice/crdt
import lattice/g_counter
let a = crdt.CrdtGCounter(g_counter.new("node-a") |> g_counter.increment(1))
let b = crdt.CrdtGCounter(g_counter.new("node-b") |> g_counter.increment(2))
let merged = crdt.merge(a, b)
Types
A tagged union wrapping every leaf CRDT type in this library.
Variants:
CrdtGCounter— grow-only counterCrdtPnCounter— increment/decrement counterCrdtLwwRegister— last-writer-wins register (String)CrdtMvRegister— multi-value register (String)CrdtGSet— grow-only set (String)CrdtTwoPSet— two-phase set (String)CrdtOrSet— observed-remove set (String)CrdtVersionVector— version vector
Parameterized types are fixed to String for v1. Maps (LWWMap,
ORMap) are composite containers and are not included in this union
to avoid circular module dependencies.
pub type Crdt {
CrdtGCounter(g_counter.GCounter)
CrdtPnCounter(pn_counter.PNCounter)
CrdtLwwRegister(lww_register.LWWRegister(String))
CrdtMvRegister(mv_register.MVRegister(String))
CrdtGSet(g_set.GSet(String))
CrdtTwoPSet(two_p_set.TwoPSet(String))
CrdtOrSet(or_set.ORSet(String))
CrdtVersionVector(version_vector.VersionVector)
}
Constructors
-
CrdtGCounter(g_counter.GCounter) -
CrdtPnCounter(pn_counter.PNCounter) -
CrdtLwwRegister(lww_register.LWWRegister(String)) -
CrdtMvRegister(mv_register.MVRegister(String)) -
CrdtGSet(g_set.GSet(String)) -
CrdtTwoPSet(two_p_set.TwoPSet(String)) -
CrdtOrSet(or_set.ORSet(String)) -
CrdtVersionVector(version_vector.VersionVector)
Specifies which leaf CRDT type an ORMap holds as its values.
When or_map.update is called on a key that does not yet exist, the map
uses this spec to auto-create a default value via default_crdt. Choosing
the right spec at or_map.new time is important because changing the
value type after the fact would require migrating all existing values.
pub type CrdtSpec {
GCounterSpec
PnCounterSpec
LwwRegisterSpec
MvRegisterSpec
GSetSpec
TwoPSetSpec
OrSetSpec
}
Constructors
-
GCounterSpec -
PnCounterSpec -
LwwRegisterSpec -
MvRegisterSpec -
GSetSpec -
TwoPSetSpec -
OrSetSpec
Values
pub fn default_crdt(spec: CrdtSpec, replica_id: String) -> Crdt
Create a new default (bottom) value of the specified CRDT type.
The replica_id is passed to CRDT constructors that require it
(counters, registers, OR-Set). For types that don’t use a replica
identifier (G-Set, 2P-Set), the argument is ignored.
Default values per spec:
GCounterSpec/PnCounterSpec— new counter forreplica_idLwwRegisterSpec— empty string""at timestamp0(bottom element)MvRegisterSpec— new MV-Register forreplica_idGSetSpec/TwoPSetSpec— empty set (no replica needed)OrSetSpec— new OR-Set forreplica_id
pub fn from_json(
json_string: String,
) -> Result(Crdt, json.DecodeError)
Decode a Crdt from a JSON string produced by to_json.
Reads the "type" field to determine which type-specific decoder to
use. Returns Error if the string is not valid JSON, the "type" field
is missing, or the type tag is not recognized.
pub fn merge(a: Crdt, b: Crdt) -> Crdt
Dispatch merge to the type-specific merge function for matching variants.
If a and b hold the same variant, their inner values are merged using
the type-specific merge function. On type mismatch (different variants),
a is returned unchanged. Type mismatches should not occur in a
well-formed system, but this behavior avoids a crash.