dioxus_history/
memory.rs

1use std::cell::RefCell;
2
3use crate::History;
4
5struct MemoryHistoryState {
6    current: String,
7    history: Vec<String>,
8    future: Vec<String>,
9}
10
11/// A [`History`] provider that stores all navigation information in memory.
12pub struct MemoryHistory {
13    state: RefCell<MemoryHistoryState>,
14    base_path: Option<String>,
15}
16
17impl Default for MemoryHistory {
18    fn default() -> Self {
19        Self::with_initial_path("/")
20    }
21}
22
23impl MemoryHistory {
24    /// Create a [`MemoryHistory`] starting at `path`.
25    ///
26    /// ```rust
27    /// # use dioxus::prelude::*;
28    /// # #[component]
29    /// # fn Index() -> Element { VNode::empty() }
30    /// # #[component]
31    /// # fn OtherPage() -> Element { VNode::empty() }
32    /// #[derive(Clone, Routable, Debug, PartialEq)]
33    /// enum Route {
34    ///     #[route("/")]
35    ///     Index {},
36    ///     #[route("/some-other-page")]
37    ///     OtherPage {},
38    /// }
39    ///
40    /// let mut history = dioxus_history::MemoryHistory::with_initial_path(Route::Index {});
41    /// assert_eq!(history.current_route(), Route::Index {}.to_string());
42    /// assert_eq!(history.can_go_back(), false);
43    /// ```
44    pub fn with_initial_path(path: impl ToString) -> Self {
45        Self {
46            state: MemoryHistoryState{
47                current: path.to_string().parse().unwrap_or_else(|err| {
48                    panic!("index route does not exist:\n{err}\n use MemoryHistory::with_initial_path to set a custom path")
49                }),
50                history: Vec::new(),
51                future: Vec::new(),
52            }.into(),
53            base_path: None,
54        }
55    }
56
57    /// Set the base path for the history. All routes will be prefixed with this path when rendered.
58    ///
59    /// ```rust
60    /// # use dioxus_history::*;
61    /// let mut history = MemoryHistory::default().with_prefix("/my-app");
62    ///
63    /// // The base path is set to "/my-app"
64    /// assert_eq!(history.current_prefix(), Some("/my-app".to_string()));
65    /// ```
66    pub fn with_prefix(mut self, prefix: impl ToString) -> Self {
67        self.base_path = Some(prefix.to_string());
68        self
69    }
70}
71
72impl History for MemoryHistory {
73    fn current_prefix(&self) -> Option<String> {
74        self.base_path.clone()
75    }
76
77    fn current_route(&self) -> String {
78        self.state.borrow().current.clone()
79    }
80
81    fn can_go_back(&self) -> bool {
82        !self.state.borrow().history.is_empty()
83    }
84
85    fn go_back(&self) {
86        let mut write = self.state.borrow_mut();
87        if let Some(last) = write.history.pop() {
88            let old = std::mem::replace(&mut write.current, last);
89            write.future.push(old);
90        }
91    }
92
93    fn can_go_forward(&self) -> bool {
94        !self.state.borrow().future.is_empty()
95    }
96
97    fn go_forward(&self) {
98        let mut write = self.state.borrow_mut();
99        if let Some(next) = write.future.pop() {
100            let old = std::mem::replace(&mut write.current, next);
101            write.history.push(old);
102        }
103    }
104
105    fn push(&self, new: String) {
106        let mut write = self.state.borrow_mut();
107        // don't push the same route twice
108        if write.current == new {
109            return;
110        }
111        let old = std::mem::replace(&mut write.current, new);
112        write.history.push(old);
113        write.future.clear();
114    }
115
116    fn replace(&self, path: String) {
117        let mut write = self.state.borrow_mut();
118        write.current = path;
119    }
120}