///| A register value timestamped by an HLC. This CRDT deliberately provides a
///| deterministic last-writer policy for domains that prefer one value over
///|
/// preserving conflicts with MultiValueRegister.
pub(all) struct LastWriterWinsRegister {
value : String
writer : String
timestamp : HlcTimestamp
} derive(Eq, Debug)
///|
/// LWW register validation errors.
pub(all) enum LastWriterWinsError {
EmptyLastWriter
} derive(Eq, Debug)
///|
/// Construct a validated register state.
pub fn LastWriterWinsRegister::new(
value : String,
writer : String,
timestamp : HlcTimestamp,
) -> Result[LastWriterWinsRegister, LastWriterWinsError] {
if writer.length() == 0 {
Err(EmptyLastWriter)
} else {
Ok({ value, writer, timestamp })
}
}
///|
/// Current value.
pub fn LastWriterWinsRegister::value(self : LastWriterWinsRegister) -> String {
self.value
}
///|
/// Writer of the current value.
pub fn LastWriterWinsRegister::writer(self : LastWriterWinsRegister) -> String {
self.writer
}
///|
/// Timestamp of the current value.
pub fn LastWriterWinsRegister::timestamp(
self : LastWriterWinsRegister,
) -> HlcTimestamp {
self.timestamp
}
///| Replace the local state when the supplied timestamp wins. Equal timestamps
///| use writer then value as stable tie-breakers, protecting convergence even
///|
/// after corrupted or manually restored clocks produce a collision.
pub fn LastWriterWinsRegister::write(
self : LastWriterWinsRegister,
value : String,
writer : String,
timestamp : HlcTimestamp,
) -> Result[LastWriterWinsRegister, LastWriterWinsError] {
match LastWriterWinsRegister::new(value, writer, timestamp) {
Ok(candidate) => Ok(self.merge(candidate))
Err(error) => Err(error)
}
}
///|
/// Deterministic state merge.
pub fn LastWriterWinsRegister::merge(
self : LastWriterWinsRegister,
other : LastWriterWinsRegister,
) -> LastWriterWinsRegister {
let timestamp_order = self.timestamp.compare(other.timestamp)
if timestamp_order < 0 {
other
} else if timestamp_order > 0 {
self
} else if self.writer < other.writer {
other
} else if self.writer > other.writer {
self
} else if self.value < other.value {
other
} else {
self
}
}
///|
/// Whether this state would win or tie during merge.
pub fn LastWriterWinsRegister::dominates(
self : LastWriterWinsRegister,
other : LastWriterWinsRegister,
) -> Bool {
self.merge(other) == self
}