bo_cell 0.1.0

A RefCell which borrows its contents rather than owning them
Documentation
/*!
* A BoCell is simply a limited version of the standard RefCell which borrows its contents rather than
  owning them. This can be useful in cases where the internal mutability and referencing properties of
  a RefCell are necessary to appease the borrow-checker but only within the context of, for example, a
  single method or trait implementation.
*/

use core::fmt;
use core::fmt::{Debug, Display};

use core::ops::{Deref, DerefMut};

use core::cell::Cell;
use core::cell::UnsafeCell;

type BorrowFlag = usize;
const UNUSED: BorrowFlag = 0;

#[inline(always)]
fn is_writing(x: BorrowFlag) -> bool {
    x > UNUSED
}

/// An error returned by try_borrow.
pub struct BorrowError {
    _private: (),
}

impl Debug for BorrowError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BorrowError").finish()
    }
}

impl Display for BorrowError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        Display::fmt("already mutably borrowed", f)
    }
}

struct BorrowShard<'b> {
    borrow: &'b Cell<BorrowFlag>,
}

impl<'b> BorrowShard<'b> {
    #[inline]
    fn new(borrow: &'b Cell<BorrowFlag>) -> Option<Self> {
        match borrow.get() {
            UNUSED => {
                borrow.set(UNUSED + 1);
                Some(BorrowShard { borrow })
            }
            _ => None,
        }
    }

    #[inline]
    fn clone(&self) -> Self {
        let borrow = self.borrow.get();
        debug_assert!(is_writing(borrow));
        assert!(borrow != usize::max_value());
        self.borrow.set(borrow + 1);
        BorrowShard {
            borrow: self.borrow,
        }
    }
}

impl Drop for BorrowShard<'_> {
    #[inline]
    fn drop(&mut self) {
        let borrow = self.borrow.get();
        debug_assert!(is_writing(borrow));
        self.borrow.set(borrow + 1);
    }
}
pub struct RefMut<'b, T: ?Sized + 'b> {
    value: &'b mut T,
    borrow: BorrowShard<'b>,
}

impl<'b, T: ?Sized> RefMut<'b, T> {
    /// Makes a new `RefMut` for a single component of the borrowed data, e.g., an enum
    /// variant.
    ///
    /// This is an associated function that needs to be used as `RefMut::map(...)`.
    #[inline]
    pub fn map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
    where
        F: FnOnce(&mut T) -> &mut U,
    {
        let RefMut { value, borrow } = orig;
        RefMut {
            value: f(value),
            borrow,
        }
    }

    /// Splits a `RefMut` into a tuple of `RefMut`s for different components of the
    /// borrowed data.
    ///
    /// Care must be taken to ensure that the resulting `Shards` refer to non-overlapping components
    /// of the parent `RefMut`.
    ///
    /// The underlying `RefCell` will remain mutably borrowed until both
    /// returned `RefMut`s go out of scope.
    ///
    /// This is an associated function that needs to be used a `RefMut::split_tuple(...)`.
    #[inline]
    pub fn split_tuple<U: ?Sized, V: ?Sized, F>(
        orig: RefMut<'b, T>,
        f: F,
    ) -> (RefMut<'b, U>, RefMut<'b, V>)
    where
        F: FnOnce(&mut T) -> (&mut U, &mut V),
    {
        let (a, b) = f(orig.value);
        let borrow = orig.borrow.clone();
        (
            RefMut { value: a, borrow },
            RefMut {
                value: b,
                borrow: orig.borrow,
            },
        )
    }

    /// Splits a `RefMut` into a triple of `RefMut`s for different components of the
    /// borrowed data.
    ///
    /// Care must be taken to ensure that the resulting `Shards` refer to non-overlapping components
    /// of the parent `RefMut`.
    ///
    /// The underlying `RefCell` will remain mutably borrowed until all three
    /// returned `RefMut`s go out of scope.
    ///
    /// This is an associated function that needs to be used a `RefMut::split_tuple(...)`.
    #[inline]
    pub fn split_triple<U: ?Sized, V: ?Sized, W: ?Sized, F>(
        orig: RefMut<'b, T>,
        f: F,
    ) -> (RefMut<'b, U>, RefMut<'b, V>, RefMut<'b, W>)
    where
        F: FnOnce(&mut T) -> (&mut U, &mut V, &mut W),
    {
        let (a, b, c) = f(orig.value);
        let borrow_a = orig.borrow.clone();
        let borrow_b = orig.borrow.clone();
        (
            RefMut {
                value: a,
                borrow: borrow_a,
            },
            RefMut {
                value: b,
                borrow: borrow_b,
            },
            RefMut {
                value: c,
                borrow: orig.borrow,
            },
        )
    }
}

impl<T: ?Sized> Deref for RefMut<'_, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.value
    }
}

impl<T: ?Sized> DerefMut for RefMut<'_, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        self.value
    }
}

impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.value.fmt(f)
    }
}

/// A `RefCell` like structure which may be coerced from a `&mut`
pub struct BoCell<'a, T> {
    borrow: Cell<BorrowFlag>,
    value: &'a UnsafeCell<T>,
}

impl<'a, T> BoCell<'a, T> {
    #[inline]
    pub fn new(contents: &'a mut T) -> Self {
        let interior = unsafe { &*(contents as *mut T as *const UnsafeCell<T>) };
        BoCell {
            borrow: Cell::new(UNUSED),
            value: interior,
        }
    }

    /// Attempts to uniquely borrow the pointer mutably as a RefMut.
    ///
    /// Panics if another RefMut has already been taken. For a panic free version use
    /// [try_borrow_mut](#method.try_borrow_mut) instead.
    pub fn borrow_mut(&self) -> RefMut<'_, T> {
        self.try_borrow_mut().expect("Already borrowed")
    }

    /// Attempts to uniquely borrow the pointer mutably. Returns an error variant if the pointer is
    /// borrowed elsewhere.
    pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowError> {
        match BorrowShard::new(&self.borrow) {
            Some(b) => Ok(RefMut {
                value: unsafe { &mut *self.value.get() },
                borrow: b,
            }),
            None => Err(BorrowError { _private: () }),
        }
    }
}