use crate::ir::NodeId;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Mutex;
static NEXT_ID: AtomicU64 = AtomicU64::new(1);
static NODE_ID_MAP: Mutex<Option<HashMap<NodeId, String>>> = Mutex::new(None);
#[doc(hidden)]
#[inline]
pub fn node_id_str(id: NodeId) -> String {
let mut guard = NODE_ID_MAP.lock().unwrap();
let map = guard.get_or_insert_with(HashMap::new);
map.entry(id)
.or_insert_with(|| NEXT_ID.fetch_add(1, Ordering::Relaxed).to_string())
.clone()
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum Patch {
#[serde(rename_all = "camelCase")]
Create {
id: String,
element_type: String,
props: indexmap::IndexMap<String, Value>,
},
#[serde(rename_all = "camelCase")]
SetProp {
id: String,
name: String,
value: Value,
},
#[serde(rename_all = "camelCase")]
RemoveProp {
id: String,
name: String,
},
#[serde(rename_all = "camelCase")]
SetText {
id: String,
text: String,
},
#[serde(rename_all = "camelCase")]
Insert {
parent_id: String,
id: String,
before_id: Option<String>,
},
#[serde(rename_all = "camelCase")]
Move {
parent_id: String,
id: String,
before_id: Option<String>,
},
#[serde(rename_all = "camelCase")]
Remove { id: String },
}
impl Patch {
pub fn create(
id: NodeId,
element_type: String,
props: indexmap::IndexMap<String, Value>,
) -> Self {
Self::Create {
id: node_id_str(id),
element_type,
props,
}
}
pub fn set_prop(id: NodeId, name: String, value: Value) -> Self {
Self::SetProp {
id: node_id_str(id),
name,
value,
}
}
pub fn remove_prop(id: NodeId, name: String) -> Self {
Self::RemoveProp {
id: node_id_str(id),
name,
}
}
pub fn set_text(id: NodeId, text: String) -> Self {
Self::SetText {
id: node_id_str(id),
text,
}
}
pub fn insert(parent_id: NodeId, id: NodeId, before_id: Option<NodeId>) -> Self {
Self::Insert {
parent_id: node_id_str(parent_id),
id: node_id_str(id),
before_id: before_id.map(node_id_str),
}
}
pub fn insert_root(id: NodeId) -> Self {
Self::Insert {
parent_id: "root".to_string(),
id: node_id_str(id),
before_id: None,
}
}
pub fn move_node(parent_id: NodeId, id: NodeId, before_id: Option<NodeId>) -> Self {
Self::Move {
parent_id: node_id_str(parent_id),
id: node_id_str(id),
before_id: before_id.map(node_id_str),
}
}
pub fn remove(id: NodeId) -> Self {
Self::Remove {
id: node_id_str(id),
}
}
}