#![cfg_attr(feature = "no_std", no_std)]
#![cfg_attr(feature = "no_std", feature(no_std, core, collections))]
#![cfg_attr(feature = "const_fn", feature(const_fn))]
#![warn(bad_style, unused, missing_docs)]
#[cfg(feature = "no_std")]
#[macro_use]
extern crate core;
#[cfg(all(feature = "no_std", not(test)))]
extern crate core as std;
#[cfg(feature = "no_std")]
extern crate collections;
#[cfg(all(feature = "no_std", test))]
extern crate std;
#[cfg(feature = "no_std")]
use std::marker::{Send, Sized};
#[cfg(not(feature = "no_std"))]
use std::borrow::Cow;
use std::cell::{Cell, UnsafeCell};
use std::clone::Clone;
use std::cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use std::default::Default;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, Drop, FnOnce};
use std::option::Option;
use std::result::Result;
type BorrowFlag = usize;
const UNUSED: BorrowFlag = 0;
const WRITING: BorrowFlag = !0;
pub struct MuCell<T: ?Sized> {
borrow: Cell<BorrowFlag>,
value: UnsafeCell<T>,
}
#[cfg(feature = "const_fn")]
#[macro_use]
mod _m {
macro_rules! const_fn {
($(#[$m:meta])* pub const fn $name:ident($value:ident: $T:ty) -> $R:ty { $body:expr }) => {
$(#[$m])* pub const fn $name($value: $T) -> $R { $body }
}
}
}
#[cfg(not(feature = "const_fn"))]
#[macro_use]
mod _m {
macro_rules! const_fn {
($(#[$m:meta])* pub const fn $name:ident($value:ident: $T:ty) -> $R:ty { $body:expr }) => {
$(#[$m])* pub fn $name($value: $T) -> $R { $body }
}
}
}
impl<T> MuCell<T> {
const_fn! {
#[doc = "
Creates a `MuCell` containing `value`.
# Examples
```
use mucell::MuCell;
let c = MuCell::new(5);
```"]
#[inline]
pub const fn new(value: T) -> MuCell<T> {
MuCell {
value: UnsafeCell::new(value),
borrow: Cell::new(UNUSED),
}
}
}
#[inline]
pub fn into_inner(self) -> T {
debug_assert!(self.borrow.get() == UNUSED);
unsafe { self.value.into_inner() }
}
}
impl<T: ?Sized> MuCell<T> {
#[inline]
pub fn borrow(&self) -> Ref<&T> {
Ref {
_borrow: BorrowRef::new(&self.borrow),
_value: unsafe { &*self.value.get() },
}
}
#[inline]
pub fn borrow_mut(&mut self) -> &mut T {
unsafe { &mut *self.value.get() }
}
#[inline]
pub fn try_mutate<F: FnOnce(&mut T)>(&self, mutator: F) -> bool {
if self.borrow.get() == UNUSED {
self.borrow.set(WRITING);
mutator(unsafe { &mut *self.value.get() });
self.borrow.set(UNUSED);
true
} else {
false
}
}
}
struct BorrowRef<'b> {
_borrow: &'b Cell<BorrowFlag>,
}
impl<'b> BorrowRef<'b> {
#[inline]
fn new(borrow: &'b Cell<BorrowFlag>) -> BorrowRef<'b> {
match borrow.get() {
WRITING => panic!("borrow() called inside try_mutate"),
b => {
borrow.set(b + 1);
BorrowRef { _borrow: borrow }
},
}
}
}
impl<'b> Drop for BorrowRef<'b> {
#[inline]
fn drop(&mut self) {
let borrow = self._borrow.get();
debug_assert!(borrow != WRITING && borrow != UNUSED);
self._borrow.set(borrow - 1);
}
}
impl<'b> Clone for BorrowRef<'b> {
#[inline]
fn clone(&self) -> BorrowRef<'b> {
let borrow = self._borrow.get();
debug_assert!(borrow != WRITING && borrow != UNUSED);
self._borrow.set(borrow + 1);
BorrowRef { _borrow: self._borrow }
}
}
pub struct Ref<'b, T: 'b> {
_value: T,
_borrow: BorrowRef<'b>
}
impl<'b, T: Deref + 'b> Deref for Ref<'b, T> {
type Target = T::Target;
#[inline]
fn deref(&self) -> &T::Target {
&*self._value
}
}
impl<'b, T: Clone> Ref<'b, T> {
#[inline]
pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
Ref {
_value: orig._value.clone(),
_borrow: orig._borrow.clone(),
}
}
}
impl<'b, T: 'static> Ref<'b, T> {
#[inline]
pub fn into_inner(self) -> T {
self._value
}
}
#[cfg(not(feature = "no_std"))]
impl<'b, T: ?Sized> Ref<'b, Cow<'b, T>> where T: ToOwned, T::Owned: 'static {
#[inline]
pub fn into_owned(self) -> T::Owned {
Ref::map(self, |cow| cow.into_owned()).into_inner()
}
}
impl<'b, T> Ref<'b, T> {
#[inline]
pub fn map<U, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
where F: FnOnce(T) -> U
{
Ref {
_value: f(orig._value),
_borrow: orig._borrow,
}
}
#[inline]
pub fn filter_map<U, F>(orig: Ref<'b, T>, f: F) -> Option<Ref<'b, U>>
where F: FnOnce(T) -> Option<U>
{
let borrow = orig._borrow;
f(orig._value).map(move |new| Ref {
_value: new,
_borrow: borrow,
})
}
}
unsafe impl<T: ?Sized> Send for MuCell<T> where T: Send {}
impl<T: ?Sized + PartialEq> PartialEq for MuCell<T> {
fn eq(&self, other: &MuCell<T>) -> bool {
*self.borrow() == *other.borrow()
}
}
impl<T: ?Sized + Eq> Eq for MuCell<T> { }
impl<T: PartialOrd> PartialOrd for MuCell<T> {
fn partial_cmp(&self, other: &MuCell<T>) -> Option<Ordering> {
self.borrow().partial_cmp(&*other.borrow())
}
}
impl<T: Ord> Ord for MuCell<T> {
fn cmp(&self, other: &MuCell<T>) -> Ordering {
self.borrow().cmp(&*other.borrow())
}
}
impl<T: Default> Default for MuCell<T> {
fn default() -> MuCell<T> {
MuCell::new(Default::default())
}
}
impl<T: Clone> Clone for MuCell<T> {
fn clone(&self) -> MuCell<T> {
MuCell::new(self.borrow().clone())
}
}
macro_rules! impl_fmt {
($($trait_name:ident)*) => {$(
impl<T: fmt::$trait_name> fmt::$trait_name for MuCell<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.borrow().fmt(f)
}
}
)*}
}
impl_fmt!(Display Debug Octal LowerHex UpperHex Pointer Binary LowerExp UpperExp);
impl<T> Hash for MuCell<T> where T: Hash {
fn hash<H: Hasher>(&self, state: &mut H) {
self.borrow().hash(state)
}
}
#[test]
#[should_panic]
fn test_borrow_in_try_mutate() {
let a = MuCell::new(());
a.try_mutate(|_| { let _ = a.borrow(); });
}
#[test]
fn test_try_mutate_in_try_mutate() {
let a = MuCell::new(());
assert!(a.try_mutate(|_| assert!(!a.try_mutate(|_| unreachable!()))));
}