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}