#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Navigation {
#[default]
Forward,
Back,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Router<P> {
stack: Vec<P>,
direction: Navigation,
}
impl<P: Clone + PartialEq> Router<P> {
#[must_use]
pub fn new(root: P) -> Self {
Self { stack: vec![root], direction: Navigation::Forward }
}
#[must_use]
pub fn current(&self) -> &P {
self.stack.last().expect("the stack always holds the root page")
}
pub fn push(&mut self, page: P) {
if *self.current() != page {
self.stack.push(page);
self.direction = Navigation::Forward;
}
}
pub fn back(&mut self) -> bool {
if self.stack.len() > 1 {
self.stack.pop();
self.direction = Navigation::Back;
true
} else {
false
}
}
pub fn replace(&mut self, page: P) {
if let Some(top) = self.stack.last_mut() {
*top = page;
self.direction = Navigation::Forward;
}
}
#[must_use]
pub fn can_go_back(&self) -> bool {
self.stack.len() > 1
}
#[must_use]
pub fn direction(&self) -> Navigation {
self.direction
}
#[must_use]
pub fn history(&self) -> &[P] {
&self.stack
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn push_back_and_replace() {
let mut router = Router::new("home");
router.push("button");
router.push("button");
router.push("list");
assert_eq!(router.history(), &["home", "button", "list"]);
assert_eq!(router.direction(), Navigation::Forward);
assert!(router.back());
assert_eq!(router.direction(), Navigation::Back);
assert_eq!(*router.current(), "button");
router.replace("tabs");
assert_eq!(router.history(), &["home", "tabs"]);
assert!(router.back());
assert!(!router.back());
assert!(!router.can_go_back());
}
}