1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*!
* 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: () }),
        }
    }
}