///| CRDT initial validation: Measuring LogicalId introduction overhead
// =============================================================================
// Experimental type definitions
// =============================================================================
///|
/// Agent identifier (simplified version: Int)
pub(all) struct AgentId(Int) derive(Eq, Debug)
///|
/// Logical ID: (agent, seq) pair
#valtype
pub(all) struct LogicalId {
agent : AgentId
seq : Int
} derive(Eq, Debug)
pub impl Show for AgentId with output(self : AgentId, logger : &Logger) -> Unit {
logger.write_string(@debug.to_string(self))
}
pub impl Show for LogicalId with output(
self : LogicalId,
logger : &Logger,
) -> Unit {
logger.write_string(@debug.to_string(self))
}
///|
/// LogicalId generator
pub(all) struct IdGenerator {
agent : AgentId
mut next_seq : Int
}
///|
pub fn IdGenerator::new(agent : AgentId) -> IdGenerator {
{ agent, next_seq: 0 }
}
///|
pub fn IdGenerator::next(self : IdGenerator) -> LogicalId {
let id = { agent: self.agent, seq: self.next_seq }
self.next_seq += 1
id
}
///|
/// CRDT-aware Span (with cache)
pub(all) struct CrdtSpan {
start_id : LogicalId
end_id : LogicalId
// Absolute position cache (for fast access)
cached_from : Int
cached_to : Int
}
///|
pub fn CrdtSpan::new(
start_id : LogicalId,
end_id : LogicalId,
from : Int,
to : Int,
) -> CrdtSpan {
{ start_id, end_id, cached_from: from, cached_to: to }
}
///|
/// TextRun: Compressed representation of contiguous text
pub(all) struct TextRun {
id : LogicalId // Start ID
content : String // Text content
deleted : Bool // Tombstone flag
}
///|
/// Experimental document structure
pub(all) struct CrdtDocument {
runs : Array[TextRun]
gen : IdGenerator
}
///|
pub fn CrdtDocument::new(agent : AgentId) -> CrdtDocument {
{ runs: [], gen: IdGenerator::new(agent) }
}
///|
/// Insert text
pub fn CrdtDocument::insert(self : CrdtDocument, text : String) -> LogicalId {
let id = self.gen.next()
self.runs.push({ id, content: text, deleted: false })
id
}
///|
/// Delete (mark as tombstone)
pub fn CrdtDocument::delete(self : CrdtDocument, idx : Int) -> Unit {
if idx < self.runs.length() {
let run = self.runs[idx]
self.runs[idx] = { ..run, deleted: true }
}
}
///|
/// Get active (non-deleted) text
pub fn CrdtDocument::get_text(self : CrdtDocument) -> String {
let buf = StringBuilder::new()
for run in self.runs {
if !(run.deleted) {
buf.write_string(run.content)
}
}
buf.to_string()
}
///|
/// Count of active runs
pub fn CrdtDocument::active_count(self : CrdtDocument) -> Int {
let mut count = 0
for run in self.runs {
if !(run.deleted) {
count += 1
}
}
count
}
///|
/// Total run count (including tombstones)
pub fn CrdtDocument::total_count(self : CrdtDocument) -> Int {
self.runs.length()
}
// =============================================================================
// LogicalId comparison functions (for CRDT merge)
// =============================================================================
///|
/// LogicalId ordering comparison (Lamport order)
pub fn LogicalId::compare(self : LogicalId, other : LogicalId) -> Int {
// Compare by seq first, then by agent if seq is equal
if self.seq != other.seq {
self.seq - other.seq
} else {
let AgentId(a1) = self.agent
let AgentId(a2) = other.agent
a1 - a2
}
}
///|
pub fn LogicalId::lt(self : LogicalId, other : LogicalId) -> Bool {
self.compare(other) < 0
}
///|
pub fn LogicalId::le(self : LogicalId, other : LogicalId) -> Bool {
self.compare(other) <= 0
}