mutate_once/
lib.rs

1//
2// Copyright (c) 2019 KAMADA Ken'ichi.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions
7// are met:
8// 1. Redistributions of source code must retain the above copyright
9//    notice, this list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright
11//    notice, this list of conditions and the following disclaimer in the
12//    documentation and/or other materials provided with the distribution.
13//
14// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24// SUCH DAMAGE.
25//
26
27//! This library provides interior mutability that can be borrowed
28//! as plain immutable references `&T` in exchange for the write-once,
29//! read-many restriction.
30//!
31//! Unlike `std::cell::Cell` or `std::cell::RefCell`, a plain
32//! immutable reference `&T` can be taken from `MutOnce<T>`.
33//! Once an immutable reference is taken, the value can never be mutated
34//! (even after all references are dropped).
35//!
36//! The use cases include caching getter and delayed evaluation.
37
38use std::cell::{Cell, UnsafeCell};
39use std::ops::{Deref, DerefMut, Drop};
40
41#[derive(Debug, Copy, Clone, PartialEq, Eq)]
42enum State {
43    Unborrowed,
44    Updating,
45    Fixed,
46}
47
48/// A mutable memory location that is write-once and can be borrowed as
49/// plain `&T`.
50///
51/// Initially the value can be mutated through struct `RefMut<T>`
52/// obtained by `get_mut` method.
53/// When there is no `RefMut` alive, a shared reference `&T` can be
54/// taken by `get_ref` method.  Once `get_ref` is called, `get_mut` must
55/// not be called again.
56///
57/// # Examples
58///
59/// ```
60/// use mutate_once::MutOnce;
61/// struct Container {
62///     expensive: MutOnce<String>,
63/// }
64/// impl Container {
65///     fn expensive(&self) -> &str {
66///         if !self.expensive.is_fixed() {
67///             let mut ref_mut = self.expensive.get_mut();
68///             *ref_mut += "expensive";
69///             // Drop `ref_mut` before calling `get_ref`.
70///         }
71///         // A plain reference can be returned to the caller
72///         // unlike `Cell` or `RefCell`.
73///         self.expensive.get_ref()
74///     }
75/// }
76/// let container = Container { expensive: MutOnce::new(String::new()) };
77/// assert_eq!(container.expensive(), "expensive");
78/// ```
79#[derive(Debug)]
80pub struct MutOnce<T> {
81    value: UnsafeCell<T>,
82    state: Cell<State>,
83}
84
85impl<T> MutOnce<T> {
86    /// Creates a new `MutOnce` containing the given `value`.
87    #[inline]
88    pub const fn new(value: T) -> Self {
89        Self {
90            value: UnsafeCell::new(value),
91            state: Cell::new(State::Unborrowed),
92        }
93    }
94
95    /// Mutably borrows the wrapped value.
96    ///
97    /// The borrow lasts until the returned `RefMut` gets dropped.
98    /// This method must not be called if another `RefMut` is active or
99    /// `get_ref` is ever called.
100    ///
101    /// # Panics
102    ///
103    /// Panics if the value is currently mutably borrowed or
104    /// ever immutably borrowed.
105    ///
106    /// # Examples
107    ///
108    /// ```
109    /// let mo = mutate_once::MutOnce::new(0);
110    /// *mo.get_mut() += 2;
111    /// *mo.get_mut() += 5;
112    /// assert_eq!(*mo.get_ref(), 7);
113    /// ```
114    ///
115    /// Panics if another mutable borrow is active:
116    ///
117    /// ```should_panic
118    /// let mo = mutate_once::MutOnce::new(0);
119    /// let mut ref_mut = mo.get_mut();
120    /// *mo.get_mut() += 7;     // Panics because `ref_mut` is still active.
121    /// ```
122    ///
123    /// Panics if `get_ref` is ever called:
124    ///
125    /// ```should_panic
126    /// let mo = mutate_once::MutOnce::new(0);
127    /// assert_eq!(*mo.get_ref(), 0);
128    /// *mo.get_mut() += 7;     // Panics because `get_ref` is called once.
129    /// ```
130    #[inline]
131    pub fn get_mut(&self) -> RefMut<T> {
132        match self.state.get() {
133            State::Unborrowed => {
134                self.state.replace(State::Updating);
135                RefMut { target: self }
136            },
137            State::Updating => panic!("already mutably borrowed"),
138            State::Fixed => panic!("no longer mutable"),
139        }
140    }
141
142    /// Returns an immutable reference to the value.
143    ///
144    /// This method must not be called while the value is mutably borrowed.
145    ///
146    /// # Panics
147    ///
148    /// Panics if the value is currently mutably borrowed.
149    ///
150    /// # Examples
151    ///
152    /// ```
153    /// let mo = mutate_once::MutOnce::new(0);
154    /// *mo.get_mut() += 7;
155    /// assert_eq!(*mo.get_ref(), 7);
156    /// ```
157    ///
158    /// Panics if a mutable borrow is active:
159    ///
160    /// ```should_panic
161    /// let mo = mutate_once::MutOnce::new(0);
162    /// let mut ref_mut = mo.get_mut();
163    /// mo.get_ref();           // Panics because `ref_mut` is still active.
164    /// ```
165    #[inline]
166    pub fn get_ref(&self) -> &T {
167        match self.state.get() {
168            State::Unborrowed => { self.state.replace(State::Fixed); },
169            State::Updating => panic!("still mutably borrowed"),
170            State::Fixed => {},
171        }
172        unsafe { &*self.value.get() }
173    }
174
175    /// Returns true if the value can be no longer mutated (in other words,
176    /// if `get_ref` is ever called).
177    #[inline]
178    pub fn is_fixed(&self) -> bool {
179        self.state.get() == State::Fixed
180    }
181
182    /// Consumes the `MutOnce`, returning the wrapped value.
183    #[inline]
184    pub fn into_inner(self) -> T {
185        self.value.into_inner()
186    }
187}
188
189impl<T: Default> Default for MutOnce<T> {
190    #[inline]
191    fn default() -> MutOnce<T> {
192        MutOnce::new(T::default())
193    }
194}
195
196impl<T> From<T> for MutOnce<T> {
197    #[inline]
198    fn from(t: T) -> MutOnce<T> {
199        MutOnce::new(t)
200    }
201}
202
203/// A wrapper type for a mutably borrowed value from a `MutOnce<T>`.
204#[derive(Debug)]
205pub struct RefMut<'a, T> {
206    target: &'a MutOnce<T>,
207}
208
209impl<'a, T> Deref for RefMut<'a, T> {
210    type Target = T;
211
212    #[inline]
213    fn deref(&self) -> &Self::Target {
214        unsafe { &*self.target.value.get() }
215    }
216}
217
218impl<'a, T> DerefMut for RefMut<'a, T> {
219    #[inline]
220    fn deref_mut(&mut self) -> &mut Self::Target {
221        unsafe { &mut *self.target.value.get() }
222    }
223}
224
225impl<'a, T> Drop for RefMut<'a, T> {
226    #[inline]
227    fn drop(&mut self) {
228        debug_assert_eq!(self.target.state.get(), State::Updating);
229        self.target.state.replace(State::Unborrowed);
230    }
231}
232
233#[cfg(test)]
234mod tests {
235    use super::*;
236
237    #[test]
238    fn repeated_muts() {
239        let mo = MutOnce::new(Vec::new());
240        {
241            let mut mutvec = mo.get_mut();
242            mutvec.push(1);
243            mutvec.push(2);
244        }
245        {
246            let mut mutvec = mo.get_mut();
247            mutvec.push(3);
248        }
249        let vec = mo.get_ref();
250        assert_eq!(vec[0], 1);
251        assert_eq!(vec[1], 2);
252        assert_eq!(vec[2], 3);
253    }
254
255    #[test]
256    fn multiple_refs() {
257        let mo = MutOnce::new(Vec::new());
258        {
259            let mut mutvec = mo.get_mut();
260            mutvec.push(1);
261            mutvec.push(2);
262            mutvec.push(3);
263        }
264        let vec1 = mo.get_ref();
265        let vec2 = mo.get_ref();
266        assert_eq!(vec1[0], 1);
267        assert_eq!(vec2[1], 2);
268        assert_eq!(vec1[2], 3);
269    }
270
271    #[test]
272    fn temporary_value() {
273        let mo = MutOnce::new(Vec::new());
274        mo.get_mut().push(1);
275        mo.get_mut().push(2);
276        assert_eq!(mo.get_ref()[0], 1);
277        assert_eq!(mo.get_ref()[1], 2);
278    }
279
280    #[test]
281    #[should_panic(expected = "still mutably borrowed")]
282    fn ref_while_mut() {
283        let mo = MutOnce::new(Vec::new());
284        let mut mutvec = mo.get_mut();
285        mutvec.push(1);
286        assert_eq!(mo.get_ref()[0], 1);
287    }
288
289    #[test]
290    #[should_panic(expected = "no longer mutable")]
291    fn mut_after_ref() {
292        let mo = MutOnce::new(Vec::new());
293        assert_eq!(mo.get_ref().len(), 0);
294        mo.get_mut().push(1);
295    }
296
297    #[test]
298    #[should_panic(expected = "already mutably borrowed")]
299    fn multiple_muts() {
300        let mo = MutOnce::new(Vec::new());
301        let mut mutvec1 = mo.get_mut();
302        let mut mutvec2 = mo.get_mut();
303        mutvec1.push(1);
304        mutvec2.push(2);
305    }
306
307    #[test]
308    fn into_inner() {
309        let mo = MutOnce::new(Vec::new());
310        mo.get_mut().push(1);
311        mo.get_mut().push(7);
312        assert_eq!(mo.into_inner(), vec![1, 7])
313    }
314
315    #[test]
316    fn default() {
317        let mo = MutOnce::<u32>::default();
318        *mo.get_mut() += 9;
319        assert_eq!(*mo.get_ref(), 9);
320    }
321
322    #[test]
323    fn from() {
324        let mo: MutOnce<_> = From::from(0);
325        *mo.get_mut() += 9;
326        assert_eq!(*mo.get_ref(), 9);
327        let mo: MutOnce<_> = 0.into();
328        *mo.get_mut() += 9;
329        assert_eq!(*mo.get_ref(), 9);
330    }
331}