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