CommandHistory

This commit is contained in:
mars 2022-09-17 06:16:57 -06:00
parent bb72e6d753
commit 180cd516ea
1 changed files with 123 additions and 30 deletions

View File

@ -1,13 +1,63 @@
use super::{Graph, GraphError, GraphResult};
use crate::node::{Edge, Node, NodeKind, SlotIndex};
use std::fmt::Debug;
pub trait Command {
pub trait Command: Debug {
fn undo(&self, graph: &Graph) -> GraphResult<DynCommand>;
fn apply(&self, graph: &mut Graph) -> GraphResult<()>;
}
pub type DynCommand = Box<dyn Command>;
pub struct CommandHistory {
commands: Vec<(DynCommand, DynCommand)>,
cursor: usize,
}
impl CommandHistory {
pub fn new() -> Self {
Self {
commands: Vec::new(),
cursor: 0,
}
}
pub fn push(&mut self, graph: &mut Graph, cmd: DynCommand) -> GraphResult<()> {
let undo = cmd.undo(graph)?;
cmd.apply(graph)?;
// Discard redo history on new push
if self.cursor < self.commands.len() {
self.commands.truncate(self.cursor);
}
self.commands.push((cmd, undo));
self.cursor += 1;
Ok(())
}
pub fn undo(&mut self, graph: &mut Graph) -> GraphResult<bool> {
if self.cursor > 0 {
self.cursor -= 1;
self.commands[self.cursor].1.apply(graph)?;
Ok(true)
} else {
Ok(false)
}
}
pub fn redo(&mut self, graph: &mut Graph) -> GraphResult<bool> {
if self.cursor < self.commands.len() {
self.commands[self.cursor].0.apply(graph)?;
self.cursor += 1;
Ok(true)
} else {
Ok(false)
}
}
}
#[derive(Clone, Debug)]
pub struct CreateNode {
pub kind: NodeKind,
@ -171,7 +221,7 @@ impl Command for DeleteEdge {
.get_mut(self.input.slot)
.ok_or(GraphError::InvalidReference)?;
if input.is_some() {
if input.is_none() {
Err(GraphError::MissingEdge)
} else {
*input = None;
@ -185,6 +235,58 @@ mod tests {
use super::*;
use crate::node::AtomOp;
impl CommandHistory {
pub fn push_multi(
&mut self,
graph: &mut Graph,
cmds: impl IntoIterator<Item = DynCommand>,
) -> GraphResult<()> {
for cmd in cmds {
println!("{:#?}", cmd);
self.push(graph, cmd)?;
println!("{:#?}", graph);
}
Ok(())
}
pub fn rewind(&mut self, graph: &mut Graph) -> GraphResult<()> {
while self.cursor > 0 {
self.cursor -= 1;
let undo = &self.commands[self.cursor].1;
println!("{:#?}", undo);
undo.apply(graph)?;
println!("{:#?}", graph);
}
Ok(())
}
}
fn three_node_add_cmds() -> Vec<DynCommand> {
vec![
Box::new(CreateNode::from(Node::literal(1.0))),
Box::new(CreateNode::from(Node::literal(2.0))),
Box::new(CreateNode::from(Node {
kind: NodeKind::Op(AtomOp::Add),
pos: glam::Vec2::ZERO,
inputs: vec![None; 2],
})),
Box::new(SetEdge {
edge: Edge {
input: SlotIndex { node: 0, slot: 0 },
output: SlotIndex { node: 2, slot: 0 },
},
}),
Box::new(SetEdge {
edge: Edge {
input: SlotIndex { node: 1, slot: 0 },
output: SlotIndex { node: 2, slot: 1 },
},
}),
]
}
#[test]
fn create_node() -> GraphResult<()> {
let mut graph = Graph::new();
@ -207,39 +309,30 @@ mod tests {
}
#[test]
fn set_edge() -> GraphResult<()> {
fn three_node_add() -> GraphResult<()> {
let mut graph = Graph::new();
CreateNode::from(Node::literal(1.0)).apply(&mut graph)?;
CreateNode::from(Node::literal(2.0)).apply(&mut graph)?;
CreateNode::from(Node {
kind: NodeKind::Op(AtomOp::Add),
pos: glam::Vec2::ZERO,
inputs: vec![None; 2],
})
.apply(&mut graph)?;
SetEdge {
edge: Edge {
input: SlotIndex { node: 0, slot: 0 },
output: SlotIndex { node: 2, slot: 0 },
},
}
.apply(&mut graph)?;
SetEdge {
edge: Edge {
input: SlotIndex { node: 1, slot: 0 },
output: SlotIndex { node: 2, slot: 1 },
},
}
.apply(&mut graph)?;
let cmds = three_node_add_cmds();
println!("{:#?}", graph);
for cmd in cmds.into_iter() {
println!("{:#?}", cmd);
cmd.apply(&mut graph)?;
println!("{:#?}", graph);
}
graph.topological_order()?;
Ok(())
}
#[test]
fn three_node_add_rewind() -> GraphResult<()> {
let mut graph = Graph::new();
let mut history = CommandHistory::new();
let cmds = three_node_add_cmds();
history.push_multi(&mut graph, cmds)?;
graph.topological_order()?;
history.rewind(&mut graph)?;
assert_eq!(graph.nodes.len(), 0);
Ok(())
}
}