mf_transform/
transform.rs1use std::{sync::Arc};
2
3use mf_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 { base: Arc<NodePool>, steps: imbl::Vector<Arc<dyn Step>> },
16    Computed(Arc<NodePool>),
18}
19
20#[derive(Debug, Clone)]
21pub struct Transform {
22    pub base_doc: Arc<NodePool>,
24    lazy_doc: LazyDoc,
26    draft: Option<Tree>,
28    pub steps: imbl::Vector<Arc<dyn Step>>,
30    pub invert_steps: imbl::Vector<Arc<dyn Step>>,
32    pub schema: Arc<Schema>,
34    needs_recompute: bool,
36}
37
38impl Transform {
39    pub fn new(
40        doc: Arc<NodePool>,
41        schema: Arc<Schema>,
42    ) -> Transform {
43        Transform {
44            base_doc: doc.clone(),
45            lazy_doc: LazyDoc::Original(doc),
46            draft: None,
47            steps: imbl::Vector::new(),
48            invert_steps: imbl::Vector::new(),
49            schema,
50            needs_recompute: false,
51        }
52    }
53
54    pub fn doc(&self) -> Arc<NodePool> {
56        match &self.lazy_doc {
57            LazyDoc::Original(doc) => doc.clone(),
58            LazyDoc::Computed(doc) => doc.clone(),
59            LazyDoc::Pending { base, steps } => {
60                self.compute_doc_state(base.clone(), steps.clone())
62            },
63        }
64    }
65
66    fn get_draft(&mut self) -> TransformResult<&mut Tree> {
68        if self.draft.is_none() {
69            self.draft = Some(self.base_doc.get_inner().as_ref().clone());
71        }
72        self.draft.as_mut().ok_or_else(|| anyhow::anyhow!("草稿状态未初始化"))
73    }
74
75    pub fn step(
76        &mut self,
77        step: Arc<dyn Step>,
78    ) -> TransformResult<()> {
79        let schema = self.schema.clone();
80        let draft = self.get_draft()?;
81        let result: StepResult = step.apply(draft, schema)?;
82
83        match result.failed {
84            Some(message) => Err(anyhow::anyhow!(message)),
85            None => {
86                self.add_step(step);
87                Ok(())
88            },
89        }
90    }
91
92    pub fn doc_changed(&self) -> bool {
94        !self.steps.is_empty()
95    }
96
97    fn add_step(
99        &mut self,
100        step: Arc<dyn Step>,
101    ) {
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: imbl::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(
137        &mut self,
138        steps: Vec<Arc<dyn Step>>,
139    ) -> TransformResult<()> {
140        let schema = self.schema.clone();
141        let base_doc_inner = self.base_doc.get_inner().clone();
142
143        let mut new_invert_steps = Vec::new();
145        for step in &steps {
146            if let Some(invert_step) = step.invert(&base_doc_inner) {
147                new_invert_steps.push(invert_step);
148            }
149        }
150
151        let draft = self.get_draft()?;
152
153        for step in &steps {
155            let result = step.apply(draft, schema.clone())?;
156            if let Some(message) = result.failed {
157                return Err(anyhow::anyhow!(message));
158            }
159        }
160
161        for step in steps {
163            self.steps.push_back(step);
164        }
165        for invert_step in new_invert_steps {
166            self.invert_steps.push_back(invert_step);
167        }
168
169        self.lazy_doc = LazyDoc::Pending {
171            base: self.base_doc.clone(),
172            steps: self.steps.clone(),
173        };
174        self.needs_recompute = true;
175
176        Ok(())
177    }
178
179    pub fn commit(&mut self) -> TransformResult<()> {
183        if self.needs_recompute && self.draft.is_some() {
184            let draft_tree = self
185                .draft
186                .as_ref()
187                .ok_or_else(|| anyhow::anyhow!("尝试提交时草稿状态意外丢失"))?;
188            let new_doc = NodePool::new(Arc::new(draft_tree.clone()));
189            self.base_doc = new_doc.clone();
190            self.lazy_doc = LazyDoc::Computed(new_doc);
191            self.draft = None;
192            self.needs_recompute = false;
194        }
195        Ok(())
196    }
197
198    pub fn rollback(&mut self) {
200        self.lazy_doc = LazyDoc::Original(self.base_doc.clone());
201        self.draft = None;
202        self.steps = imbl::Vector::new();
203        self.invert_steps = imbl::Vector::new();
204        self.needs_recompute = false;
205    }
206
207    pub fn rollback_steps(
209        &mut self,
210        count: usize,
211    ) -> TransformResult<()> {
212        if count > self.invert_steps.len() {
213            return Err(anyhow::anyhow!("回滚步骤数量超出历史记录"));
214        }
215
216        let schema = self.schema.clone();
217
218        let mut invert_steps_to_apply = Vec::new();
220        for _ in 0..count {
221            if let Some(invert_step) = self.invert_steps.pop_back() {
222                invert_steps_to_apply.push(invert_step);
223                self.steps.pop_back();
224            }
225        }
226
227        let draft = self.get_draft()?;
228
229        for invert_step in invert_steps_to_apply {
231            invert_step.apply(draft, schema.clone())?;
232        }
233
234        self.needs_recompute = true;
235        Ok(())
236    }
237
238    pub fn clear_history(&mut self) {
240        self.steps = imbl::Vector::new();
241        self.invert_steps = imbl::Vector::new();
242    }
243
244    pub fn history_size(&self) -> usize {
246        self.steps.len()
247    }
248}