lattice/g_counter
A grow-only counter (G-Counter) CRDT.
Each replica maintains its own monotonically increasing count. The global value is the sum across all replicas. Merge takes the pairwise maximum of each replica’s count, guaranteeing convergence.
G-Counter is non-opaque because pn_counter directly accesses its internal
fields for serialization. Adding opaque accessor functions would not improve
the API for this paired type.
Example
import lattice/g_counter
let a = g_counter.new("node-a") |> g_counter.increment(3)
let b = g_counter.new("node-b") |> g_counter.increment(5)
let merged = g_counter.merge(a, b)
g_counter.value(merged) // -> 8
Types
A grow-only counter that tracks per-replica counts.
Each replica identified by a String ID maintains its own count.
The global value is the sum of all per-replica counts.
The type is non-opaque so that pn_counter can access fields for
serialization; do not rely on internal field names in application code.
pub type GCounter {
GCounter(dict: dict.Dict(String, Int), self_id: String)
}
Constructors
-
GCounter(dict: dict.Dict(String, Int), self_id: String)
Values
pub fn from_json(
json_string: String,
) -> Result(GCounter, json.DecodeError)
Decode a G-Counter from a JSON string produced by to_json.
Returns Ok(GCounter) on success, or Error(json.DecodeError) if the
input is not a valid G-Counter JSON envelope.
pub fn increment(counter: GCounter, delta: Int) -> GCounter
Increment the counter by delta.
Adds delta to this replica’s count. delta should be a non-negative
integer; passing a negative value will decrease the local count, which
violates the grow-only invariant and may cause incorrect merge results.
pub fn merge(a: GCounter, b: GCounter) -> GCounter
Merge two G-Counters using pairwise maximum.
For each replica, the merged count is the maximum of the two inputs.
The result’s self_id is taken from a.
This operation is commutative, associative, and idempotent, satisfying the CRDT join-semilattice laws. Any ordering of concurrent merges will produce the same final state.
pub fn new(replica_id: String) -> GCounter
Create a new G-Counter for the given replica.
Returns a fresh counter where all per-replica counts are zero.
The replica_id identifies this node and is used when incrementing.
pub fn to_json(counter: GCounter) -> json.Json
Encode a G-Counter as a self-describing JSON value.
Produces an envelope with type, v (schema version), and state.
Format: {"type": "g_counter", "v": 1, "state": {"self_id": "...", "counts": {...}}}
Use from_json to decode the result back into a GCounter.