moduforge_transform/
transform.rs1use std::{sync::Arc};
2
3use moduforge_model::{node_pool::NodePool, schema::Schema, tree::Tree};
4
5use crate::TransformResult;
6
7use super::step::{Step, StepResult};
8
9#[derive(Debug, Clone)]
11enum LazyDoc {
12 Original(Arc<NodePool>),
14 Pending {
16 base: Arc<NodePool>,
17 steps: im::Vector<Arc<dyn Step>>,
18 },
19 Computed(Arc<NodePool>),
21}
22
23#[derive(Debug, Clone)]
24pub struct Transform {
25 pub base_doc: Arc<NodePool>,
27 lazy_doc: LazyDoc,
29 draft: Option<Tree>,
31 pub steps: im::Vector<Arc<dyn Step>>,
33 pub invert_steps: im::Vector<Arc<dyn Step>>,
35 pub schema: Arc<Schema>,
37 needs_recompute: bool,
39}
40
41impl Transform {
42 pub fn new(
43 doc: Arc<NodePool>,
44 schema: Arc<Schema>,
45 ) -> Transform {
46 Transform {
47 base_doc: doc.clone(),
48 lazy_doc: LazyDoc::Original(doc),
49 draft: None,
50 steps: im::Vector::new(),
51 invert_steps: im::Vector::new(),
52 schema,
53 needs_recompute: false,
54 }
55 }
56
57 pub fn doc(&self) -> Arc<NodePool> {
59 match &self.lazy_doc {
60 LazyDoc::Original(doc) => doc.clone(),
61 LazyDoc::Computed(doc) => doc.clone(),
62 LazyDoc::Pending { base, steps } => {
63 self.compute_doc_state(base.clone(), steps.clone())
65 }
66 }
67 }
68
69 fn get_draft(&mut self) -> &mut Tree {
71 if self.draft.is_none() {
72 self.draft = Some(self.base_doc.get_inner().as_ref().clone());
74 }
75 self.draft.as_mut().unwrap()
76 }
77
78 pub fn step(
79 &mut self,
80 step: Arc<dyn Step>,
81 ) -> TransformResult<()> {
82 let schema = self.schema.clone();
83 let draft = self.get_draft();
84 let result: StepResult = step.apply(draft, schema)?;
85
86 match result.failed {
87 Some(message) => Err(anyhow::anyhow!(message)),
88 None => {
89 self.add_step(step);
90 Ok(())
91 },
92 }
93 }
94
95 pub fn doc_changed(&self) -> bool {
97 !self.steps.is_empty()
98 }
99
100 fn add_step(&mut self, step: Arc<dyn Step>) {
102 if let Some(invert_step) = step.invert(&self.base_doc.get_inner()) {
104 self.invert_steps.push_back(invert_step);
105 }
106
107 self.steps.push_back(step.clone());
108
109 self.lazy_doc = LazyDoc::Pending {
111 base: self.base_doc.clone(),
112 steps: self.steps.clone(),
113 };
114 self.needs_recompute = true;
115 }
116
117 fn compute_doc_state(
119 &self,
120 base: Arc<NodePool>,
121 steps: im::Vector<Arc<dyn Step>>,
122 ) -> Arc<NodePool> {
123 if steps.is_empty() {
124 return base;
125 }
126
127 if let Some(ref draft) = self.draft {
129 NodePool::new(Arc::new(draft.clone()))
130 } else {
131 base
132 }
133 }
134
135 pub fn apply_steps_batch(&mut self, steps: Vec<Arc<dyn Step>>) -> TransformResult<()> {
137 let schema = self.schema.clone();
138 let base_doc_inner = self.base_doc.get_inner().clone();
139
140 let mut new_invert_steps = Vec::new();
142 for step in &steps {
143 if let Some(invert_step) = step.invert(&base_doc_inner) {
144 new_invert_steps.push(invert_step);
145 }
146 }
147
148 let draft = self.get_draft();
149
150 for step in &steps {
152 let result = step.apply(draft, schema.clone())?;
153 if let Some(message) = result.failed {
154 return Err(anyhow::anyhow!(message));
155 }
156 }
157
158 for step in steps {
160 self.steps.push_back(step);
161 }
162 for invert_step in new_invert_steps {
163 self.invert_steps.push_back(invert_step);
164 }
165
166 self.lazy_doc = LazyDoc::Pending {
168 base: self.base_doc.clone(),
169 steps: self.steps.clone(),
170 };
171 self.needs_recompute = true;
172
173 Ok(())
174 }
175
176 pub fn commit(&mut self) {
179 if self.needs_recompute && self.draft.is_some() {
180 let new_doc = NodePool::new(Arc::new(self.draft.as_ref().unwrap().clone()));
181 self.base_doc = new_doc.clone();
182 self.lazy_doc = LazyDoc::Computed(new_doc);
183 self.draft = None;
184 self.needs_recompute = false;
186 }
187 }
188
189 pub fn rollback(&mut self) {
191 self.lazy_doc = LazyDoc::Original(self.base_doc.clone());
192 self.draft = None;
193 self.steps = im::Vector::new();
194 self.invert_steps = im::Vector::new();
195 self.needs_recompute = false;
196 }
197
198 pub fn rollback_steps(&mut self, count: usize) -> TransformResult<()> {
200 if count > self.invert_steps.len() {
201 return Err(anyhow::anyhow!("回滚步骤数量超出历史记录"));
202 }
203
204 let schema = self.schema.clone();
205
206 let mut invert_steps_to_apply = Vec::new();
208 for _ in 0..count {
209 if let Some(invert_step) = self.invert_steps.pop_back() {
210 invert_steps_to_apply.push(invert_step);
211 self.steps.pop_back();
212 }
213 }
214
215 let draft = self.get_draft();
216
217 for invert_step in invert_steps_to_apply {
219 invert_step.apply(draft, schema.clone())?;
220 }
221
222 self.needs_recompute = true;
223 Ok(())
224 }
225
226 pub fn clear_history(&mut self) {
228 self.steps = im::Vector::new();
229 self.invert_steps = im::Vector::new();
230 }
231
232 pub fn history_size(&self) -> usize {
234 self.steps.len()
235 }
236}