use std::cell::RefCell; use crate::History; struct MemoryHistoryState { current: String, history: Vec, future: Vec, } /// A [`History`] provider that stores all navigation information in memory. pub struct MemoryHistory { state: RefCell, base_path: Option, } impl Default for MemoryHistory { fn default() -> Self { Self::with_initial_path("/") } } impl MemoryHistory { /// Create a [`MemoryHistory`] starting at `path`. /// /// ```rust /// # use dioxus_router::prelude::*; /// # use dioxus::prelude::*; /// # #[component] /// # fn Index() -> Element { VNode::empty() } /// # #[component] /// # fn OtherPage() -> Element { VNode::empty() } /// #[derive(Clone, Routable, Debug, PartialEq)] /// enum Route { /// #[route("/")] /// Index {}, /// #[route("/some-other-page")] /// OtherPage {}, /// } /// /// let mut history = dioxus_history::MemoryHistory::with_initial_path(Route::Index {}); /// assert_eq!(history.current_route(), Route::Index {}.to_string()); /// assert_eq!(history.can_go_back(), false); /// ``` pub fn with_initial_path(path: impl ToString) -> Self { Self { state: MemoryHistoryState{ current: path.to_string().parse().unwrap_or_else(|err| { panic!("index route does not exist:\n{err}\n use MemoryHistory::with_initial_path to set a custom path") }), history: Vec::new(), future: Vec::new(), }.into(), base_path: None, } } /// Set the base path for the history. All routes will be prefixed with this path when rendered. /// /// ```rust /// # use dioxus_history::*; /// let mut history = MemoryHistory::default().with_prefix("/my-app"); /// /// // The base path is set to "/my-app" /// assert_eq!(history.current_prefix(), Some("/my-app".to_string())); /// ``` pub fn with_prefix(mut self, prefix: impl ToString) -> Self { self.base_path = Some(prefix.to_string()); self } } impl History for MemoryHistory { fn current_prefix(&self) -> Option { self.base_path.clone() } fn current_route(&self) -> String { self.state.borrow().current.clone() } fn can_go_back(&self) -> bool { !self.state.borrow().history.is_empty() } fn go_back(&self) { let mut write = self.state.borrow_mut(); if let Some(last) = write.history.pop() { let old = std::mem::replace(&mut write.current, last); write.future.push(old); } } fn can_go_forward(&self) -> bool { !self.state.borrow().future.is_empty() } fn go_forward(&self) { let mut write = self.state.borrow_mut(); if let Some(next) = write.future.pop() { let old = std::mem::replace(&mut write.current, next); write.history.push(old); } } fn push(&self, new: String) { let mut write = self.state.borrow_mut(); // don't push the same route twice if write.current == new { return; } let old = std::mem::replace(&mut write.current, new); write.history.push(old); write.future.clear(); } fn replace(&self, path: String) { let mut write = self.state.borrow_mut(); write.current = path; } }