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()
    }
}