topola/src/autorouter/history.rs

76 lines
2.0 KiB
Rust

// SPDX-FileCopyrightText: 2024 Topola contributors
//
// SPDX-License-Identifier: MIT
//! Manages command history operations, allowing for undoing and redoing commands.
//! Handles error scenarios related to command history, maintaining lists of executed
//! and undone commands for easy navigation.
use derive_getters::{Dissolve, Getters};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::{autorouter::execution::Command, board::edit::BoardEdit};
#[derive(Error, Debug, Clone)]
pub enum HistoryError {
#[error("no previous command")]
NoPreviousCommand,
#[error("no next command")]
NoNextCommand,
}
#[derive(Debug, Clone, Getters, Serialize, Deserialize)]
#[serde(transparent)]
pub struct HistoryEntry {
command: Command,
#[serde(skip)]
edit: Option<BoardEdit>,
}
#[derive(Debug, Default, Clone, Getters, Dissolve, Serialize, Deserialize)]
pub struct History {
done: Vec<HistoryEntry>,
undone: Vec<HistoryEntry>,
}
impl History {
pub fn new() -> Self {
Self::default()
}
pub fn do_(&mut self, command: Command, edit: Option<BoardEdit>) {
self.done.push(HistoryEntry { command, edit });
}
pub fn undo(&mut self) -> Result<(), HistoryError> {
let Some(command) = self.done.pop() else {
return Err(HistoryError::NoPreviousCommand);
};
self.undone.push(command);
Ok(())
}
pub fn redo(&mut self) -> Result<(), HistoryError> {
let Some(command) = self.undone.pop() else {
return Err(HistoryError::NoNextCommand);
};
self.done.push(command);
Ok(())
}
pub fn set_undone(&mut self, iter: impl IntoIterator<Item = HistoryEntry>) {
self.undone = Vec::from_iter(iter);
}
pub fn last_done(&self) -> Result<&HistoryEntry, HistoryError> {
self.done.last().ok_or(HistoryError::NoPreviousCommand)
}
pub fn last_undone(&self) -> Result<&HistoryEntry, HistoryError> {
self.undone.last().ok_or(HistoryError::NoNextCommand)
}
}