hypen_engine/reconcile/
patch.rs1use crate::ir::NodeId;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::collections::HashMap;
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::sync::Mutex;
7
8static NEXT_ID: AtomicU64 = AtomicU64::new(1);
10
11static NODE_ID_MAP: Mutex<Option<HashMap<NodeId, String>>> = Mutex::new(None);
15
16#[inline]
22pub fn node_id_str(id: NodeId) -> String {
23 let mut guard = NODE_ID_MAP.lock().unwrap();
24 let map = guard.get_or_insert_with(HashMap::new);
25 map.entry(id)
26 .or_insert_with(|| NEXT_ID.fetch_add(1, Ordering::Relaxed).to_string())
27 .clone()
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32#[serde(tag = "type", rename_all = "camelCase")]
33pub enum Patch {
34 #[serde(rename_all = "camelCase")]
36 Create {
37 id: String,
38 element_type: String,
39 props: indexmap::IndexMap<String, Value>,
40 },
41
42 #[serde(rename_all = "camelCase")]
44 SetProp {
45 id: String,
46 name: String,
47 value: Value,
48 },
49
50 #[serde(rename_all = "camelCase")]
52 RemoveProp { id: String, name: String },
53
54 #[serde(rename_all = "camelCase")]
56 SetText { id: String, text: String },
57
58 #[serde(rename_all = "camelCase")]
60 Insert {
61 parent_id: String,
62 id: String,
63 before_id: Option<String>,
64 },
65
66 #[serde(rename_all = "camelCase")]
68 Move {
69 parent_id: String,
70 id: String,
71 before_id: Option<String>,
72 },
73
74 #[serde(rename_all = "camelCase")]
76 Remove { id: String },
77}
78
79impl Patch {
80 pub fn create(
81 id: NodeId,
82 element_type: String,
83 props: indexmap::IndexMap<String, Value>,
84 ) -> Self {
85 Self::Create {
86 id: node_id_str(id),
87 element_type,
88 props,
89 }
90 }
91
92 pub fn set_prop(id: NodeId, name: String, value: Value) -> Self {
93 Self::SetProp {
94 id: node_id_str(id),
95 name,
96 value,
97 }
98 }
99
100 pub fn remove_prop(id: NodeId, name: String) -> Self {
101 Self::RemoveProp {
102 id: node_id_str(id),
103 name,
104 }
105 }
106
107 pub fn set_text(id: NodeId, text: String) -> Self {
108 Self::SetText {
109 id: node_id_str(id),
110 text,
111 }
112 }
113
114 pub fn insert(parent_id: NodeId, id: NodeId, before_id: Option<NodeId>) -> Self {
115 Self::Insert {
116 parent_id: node_id_str(parent_id),
117 id: node_id_str(id),
118 before_id: before_id.map(node_id_str),
119 }
120 }
121
122 pub fn insert_root(id: NodeId) -> Self {
124 Self::Insert {
125 parent_id: "root".to_string(),
126 id: node_id_str(id),
127 before_id: None,
128 }
129 }
130
131 pub fn move_node(parent_id: NodeId, id: NodeId, before_id: Option<NodeId>) -> Self {
132 Self::Move {
133 parent_id: node_id_str(parent_id),
134 id: node_id_str(id),
135 before_id: before_id.map(node_id_str),
136 }
137 }
138
139 pub fn remove(id: NodeId) -> Self {
140 Self::Remove {
141 id: node_id_str(id),
142 }
143 }
144}