braid-core 0.1.4

Unified Braid Protocol implementation in Rust, including Braid-HTTP, Antimatter CRDT, and BraidFS.
Documentation
use super::crdt_trait::PrunableCrdt;
use super::messages::Patch;
use super::sequence_crdt::{self, SequenceElems, SequenceNode};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::collections::{HashMap, HashSet};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonCrdt {
    pub id: String,
    pub root: SequenceNode,
    pub next_seq: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonPatch {
    pub path: Vec<String>,
    pub range: String,
    pub content: Value,
}

impl PrunableCrdt for JsonCrdt {
    fn apply_patch(&mut self, patch: Patch) {
        // Simplified JSON CRDT application for strings/text
        // In real antimatter, this handles complex nested structures
        if let Some(content_str) = patch.content.as_str() {
            // Treat as text insert/replace
            if patch.range.is_empty() {
                // Initial content
                self.root = SequenceNode::text(&format!("{}@{}", self.next_seq, self.id), content_str);
            } else {
                // This is a simplified mock behavior matching braid-http requirements
                // Real antimatter would use the range to find the path in the JSON tree
            }
        }
        self.next_seq += 1;
    }

    fn prune(&mut self, version: &str) {
        sequence_crdt::prune(&mut self.root, version);
    }

    fn get_next_seq(&self) -> u64 {
        self.next_seq
    }

    fn generate_braid(
        &self,
        known_versions: &HashMap<String, bool>,
    ) -> Vec<(String, HashMap<String, bool>, Vec<Patch>)> {
        // Return visibility-based patches
        let visible = |v: &str| {
            if v.is_empty() {
                return true;
            }
            !known_versions.contains_key(v)
        };

        vec![(
            self.generate_version(),
            known_versions.clone(),
            vec![Patch {
                range: "0".to_string(),
                content: json!(sequence_crdt::content(&self.root, visible)),
            }],
        )]
    }
}

impl JsonCrdt {
    pub fn new(id: &str) -> Self {
        Self {
            id: id.to_string(),
            root: SequenceNode {
                version: None,
                elems: SequenceElems::String(String::new()),
                next: Vec::new(),
                deleted_by: HashSet::new(),
            },
            next_seq: 0,
        }
    }

    pub fn with_content(id: &str, content: &str) -> Self {
        let mut crdt = Self::new(id);
        crdt.root = SequenceNode::text(&format!("0@{}", id), content);
        crdt.next_seq = 1;
        crdt
    }

    pub fn get_content(&self) -> String {
        sequence_crdt::content(&self.root, |_| true)
    }

    pub fn get_length(&self) -> usize {
        sequence_crdt::length(&self.root, |_| true)
    }

    pub fn generate_version(&self) -> String {
        format!("{}@{}", self.next_seq, self.id)
    }

    pub fn get_frontier(&self) -> Vec<String> {
        // Search versions in the tree
        let mut versions = HashSet::new();
        let mut stack = vec![&self.root];
        while let Some(node) = stack.pop() {
            if let Some(v) = &node.version {
                versions.insert(v.clone());
            }
            for child in &node.next {
                stack.push(child);
            }
        }
        versions.into_iter().collect()
    }
}