use serde::{Deserialize, Serialize};
pub trait HistoryState {
fn history(&self) -> &History;
fn set_history(&mut self, history: History);
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct History {
history: Vec<String>,
}
impl History {
pub fn new(default: Option<&str>) -> Self {
History {
history: default.map(|d| vec![d.to_string()]).unwrap_or(Vec::new()),
}
}
pub fn push(&mut self, site: String) {
self.history.push(site);
}
pub fn pop(&mut self) {
self.history.pop();
}
pub fn latest(&self) -> Option<&String> {
self.history.last()
}
}
pub trait HistoryAction {
fn navigation(&self) -> Option<&Navigation>;
fn navigation_push(site: &str) -> Self;
fn navigation_replace(site: &str) -> Self;
fn navigation_go_back() -> Self;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Navigation {
Push(String),
Replace(String),
GoBack,
}
pub fn reduce_history<A, S>(action: A, state: S) -> S
where
A: HistoryAction,
S: Clone + HistoryState,
{
let mut state = state.clone();
if let Some(navigation) = action.navigation() {
match navigation {
Navigation::Push(site) => {
let mut history = state.history().clone();
history.push(site.clone());
state.set_history(history);
}
Navigation::Replace(site) => {
let mut history = Vec::new();
history.push(site.clone());
state.set_history(History { history });
}
Navigation::GoBack => {
let mut history = state.history().clone();
history.pop();
state.set_history(history);
}
}
}
state
}