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}