#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct OperationHistory {
entries: Vec<String>,
}
impl OperationHistory {
pub fn new() -> Self {
Self::default()
}
pub fn from_entry(entry: impl Into<String>) -> Self {
Self {
entries: vec![entry.into()],
}
}
pub fn entries(&self) -> &[String] {
&self.entries
}
pub fn to_vec(&self) -> Vec<String> {
self.entries.clone()
}
pub fn push(&mut self, entry: impl Into<String>) {
self.entries.push(entry.into());
}
pub fn extend_prefixed(&mut self, prefix: &str, other: &OperationHistory) {
self.entries.extend(
other
.entries
.iter()
.map(|entry| format!("{prefix}.{entry}")),
);
}
pub fn with_entry(&self, entry: impl Into<String>) -> Self {
let mut out = self.clone();
out.push(entry);
out
}
}
impl From<Vec<String>> for OperationHistory {
fn from(entries: Vec<String>) -> Self {
Self { entries }
}
}
impl From<OperationHistory> for Vec<String> {
fn from(history: OperationHistory) -> Self {
history.entries
}
}
pub trait HasHistory {
fn operation_history(&self) -> &OperationHistory;
fn operation_history_mut(&mut self) -> &mut OperationHistory;
fn history(&self) -> &[String] {
self.operation_history().entries()
}
fn record_history(&mut self, entry: impl Into<String>) {
self.operation_history_mut().push(entry);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn history_preserves_order_and_prefixes_sources() {
let mut history = OperationHistory::from_entry("surface.constant(value=1)");
history.push("surface.add_scalar(2)");
let rhs = OperationHistory::from_entry("surface.constant(value=3)");
history.extend_prefixed("rhs", &rhs);
history.push("surface.plus(surface)");
assert_eq!(
history.entries(),
&[
"surface.constant(value=1)".to_string(),
"surface.add_scalar(2)".to_string(),
"rhs.surface.constant(value=3)".to_string(),
"surface.plus(surface)".to_string(),
]
);
}
}