use car_state::crdt::{
claim_owners, export_lww, materialize, merge_claims_many, merge_many, ClaimRegistry, LwwMap,
};
use serde_json::Value;
use std::collections::HashMap;
pub fn merge(replicas_json: &str) -> Result<String, String> {
let replicas: Vec<LwwMap> = crate::from_json("replicas", replicas_json)?;
let merged = merge_many(&replicas);
let state = materialize(&merged);
crate::to_json(&serde_json::json!({
"registers": merged,
"state": state,
}))
}
pub fn export(
snapshot_json: &str,
versions_json: &str,
replica: &str,
) -> Result<String, String> {
let snapshot: HashMap<String, Value> = crate::from_json("snapshot", snapshot_json)?;
let versions: HashMap<String, u64> = crate::from_json("versions", versions_json)?;
let map = export_lww(&snapshot, &versions, replica);
crate::to_json(&map)
}
pub fn merge_claims(registries_json: &str) -> Result<String, String> {
let registries: Vec<ClaimRegistry> = crate::from_json("registries", registries_json)?;
let merged = merge_claims_many(®istries);
let owners = claim_owners(&merged);
crate::to_json(&serde_json::json!({ "registry": merged, "owners": owners }))
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::Value;
#[test]
fn merge_converges_and_materializes() {
let replicas = r#"[
{ "x": { "value": 1, "version": 2, "replica": "r1" },
"shared": { "value": "a", "version": 1, "replica": "r1" } },
{ "y": { "value": 2, "version": 1, "replica": "r2" },
"shared": { "value": "b", "version": 3, "replica": "r2" } }
]"#;
let out = merge(replicas).unwrap();
let v: Value = serde_json::from_str(&out).unwrap();
assert_eq!(v["state"]["shared"], "b");
assert_eq!(v["state"]["x"], 1);
assert_eq!(v["state"]["y"], 2);
assert_eq!(v["registers"]["shared"]["replica"], "r2");
}
#[test]
fn empty_is_empty() {
let out = merge("[]").unwrap();
let v: Value = serde_json::from_str(&out).unwrap();
assert_eq!(v["state"], serde_json::json!({}));
}
#[test]
fn invalid_json_errs() {
assert!(merge("not json").is_err());
}
#[test]
fn merge_claims_resolves_owner() {
let regs = r#"[
{"t":{"claimant":"a2","version":2,"replica":"r2"}},
{"t":{"claimant":"a1","version":1,"replica":"r1"}}
]"#;
let out = merge_claims(regs).unwrap();
let v: Value = serde_json::from_str(&out).unwrap();
assert_eq!(v["owners"]["t"], "a1");
assert_eq!(v["registry"]["t"]["claimant"], "a1");
}
#[test]
fn export_then_merge_via_ffi() {
let a = export(r#"{"k":"a"}"#, r#"{"k":1}"#, "A").unwrap();
let b = export(r#"{"k":"b"}"#, r#"{"k":2}"#, "B").unwrap();
let replicas = format!("[{a},{b}]");
let out = merge(&replicas).unwrap();
let v: Value = serde_json::from_str(&out).unwrap();
assert_eq!(v["state"]["k"], "b"); }
}