mucell/
lib.rs

1//! A cell with the ability to mutate the value through an immutable reference when safe.
2//!
3//! # Comparison with `RefCell`
4//!
5//! `RefCell` goes for completely runtime checking, having `try_borrow`, `try_borrow_mut`,
6//! `borrow` and `borrow_mut` all taking `&self` and using custom reference types everywhere.
7//!
8//! `MuCell` (out of pity and the fact that “non-ascii idents are not fully supported” I did not
9//! name it `ΜCell` with the crate named `µcell`) makes much more use of true Rust borrow checking
10//! for a result that is more efficient and has no possibility of panicking.
11//!
12//! However, its purpose is not the same as `RefCell`; it is designed specifically for cases where
13//! something only *needs* an immutable reference, but where being able to safely take a mutable
14//! reference can improve efficiency. Say, for example, where it’s beneficial to be able to cache
15//! the result of a calculation, but you don’t really want to *need* to do that.
16//!
17//! The purpose of all of this is for an accessor for a `T` that can be made more efficient if it
18//! can have `&mut self`, but doesn’t strictly require it. For this reason, it’s often going to be
19//! paired with [`std::borrow::Cow`](http://doc.rust-lang.org/std/borrow/enum.Cow.html), e.g.
20//! `Cow<str>` or `Cow<[T]>`, producing `Borrowed` if you are able to mutate the value or `Owned`
21//! of the same data if not.
22//!
23//! # Examples
24//!
25//! This example covers most of the surface area of the library:
26//!
27//! ```rust
28//! # use mucell::MuCell;
29//! let mut cell = MuCell::new(vec![1, 2, 3]);
30//!
31//! // You can borrow from the cell mutably at no cost.
32//! cell.borrow_mut().push(4);
33//!
34//! // You can borrow immutably, too, and it’s very cheap.
35//! // (Rust’s standard borrow checking prevents you from doing
36//! // this while there’s a mutable reference taken out.)
37//! assert_eq!(&*cell.borrow(), &[1, 2, 3, 4]);
38//!
39//! // So long as there are no active borrows,
40//! // try_mutate can be used to mutate the value.
41//! assert!(cell.try_mutate(|x| x.push(5)));
42//! assert_eq!(&*cell.borrow(), &[1, 2, 3, 4, 5]);
43//!
44//! // But when there is an immutable borrow active,
45//! // try_mutate says no.
46//! let b = cell.borrow();
47//! assert!(!cell.try_mutate(|_| unreachable!()));
48//! drop(b);
49//!
50//! // We can have many immutable borrows at a time, too.
51//! {
52//!     let a = cell.borrow();
53//!     let b = cell.borrow();
54//!     let c = cell.borrow();
55//!     assert_eq!(&*a as *const Vec<i32>, &*b as *const Vec<i32>);
56//! }
57//!
58//! // Once they’re all cleared, try_mutate is happy again.
59//! assert!(cell.try_mutate(|x| x.push(6)));
60//! assert_eq!(&*cell.borrow(), &[1, 2, 3, 4, 5, 6]);
61//! ```
62//!
63//! Look at the examples in the repository for some slightly more practical (though still
64//! typically contrived) examples.
65
66#![cfg_attr(feature = "no_std", no_std)]
67#![cfg_attr(feature = "const_fn", feature(const_fn))]
68#![warn(bad_style, unused, missing_docs)]
69
70#[cfg(not(feature = "no_std"))]
71extern crate std as core;
72
73#[cfg(not(feature = "no_std"))]
74use std::borrow::Cow;
75use core::cell::{Cell, UnsafeCell};
76use core::cmp::Ordering;
77use core::fmt;
78use core::hash::{Hash, Hasher};
79use core::ops::{Deref, DerefMut};
80
81type BorrowFlag = usize;
82const UNUSED: BorrowFlag = 0;
83const WRITING: BorrowFlag = !0;
84
85/// A cell with the ability to mutate the value through an immutable reference when safe.
86pub struct MuCell<T: ?Sized> {
87    borrow: Cell<BorrowFlag>,
88    value: UnsafeCell<T>,
89}
90
91#[cfg(feature = "const_fn")]
92#[macro_use]
93mod _m {
94    macro_rules! const_fn {
95        ($(#[$m:meta])* pub const fn $name:ident($value:ident: $T:ty) -> $R:ty { $body:expr }) => {
96            $(#[$m])* pub const fn $name($value: $T) -> $R { $body }
97        }
98    }
99}
100
101#[cfg(not(feature = "const_fn"))]
102#[macro_use]
103mod _m {
104    macro_rules! const_fn {
105        ($(#[$m:meta])* pub const fn $name:ident($value:ident: $T:ty) -> $R:ty { $body:expr }) => {
106            $(#[$m])* pub fn $name($value: $T) -> $R { $body }
107        }
108    }
109}
110
111impl<T> MuCell<T> {
112    const_fn! {
113        #[doc = "
114            Creates a `MuCell` containing `value`.
115
116            # Examples
117
118            ```
119            use mucell::MuCell;
120
121            let c = MuCell::new(5);
122            ```"]
123        #[inline]
124        pub const fn new(value: T) -> MuCell<T> {
125            MuCell {
126                value: UnsafeCell::new(value),
127                borrow: Cell::new(UNUSED),
128            }
129        }
130    }
131
132    /// Consumes the `MuCell`, returning the wrapped value.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// use mucell::MuCell;
138    ///
139    /// let c = MuCell::new(5);
140    ///
141    /// let five = c.into_inner();
142    /// ```
143    #[inline]
144    pub fn into_inner(self) -> T {
145        // Since this function takes `self` (the `RefCell`) by value, the
146        // compiler statically verifies that it is not currently borrowed.
147        // Therefore the following assertion is just a `debug_assert!`.
148        debug_assert!(self.borrow.get() == UNUSED);
149        unsafe { self.value.into_inner() }
150    }
151}
152
153impl<T: ?Sized> MuCell<T> {
154    // Explicitly not implemented from RefCell is borrow_state.
155    //
156    // - Returning `Writing` would indicate you are in a `try_mutate` block, and so calling
157    //   `borrow()` would panic, but you should definitely know that already.
158    // - Returning `Reading` would indicate there are immutable borrows alive, and so calling
159    //   `try_mutate()` would return `false`, but there’s no real value in knowing that.
160    //
161    // In short, there just doesn’t seem much point in providing it.
162
163    /// Immutably borrows the wrapped value.
164    ///
165    /// The borrow lasts until the returned `Ref` exits scope.
166    /// Multiple immutable borrows can be taken out at the same time.
167    ///
168    /// # Panics
169    ///
170    /// Panics if called inside the `try_mutate()` mutator function.
171    /// But that’s generally a nonsensical thing to do, anyway, so just be sensible and you’re OK.
172    #[inline]
173    pub fn borrow(&self) -> Ref<&T> {
174        Ref {
175            _borrow: BorrowRef::new(&self.borrow),
176            _value: unsafe { &*self.value.get() },
177        }
178    }
179
180    /// Mutably borrows the wrapped value.
181    ///
182    /// Unlike `RefCell.borrow_mut`, this method lets Rust’s type system prevent aliasing
183    /// and so cannot have anything go wrong. It is also, in consequence, completely free,
184    /// unlike `RefCell` or `MuCell.borrow` which all have to keep track of borrows at runtime.
185    #[inline]
186    pub fn borrow_mut(&mut self) -> &mut T {
187        unsafe { &mut *self.value.get() }
188    }
189
190    /// Mutate the contained object if possible.
191    ///
192    /// If any immutable references produced by calling `borrow()` are active,
193    /// this will return false, not executing the function given.
194    ///
195    /// If there are no immutable references active,
196    /// this will execute the mutator function and return true.
197    ///
198    /// The mutator function should not touch `self` (not that it would really
199    /// make much sense to be touching it, anyway); most notably, you may not call `borrow` on
200    /// `self` inside the mutator, which includes things like the `==` implementation which borrow
201    /// the value briefly; while calling `try_mutate` inside it will just return false, calling
202    /// `borrow` will panic.
203    #[inline]
204    pub fn try_mutate<F: FnOnce(&mut T)>(&self, mutator: F) -> bool {
205        if self.borrow.get() == UNUSED {
206            self.borrow.set(WRITING);
207            mutator(unsafe { &mut *self.value.get() });
208            self.borrow.set(UNUSED);
209            true
210        } else {
211            false
212        }
213    }
214
215    // Not implemented at present from RefCell: as_unsafe_cell. I don’t see the point of it,
216    // but it can easily be added at a later date if desired.
217}
218
219struct BorrowRef<'b> {
220    _borrow: &'b Cell<BorrowFlag>,
221}
222
223impl<'b> BorrowRef<'b> {
224    #[inline]
225    fn new(borrow: &'b Cell<BorrowFlag>) -> BorrowRef<'b> {
226        match borrow.get() {
227            WRITING => panic!("borrow() called inside try_mutate"),
228            b => {
229                borrow.set(b + 1);
230                BorrowRef { _borrow: borrow }
231            },
232        }
233    }
234}
235
236impl<'b> Drop for BorrowRef<'b> {
237    #[inline]
238    fn drop(&mut self) {
239        let borrow = self._borrow.get();
240        debug_assert!(borrow != WRITING && borrow != UNUSED);
241        self._borrow.set(borrow - 1);
242    }
243}
244
245impl<'b> Clone for BorrowRef<'b> {
246    #[inline]
247    fn clone(&self) -> BorrowRef<'b> {
248        // Since this BorrowRef exists,
249        // we know the borrow flag is not set to WRITING.
250        let borrow = self._borrow.get();
251        debug_assert!(borrow != WRITING && borrow != UNUSED);
252        self._borrow.set(borrow + 1);
253        BorrowRef { _borrow: self._borrow }
254    }
255}
256
257/// An immutable reference to a `MuCell`.
258/// Normally you should dereference to get at the object,
259/// but after transformation with `Ref::map` or `Ref::filter_map`
260/// you might instead use `.into_inner()`.
261pub struct Ref<'b, T: 'b> {
262    // FIXME #12808: strange name to try to avoid interfering with
263    // field accesses of the contained type via Deref
264    _value: T,
265    _borrow: BorrowRef<'b>
266}
267
268impl<'b, T: Deref + 'b> Deref for Ref<'b, T> {
269    type Target = T::Target;
270
271    #[inline]
272    fn deref(&self) -> &T::Target {
273        &*self._value
274    }
275}
276
277impl<'b, T: DerefMut + 'b> DerefMut for Ref<'b, T> {
278    #[inline]
279    fn deref_mut(&mut self) -> &mut T::Target {
280        &mut *self._value
281    }
282}
283
284impl<'b, T: Clone> Ref<'b, T> {
285    /// Copies a `Ref`.
286    ///
287    /// The `MuCell` is already immutably borrowed, so this cannot fail.
288    ///
289    /// This is an associated function that needs to be used as
290    /// `Ref::clone(...)`.  A `Clone` implementation or a method would interfere
291    /// with the widespread use of `r.borrow().clone()` to clone the contents of
292    /// a `MuCell`.
293    #[inline]
294    pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
295        Ref {
296            _value: orig._value.clone(),
297            _borrow: orig._borrow.clone(),
298        }
299    }
300}
301
302impl<'b, T: 'static> Ref<'b, T> {
303    /// Consumes the `Ref`, returning the wrapped value.
304    ///
305    /// The `'static` constraint on `T` is what makes this possible; there is no longer any need to
306    /// keep the borrow alive, and so the `Ref` itself can be consumed while keeping the contained
307    /// value.
308    ///
309    /// # Examples
310    ///
311    /// ```
312    /// use mucell::{MuCell, Ref};
313    /// use std::borrow::Cow;
314    ///
315    /// let c = MuCell::new("foo");
316    ///
317    /// let r1: Ref<Cow<str>> = Ref::map(c.borrow(), |s| Cow::from(*s));
318    /// let r2: Ref<String> = Ref::map(r1, |s| s.into_owned());
319    /// let string: String = r2.into_inner();
320    /// ```
321    #[inline]
322    pub fn into_inner(self) -> T {
323        self._value
324    }
325}
326
327#[cfg(not(feature = "no_std"))]
328impl<'b, T: ?Sized> Ref<'b, Cow<'b, T>> where T: ToOwned, T::Owned: 'static {
329    /// Extracts the owned data.
330    ///
331    /// Copies the data if it is not already owned.
332    ///
333    /// This code is precisely equivalent to `Ref::map(self, |cow| cow.into_owned()).into_inner()`
334    /// and is purely a convenience method because `Ref<Cow<T>>` is a common case.
335    ///
336    /// # Examples
337    ///
338    /// ```
339    /// use mucell::{MuCell, Ref};
340    /// use std::borrow::Cow;
341    ///
342    /// let c = MuCell::new("foo");
343    ///
344    /// let r: Ref<Cow<str>> = Ref::map(c.borrow(), |s| Cow::from(*s));
345    /// let string: String = r.into_owned();
346    /// ```
347    #[inline]
348    pub fn into_owned(self) -> T::Owned {
349        Ref::map(self, |cow| cow.into_owned()).into_inner()
350    }
351}
352
353impl<'b, T> Ref<'b, T> {
354    /// Make a new `Ref` for a component of the borrowed data.
355    ///
356    /// The `MuCell` is already immutably borrowed, so this cannot fail.
357    ///
358    /// This is an associated function that needs to be used as `Ref::map(...)`.
359    /// A method would interfere with methods of the same name on the contents
360    /// of a `MuCell` used through `Deref`.
361    ///
362    /// # Memory unsafety
363    ///
364    /// This function is marked as unsafe because it is possible (though not the easiest
365    /// thing) to subvert memory safety by storing a reference to the wrapped value.
366    /// This is a deficiency which cannot be solved without Rust supporting HKT.
367    /// It’d need something like `where F: (for<'f> FnOnce(T) -> U where T: 'f, U: 'f)`.
368    ///
369    /// The only class of transformation functions that can structurally be known to be safe in
370    /// current Rust is those with no non-static environment; the `map` function embodies that
371    /// constraint and should be used where possible instead of this function.
372    ///
373    /// # Example
374    ///
375    /// ```
376    /// use mucell::{MuCell, Ref};
377    ///
378    /// let c = MuCell::new((5, 'b'));
379    /// let b1: Ref<&(u32, char)> = c.borrow();
380    /// let b2: Ref<&u32> = Ref::map(b1, |t| &t.0);
381    /// assert_eq!(*b2, 5)
382    /// ```
383    #[inline]
384    pub unsafe fn map_unsafe<U, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
385        where F: FnOnce(T) -> U
386    {
387        Ref {
388            _value: f(orig._value),
389            _borrow: orig._borrow,
390        }
391    }
392
393    /// This is a safe version of `map_unsafe`,
394    /// imposing the constraint that `F` is `'static`.
395    ///
396    /// This is the only way to make it safe in a pre-HKT world:
397    /// by preventing the closure from capturing any non-static environment.
398    /// Anything beyond that will require caution to ensure safety.
399    #[inline]
400    pub fn map<U, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
401        where F: FnOnce(T) -> U + 'static
402    {
403        unsafe { Ref::map_unsafe(orig, f) }
404    }
405
406    /// Make a new `Ref` for a optional component of the borrowed data, e.g. an
407    /// enum variant.
408    ///
409    /// The `MuCell` is already immutably borrowed, so this cannot fail.
410    ///
411    /// This is an associated function that needs to be used as
412    /// `Ref::filter_map(...)`.  A method would interfere with methods of the
413    /// same name on the contents of a `MuCell` used through `Deref`.
414    ///
415    /// # Memory unsafety
416    ///
417    /// This function is marked as unsafe because it is possible (though not the easiest
418    /// thing) to subvert memory safety by storing a reference to the wrapped value.
419    /// This is a deficiency which cannot be solved without Rust supporting HKT.
420    /// It’d need something like `where F: (for<'f> FnOnce(T) -> Option<U> where T: 'f, U: 'f)`.
421    ///
422    /// The only class of transformation functions that can structurally be known to be safe in
423    /// current Rust is those with no non-static environment; the `map` function embodies that
424    /// constraint and should be used where possible instead of this function.
425    ///
426    /// # Example
427    ///
428    /// ```
429    /// use mucell::{MuCell, Ref};
430    ///
431    /// let c = MuCell::new(Ok(5));
432    /// let b1: Ref<&Result<u32, ()>> = c.borrow();
433    /// let b2: Ref<&u32> = Ref::filter_map(b1, |o| o.as_ref().ok()).unwrap();
434    /// assert_eq!(*b2, 5)
435    /// ```
436    #[inline]
437    pub unsafe fn filter_map_unsafe<U, F>(orig: Ref<'b, T>, f: F) -> Option<Ref<'b, U>>
438        where F: FnOnce(T) -> Option<U>
439    {
440        let borrow = orig._borrow;
441        f(orig._value).map(move |new| Ref {
442            _value: new,
443            _borrow: borrow,
444        })
445    }
446
447    /// This is a safe version of `filter_map_unsafe`,
448    /// imposing the constraint that `F` is `'static`.
449    ///
450    /// This is the only way to make it safe in a pre-HKT world:
451    /// by preventing the closure from capturing any non-static environment.
452    /// Anything beyond that will require caution to ensure safety.
453    #[inline]
454    pub fn filter_map<U, F>(orig: Ref<'b, T>, f: F) -> Option<Ref<'b, U>>
455        where F: FnOnce(T) -> Option<U> + 'static
456    {
457        unsafe { Ref::filter_map_unsafe(orig, f) }
458    }
459}
460
461unsafe impl<T: ?Sized> Send for MuCell<T> where T: Send {}
462
463impl<T: ?Sized + PartialEq> PartialEq for MuCell<T> {
464    fn eq(&self, other: &MuCell<T>) -> bool {
465        *self.borrow() == *other.borrow()
466    }
467}
468
469impl<T: ?Sized + Eq> Eq for MuCell<T> { }
470
471impl<T: PartialOrd> PartialOrd for MuCell<T> {
472    fn partial_cmp(&self, other: &MuCell<T>) -> Option<Ordering> {
473        self.borrow().partial_cmp(&*other.borrow())
474    }
475}
476
477impl<T: Ord> Ord for MuCell<T> {
478    fn cmp(&self, other: &MuCell<T>) -> Ordering {
479        self.borrow().cmp(&*other.borrow())
480    }
481}
482
483impl<T: Default> Default for MuCell<T> {
484    fn default() -> MuCell<T> {
485        MuCell::new(Default::default())
486    }
487}
488
489impl<T: Clone> Clone for MuCell<T> {
490    fn clone(&self) -> MuCell<T> {
491        MuCell::new(self.borrow().clone())
492    }
493}
494
495macro_rules! impl_fmt {
496    ($($trait_name:ident)*) => {$(
497        impl<T: fmt::$trait_name> fmt::$trait_name for MuCell<T> {
498            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
499                self.borrow().fmt(f)
500            }
501        }
502    )*}
503}
504impl_fmt!(Display Debug Octal LowerHex UpperHex Pointer Binary LowerExp UpperExp);
505
506impl<T> Hash for MuCell<T> where T: Hash {
507    fn hash<H: Hasher>(&self, state: &mut H) {
508        self.borrow().hash(state)
509    }
510}
511
512// RefCell doesn’t have PartialOrd, Ord, Hash or fmt::*. TODO: why not?
513
514#[test]
515#[should_panic]
516fn test_borrow_in_try_mutate() {
517    let a = MuCell::new(());
518    a.try_mutate(|_| { let _ = a.borrow(); });
519}
520
521#[test]
522fn test_try_mutate_in_try_mutate() {
523    let a = MuCell::new(());
524    assert!(a.try_mutate(|_| assert!(!a.try_mutate(|_| unreachable!()))));
525}
526
527/// A demonstration of the subversion of memory safety using `map_unsafe`.
528#[test]
529fn unsafe_subversion_demo() {
530    let cell = MuCell::new(0);
531    let (borrow, mut x) = (cell.borrow(), Option::None);
532    unsafe {
533        Ref::map_unsafe(borrow, |a| x = Option::Some(a));
534    }
535    assert_eq!(x, Option::Some(&0));
536    assert!(cell.try_mutate(|n| *n += 1));
537    assert_eq!(x, Option::Some(&1));
538}