Redo the most-recently-undone interaction: re-apply every delta from the current `head` forward to (and including) the checkpoint rev, advancing `head` to it. Collects the forward span by walking parents back from the checkpoint to `head` (the chain is linear in the silent solo zone).
(&mut self)
| 403 | /// (and including) the checkpoint rev, advancing `head` to it. Collects the forward span by walking |
| 404 | /// parents back from the checkpoint to `head` (the chain is linear in the silent solo zone). |
| 405 | pub fn redo(&mut self) -> Result<Rev, CrdtError> { |
| 406 | let checkpoint = self.document.redo_stack.pop().ok_or(CrdtError::NothingToRedo)?; |
| 407 | |
| 408 | let mut forward = Vec::new(); |
| 409 | let mut cursor = Some(checkpoint); |
| 410 | while cursor != self.document.head { |
| 411 | let Some(rev) = cursor else { break }; |
| 412 | let delta = self.document.history.get(rev).ok_or(CrdtError::NotFoundInHistory(rev))?.clone(); |
| 413 | cursor = delta.parent; |
| 414 | forward.push(delta); |
| 415 | } |
| 416 | |
| 417 | // Force-apply so each forward value wins the LWW tie against the reverse that undo force-applied |
| 418 | // at the same timestamp. Symmetric with `revert_delta`. |
| 419 | for delta in forward.into_iter().rev() { |
| 420 | self.document.force_apply_op(delta.kind.clone(), delta.timestamp)?; |
| 421 | } |
| 422 | self.document.head = Some(checkpoint); |
| 423 | |
| 424 | // Redo runs with an empty hot log; keep the retired snapshot in lockstep with the working registry. |
| 425 | self.document.retired_snapshot = self.document.working_registry.clone(); |
| 426 | Ok(checkpoint) |
| 427 | } |
| 428 | |
| 429 | /// Build a synthetic linear history whose replay reproduces `registry`. Each op gets a |
| 430 | /// freshly-ticked clock timestamp and chains to the previous op's `Rev`. |