memory.rs 3.4 KB

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