1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
use std::collections::VecDeque; use std::ops::Deref; // TODO when const generics lands, it would be useful to add a usize type parameter over the max number of elements. // It would also be interesting to see if a diffing history implementation could be built over types // that can represent themselves as diffs - where reversible transitions can be recorded instead of values // and the transitions can be rolled back. // That would probably have worse performance in exchange for smaller size. /// Wrapper that keeps track of prior values that have been assigned to it. /// /// It keeps values that have been `set` for it around for the duration of its lifetime, /// or until they are dropped by calling `reset` or `forget`. /// /// Prior values can be iterated over as well. pub struct History<T>(VecDeque<T>); impl<T> History<T> { /// Creates a new history wrapper. pub fn new(value: T) -> Self { let mut vec = VecDeque::new(); vec.push_front(value); Self(vec) } /// Set the value represented by the `History` struct. /// /// This pushes the new value into the front of a list, /// where the front-most value represents the most recent value. /// /// # Example /// ``` ///# use yewtil::History; /// let mut history = History::new(0); /// history.set(1); /// /// assert_eq!(*history, 1); /// assert_eq!(history.count(), 2); /// ``` pub fn set(&mut self, value: T) { self.0.push_front(value) } /// Replaces the current value without creating a history entry. /// /// # Example /// ``` ///# use yewtil::History; /// let mut history = History::new(0); /// history.replace(1); /// /// assert_eq!(*history, 1); /// assert_eq!(history.count(), 1); /// ``` pub fn replace(&mut self, value: T) { self.0[0] = value; } /// Removes all prior values. /// /// This effectively sets a new "checkpoint" that can be restored by calling `reset`. /// /// The returned bool indicates if any entries were removed. /// /// # Example /// ``` ///# use yewtil::History; /// let mut history = History::new(0); /// history.set(1); /// history.set(2); /// /// history.forget(); /// assert_eq!(*history, 2); /// assert_eq!(history.count(), 1); /// ``` pub fn forget(&mut self) -> bool { if self.dirty() { self.0.drain(1..); true } else { false } } /// Remove all elements except the last one, making the oldest entry the "current value". /// /// The returned bool indicates if any entries were removed. /// /// # Example /// ``` ///# use yewtil::History; /// let mut history = History::new(0); /// history.set(1); /// history.set(2); /// /// history.reset(); /// assert_eq!(*history, 0); /// assert_eq!(history.count(), 1); /// ``` pub fn reset(&mut self) -> bool { if self.dirty() { self.0.drain(..self.0.len() - 1); true } else { false } } /// Returns true if there is more than one entry in the history. /// /// # Example /// ``` ///# use yewtil::History; /// let mut history = History::new(0); /// history.set(1); /// assert!(history.dirty()); /// ``` pub fn dirty(&mut self) -> bool { self.count() > 1 } /// Returns the number of entries in the history. /// /// This will never be less than 1, as the first entry of the backing VecDeque is always occupied by the /// "current value" in the `History` struct. /// /// # Example /// ``` ///# use yewtil::History; /// let mut history = History::new(0); /// assert_eq!(history.count(), 1); /// /// history.set(1); /// assert_eq!(history.count(), 2); /// ``` pub fn count(&self) -> usize { self.0.len() } /// Produces an iterator over references to history items ordered from newest to oldest. pub fn iter(&self) -> std::collections::vec_deque::Iter<T> { self.0.iter() } /// Gets the current value. pub fn into_inner(mut self) -> T { self.0 .pop_front() .expect("History should have at least one item") } } impl<T: PartialEq> History<T> { /// Will only `set` the value if the provided value is different than the current value. /// /// It returns true to indicate if the history's current value was updated to be the provided value. /// # Example /// ``` ///# use yewtil::History; /// let mut history = History::new(0); /// let did_set = history.neq_set(0); /// assert!(!did_set); /// /// let did_set = history.neq_set(1); /// assert!(did_set); /// ``` pub fn neq_set(&mut self, value: T) -> bool { if self.0[0] != value { self.set(value); true } else { false } } } impl<T> IntoIterator for History<T> { type Item = T; type IntoIter = std::collections::vec_deque::IntoIter<T>; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } impl<T> AsRef<T> for History<T> { fn as_ref(&self) -> &T { // Get the first element &self.0[0] } } impl<T> Deref for History<T> { type Target = T; fn deref(&self) -> &Self::Target { self.as_ref() } }