unchecked_refcell/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3
4use core::fmt;
5use core::{
6 cell::{Cell, UnsafeCell},
7 cmp::Ordering,
8 fmt::{Debug, Display, Formatter},
9 marker::PhantomData,
10 mem,
11 ops::{Deref, DerefMut},
12 ptr::NonNull,
13};
14
15/// A mutable memory location with dynamically checked borrow rules.
16///
17/// `UncheckedRefCell` behaves exactly like `std::cell::RefCell` when `debug_assertions` is enabled (debug builds).
18/// For release-like builds, `UncheckedRefCell` does not
19/// perform any borrow checking. Thus it is faster than `RefCell` (see benchmarks), but may lead to
20/// undefined behavior instead of panicking like `RefCell`. Only use this over `RefCell` for performance
21/// critical code where it is known a `RefCell` would never panic.
22///
23/// Enabling the `checked` feature flag (disabled by default) forces borrow checking in release
24/// builds too. This is only intended for use with debugging.
25pub struct UncheckedRefCell<T: ?Sized> {
26 #[cfg(any(feature = "checked", debug_assertions))]
27 borrow: Cell<BorrowCounter>,
28 // Stores the location of the earliest currently active borrow.
29 // This gets updated whenever we go from having zero borrows
30 // to having a single borrow. When a borrow occurs, this gets included
31 // in the generated `BorrowError`/`BorrowMutError`
32 #[cfg(feature = "debug_refcell")]
33 borrowed_at: Cell<Option<&'static core::panic::Location<'static>>>,
34 // to make not sync since `impl<T: ?Sized> !Sync for RefCell<T> {}` is not possible on stable outside of core
35 marker: PhantomData<*mut T>,
36 value: UnsafeCell<T>,
37}
38
39/// An error returned by [`RefCell::try_borrow`].
40#[non_exhaustive]
41#[derive(Debug)]
42pub struct BorrowError {
43 #[cfg(feature = "debug_refcell")]
44 location: &'static core::panic::Location<'static>,
45}
46
47impl Display for BorrowError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 #[cfg(feature = "debug_refcell")]
50 let res = write!(
51 f,
52 "RefCell already mutably borrowed; a previous borrow was at {}",
53 self.location
54 );
55
56 #[cfg(not(feature = "debug_refcell"))]
57 let res = Display::fmt("RefCell already mutably borrowed", f);
58
59 res
60 }
61}
62
63/// An error returned by [`RefCell::try_borrow_mut`].
64#[non_exhaustive]
65#[derive(Debug)]
66pub struct BorrowMutError {
67 #[cfg(feature = "debug_refcell")]
68 location: &'static core::panic::Location<'static>,
69}
70
71impl Display for BorrowMutError {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 #[cfg(feature = "debug_refcell")]
74 let res = write!(
75 f,
76 "RefCell already borrowed; a previous borrow was at {}",
77 self.location
78 );
79
80 #[cfg(not(feature = "debug_refcell"))]
81 let res = Display::fmt("RefCell already borrowed", f);
82
83 res
84 }
85}
86
87// This ensures the panicking code is outlined from `borrow_mut` for `RefCell`.
88#[track_caller]
89#[cold]
90fn panic_already_borrowed(err: BorrowError) -> ! {
91 panic!("RefCell already borrowed: {err}")
92}
93
94// This ensures the panicking code is outlined from `borrow` for `RefCell`.
95#[track_caller]
96#[cold]
97fn panic_already_mutably_borrowed(err: BorrowMutError) -> ! {
98 panic!("RefCell already mutably borrowed: {err}")
99}
100
101// Positive values represent the number of `UncheckedRef` active. Negative values
102// represent the number of `UncheckedRefMut` active. Multiple `UncheckedRefMut`s can only be
103// active at a time if they refer to distinct, nonoverlapping components of a
104// `RefCell` (e.g., different ranges of a slice).
105//
106// `UncheckedRef` and `UncheckedRefMut` are both two words in size, and so there will likely never
107// be enough `UncheckedRef`s or `UncheckedRefMut`s in existence to overflow half of the `usize`
108// range. Thus, a `BorrowCounter` will probably never overflow or underflow.
109// However, this is not a guarantee, as a pathological program could repeatedly
110// create and then mem::forget `UncheckedRef`s or `UncheckedRefMut`s. Thus, all code must
111// explicitly check for overflow and underflow in order to avoid unsafety, or at
112// least behave correctly in the event that overflow or underflow happens (e.g.,
113// see BorrowRef::new).
114type BorrowCounter = isize;
115const UNUSED: BorrowCounter = 0;
116
117#[inline(always)]
118const fn is_writing(x: BorrowCounter) -> bool {
119 x < UNUSED
120}
121
122#[inline(always)]
123const fn is_reading(x: BorrowCounter) -> bool {
124 x > UNUSED
125}
126
127impl<T> UncheckedRefCell<T> {
128 /// Creates a new `RefCell` containing `value`.
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// use unchecked_refcell::UncheckedRefCell;
134 ///
135 /// let c = UncheckedRefCell::new(5);
136 /// ```
137 #[inline]
138 pub const fn new(value: T) -> UncheckedRefCell<T> {
139 UncheckedRefCell {
140 value: UnsafeCell::new(value),
141 #[cfg(any(feature = "checked", debug_assertions))]
142 borrow: Cell::new(UNUSED),
143 marker: PhantomData,
144 #[cfg(feature = "debug_refcell")]
145 borrowed_at: Cell::new(None),
146 }
147 }
148
149 /// Consumes the `RefCell`, returning the wrapped value.
150 ///
151 /// # Examples
152 ///
153 /// ```
154 /// use unchecked_refcell::UncheckedRefCell;
155 ///
156 /// let c = UncheckedRefCell::new(5);
157 ///
158 /// let five = c.into_inner();
159 /// ```
160 #[inline]
161 pub fn into_inner(self) -> T {
162 // Since this function takes `self` (the `RefCell`) by value, the
163 // compiler statically verifies that it is not currently borrowed.
164 self.value.into_inner()
165 }
166
167 /// Replaces the wrapped value with a new one, returning the old value,
168 /// without deinitializing either one.
169 ///
170 /// This function corresponds to [`std::mem::replace`](../mem/fn.replace.html).
171 ///
172 /// # Panics
173 ///
174 /// Panics if the value is currently borrowed.
175 ///
176 /// # Examples
177 ///
178 /// ```
179 /// use unchecked_refcell::UncheckedRefCell;
180 /// let cell = UncheckedRefCell::new(5);
181 /// let old_value = cell.replace(6);
182 /// assert_eq!(old_value, 5);
183 /// assert_eq!(cell, UncheckedRefCell::new(6));
184 /// ```
185 #[track_caller]
186 pub fn replace(&self, t: T) -> T {
187 mem::replace(&mut self.borrow_mut(), t)
188 }
189
190 /// Replaces the wrapped value with a new one computed from `f`, returning
191 /// the old value, without deinitializing either one.
192 ///
193 /// # Panics
194 ///
195 /// Panics if the value is currently borrowed.
196 ///
197 /// # Examples
198 ///
199 /// ```
200 /// use unchecked_refcell::UncheckedRefCell;
201 /// let cell = UncheckedRefCell::new(5);
202 /// let old_value = cell.replace_with(|&mut old| old + 1);
203 /// assert_eq!(old_value, 5);
204 /// assert_eq!(cell, UncheckedRefCell::new(6));
205 /// ```
206 #[inline]
207 #[track_caller]
208 pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
209 let mut_borrow = &mut *self.borrow_mut();
210 let replacement = f(mut_borrow);
211 mem::replace(mut_borrow, replacement)
212 }
213
214 /// Swaps the wrapped value of `self` with the wrapped value of `other`,
215 /// without deinitializing either one.
216 ///
217 /// This function corresponds to [`std::mem::swap`](../mem/fn.swap.html).
218 ///
219 /// # Panics
220 ///
221 /// Panics if the value in either `RefCell` is currently borrowed, or
222 /// if `self` and `other` point to the same `RefCell`.
223 ///
224 /// # Examples
225 ///
226 /// ```
227 /// use unchecked_refcell::UncheckedRefCell;
228 /// let c = UncheckedRefCell::new(5);
229 /// let d = UncheckedRefCell::new(6);
230 /// c.swap(&d);
231 /// assert_eq!(c, UncheckedRefCell::new(6));
232 /// assert_eq!(d, UncheckedRefCell::new(5));
233 /// ```
234 #[inline]
235 pub fn swap(&self, other: &Self) {
236 mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
237 }
238}
239
240impl<T: ?Sized> UncheckedRefCell<T> {
241 /// Immutably borrows the wrapped value.
242 ///
243 /// The borrow lasts until the returned `UncheckedRef` exits scope. Multiple
244 /// immutable borrows can be taken out at the same time.
245 ///
246 /// # Panics
247 ///
248 /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
249 /// [`try_borrow`](#method.try_borrow).
250 ///
251 /// # Examples
252 ///
253 /// ```
254 /// use unchecked_refcell::UncheckedRefCell;
255 ///
256 /// let c = UncheckedRefCell::new(5);
257 ///
258 /// let borrowed_five = c.borrow();
259 /// let borrowed_five2 = c.borrow();
260 /// ```
261 ///
262 /// An example of panic:
263 ///
264 /// ```should_panic
265 /// use unchecked_refcell::UncheckedRefCell;
266 ///
267 /// let c = UncheckedRefCell::new(5);
268 ///
269 /// let m = c.borrow_mut();
270 /// let b = c.borrow(); // this causes a panic
271 /// ```
272 #[inline]
273 #[track_caller]
274 pub fn borrow(&self) -> UncheckedRef<'_, T> {
275 match self.try_borrow() {
276 Ok(b) => b,
277 Err(err) => panic_already_borrowed(err),
278 }
279 }
280
281 /// Immutably borrows the wrapped value, returning an error if the value is currently mutably
282 /// borrowed.
283 ///
284 /// The borrow lasts until the returned `UncheckedRef` exits scope. Multiple immutable borrows can be
285 /// taken out at the same time.
286 ///
287 /// This is the non-panicking variant of [`borrow`](#method.borrow).
288 ///
289 /// # Examples
290 ///
291 /// ```
292 /// use unchecked_refcell::UncheckedRefCell;
293 ///
294 /// let c = UncheckedRefCell::new(5);
295 ///
296 /// {
297 /// let m = c.borrow_mut();
298 /// assert!(c.try_borrow().is_err());
299 /// }
300 ///
301 /// {
302 /// let m = c.borrow();
303 /// assert!(c.try_borrow().is_ok());
304 /// }
305 /// ```
306 #[inline]
307 pub fn try_borrow(&self) -> Result<UncheckedRef<'_, T>, BorrowError> {
308 #[cfg(any(feature = "checked", debug_assertions))]
309 match BorrowRef::new(&self.borrow) {
310 Some(b) => {
311 // SAFETY: `BorrowRef` ensures that there is only immutable access
312 // to the value while borrowed.
313 let value = unsafe { NonNull::new_unchecked(self.value.get()) };
314 Ok(UncheckedRef { value, borrow: b })
315 }
316 None => Err(BorrowError {
317 // If a borrow occurred, then we must already have an outstanding borrow,
318 // so `borrowed_at` will be `Some`
319 #[cfg(feature = "debug_refcell")]
320 location: self.borrowed_at.get().unwrap(),
321 }),
322 }
323 #[cfg(not(any(feature = "checked", debug_assertions)))]
324 {
325 // SAFETY: `BorrowRef` ensures that there is only immutable access
326 // to the value while borrowed.
327 let value = unsafe { NonNull::new_unchecked(self.value.get()) };
328 Ok(UncheckedRef {
329 value,
330 marker: PhantomData,
331 })
332 }
333 }
334
335 /// Mutably borrows the wrapped value.
336 ///
337 /// The borrow lasts until the returned `UncheckedRefMut` or all `UncheckedRefMut`s derived
338 /// from it exit scope. The value cannot be borrowed while this borrow is
339 /// active.
340 ///
341 /// # Panics
342 ///
343 /// Panics if the value is currently borrowed. For a non-panicking variant, use
344 /// [`try_borrow_mut`](#method.try_borrow_mut).
345 ///
346 /// # Examples
347 ///
348 /// ```
349 /// use unchecked_refcell::UncheckedRefCell;
350 ///
351 /// let c = UncheckedRefCell::new("hello".to_owned());
352 ///
353 /// *c.borrow_mut() = "bonjour".to_owned();
354 ///
355 /// assert_eq!(&*c.borrow(), "bonjour");
356 /// ```
357 ///
358 /// An example of panic:
359 ///
360 /// ```should_panic
361 /// use unchecked_refcell::UncheckedRefCell;
362 ///
363 /// let c = UncheckedRefCell::new(5);
364 /// let m = c.borrow();
365 ///
366 /// let b = c.borrow_mut(); // this causes a panic
367 /// ```
368 #[inline]
369 #[track_caller]
370 pub fn borrow_mut(&self) -> UncheckedRefMut<'_, T> {
371 match self.try_borrow_mut() {
372 Ok(b) => b,
373 Err(err) => panic_already_mutably_borrowed(err),
374 }
375 }
376
377 /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed.
378 ///
379 /// The borrow lasts until the returned `UncheckedRefMut` or all `UncheckedRefMut`s derived
380 /// from it exit scope. The value cannot be borrowed while this borrow is
381 /// active.
382 ///
383 /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut).
384 ///
385 /// # Examples
386 ///
387 /// ```
388 /// use unchecked_refcell::UncheckedRefCell;
389 ///
390 /// let c = UncheckedRefCell::new(5);
391 ///
392 /// {
393 /// let m = c.borrow();
394 /// assert!(c.try_borrow_mut().is_err());
395 /// }
396 ///
397 /// assert!(c.try_borrow_mut().is_ok());
398 /// ```
399 #[inline]
400 #[cfg_attr(feature = "debug_refcell", track_caller)]
401 pub fn try_borrow_mut(&self) -> Result<UncheckedRefMut<'_, T>, BorrowMutError> {
402 #[cfg(any(feature = "checked", debug_assertions))]
403 {
404 match BorrowRefMut::new(&self.borrow) {
405 Some(b) => {
406 #[cfg(feature = "debug_refcell")]
407 {
408 self.borrowed_at
409 .replace(Some(core::panic::Location::caller()));
410 }
411
412 // SAFETY: `BorrowRefMut` guarantees unique access.
413 let value = unsafe { NonNull::new_unchecked(self.value.get()) };
414 Ok(UncheckedRefMut {
415 value,
416 borrow: b,
417 marker: PhantomData,
418 })
419 }
420 None => Err(BorrowMutError {
421 // If a borrow occurred, then we must already have an outstanding borrow,
422 // so `borrowed_at` will be `Some`
423 #[cfg(feature = "debug_refcell")]
424 location: self.borrowed_at.get().unwrap(),
425 }),
426 }
427 }
428 #[cfg(not(any(feature = "checked", debug_assertions)))]
429 {
430 let value = unsafe { NonNull::new_unchecked(self.value.get()) };
431 Ok(UncheckedRefMut {
432 value,
433 marker: PhantomData,
434 })
435 }
436 }
437
438 /// Returns a raw pointer to the underlying data in this cell.
439 ///
440 /// # Examples
441 ///
442 /// ```
443 /// use unchecked_refcell::UncheckedRefCell;
444 ///
445 /// let c = UncheckedRefCell::new(5);
446 ///
447 /// let ptr = c.as_ptr();
448 /// ```
449 #[inline]
450 pub const fn as_ptr(&self) -> *mut T {
451 self.value.get()
452 }
453
454 /// Returns a mutable reference to the underlying data.
455 ///
456 /// Since this method borrows `RefCell` mutably, it is statically guaranteed
457 /// that no borrows to the underlying data exist. The dynamic checks inherent
458 /// in [`borrow_mut`] and most other methods of `RefCell` are therefore
459 /// unnecessary. Note that this method does not reset the borrowing state if borrows were previously leaked
460 /// (e.g., via [`forget()`] on a [`UncheckedRef`] or [`UncheckedRefMut`]). For that purpose,
461 /// consider using the unstable [`undo_leak`] method.
462 ///
463 /// This method can only be called if `RefCell` can be mutably borrowed,
464 /// which in general is only the case directly after the `RefCell` has
465 /// been created. In these situations, skipping the aforementioned dynamic
466 /// borrowing checks may yield better ergonomics and runtime-performance.
467 ///
468 /// In most situations where `RefCell` is used, it can't be borrowed mutably.
469 /// Use [`borrow_mut`] to get mutable access to the underlying data then.
470 ///
471 /// [`borrow_mut`]: UncheckedRefCell::borrow_mut()
472 /// [`forget()`]: mem::forget
473 /// [`undo_leak`]: UncheckedRefCell::undo_leak()
474 ///
475 /// # Examples
476 ///
477 /// ```
478 /// use unchecked_refcell::UncheckedRefCell;
479 ///
480 /// let mut c = UncheckedRefCell::new(5);
481 /// *c.get_mut() += 1;
482 ///
483 /// assert_eq!(c, UncheckedRefCell::new(6));
484 /// ```
485 #[inline]
486 pub const fn get_mut(&mut self) -> &mut T {
487 self.value.get_mut()
488 }
489
490 /// Undo the effect of leaked guards on the borrow state of the `RefCell`.
491 ///
492 /// This call is similar to [`get_mut`] but more specialized. It borrows `RefCell` mutably to
493 /// ensure no borrows exist and then resets the state tracking shared borrows. This is relevant
494 /// if some `UncheckedRef` or `UncheckedRefMut` borrows have been leaked.
495 ///
496 /// [`get_mut`]: UncheckedRefCell::get_mut()
497 ///
498 /// # Examples
499 ///
500 /// ```
501 /// use unchecked_refcell::UncheckedRefCell;
502 ///
503 /// let mut c = UncheckedRefCell::new(0);
504 /// std::mem::forget(c.borrow_mut());
505 ///
506 /// assert!(c.try_borrow().is_err());
507 /// c.undo_leak();
508 /// assert!(c.try_borrow().is_ok());
509 /// ```
510 pub const fn undo_leak(&mut self) -> &mut T {
511 #[cfg(any(feature = "checked", debug_assertions))]
512 {
513 *self.borrow.get_mut() = UNUSED;
514 }
515 self.get_mut()
516 }
517
518 /// Immutably borrows the wrapped value, returning an error if the value is
519 /// currently mutably borrowed.
520 ///
521 /// # Safety
522 ///
523 /// Unlike `RefCell::borrow`, this method is unsafe because it does not
524 /// return a `UncheckedRef`, thus leaving the borrow flag untouched. Mutably
525 /// borrowing the `RefCell` while the reference returned by this method
526 /// is alive is undefined behavior.
527 ///
528 /// # Examples
529 ///
530 /// ```
531 /// use unchecked_refcell::UncheckedRefCell;
532 ///
533 /// let c = UncheckedRefCell::new(5);
534 ///
535 /// {
536 /// let m = c.borrow_mut();
537 /// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
538 /// }
539 ///
540 /// {
541 /// let m = c.borrow();
542 /// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
543 /// }
544 /// ```
545 #[inline]
546 pub const unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
547 #[cfg(any(feature = "checked", debug_assertions))]
548 {
549 if !is_writing(self.borrow.get()) {
550 // SAFETY: We check that nobody is actively writing now, but it is
551 // the caller's responsibility to ensure that nobody writes until
552 // the returned reference is no longer in use.
553 // Also, `self.value.get()` refers to the value owned by `self`
554 // and is thus guaranteed to be valid for the lifetime of `self`.
555 Ok(unsafe { &*self.value.get() })
556 } else {
557 Err(BorrowError {
558 // If a borrow occurred, then we must already have an outstanding borrow,
559 // so `borrowed_at` will be `Some`
560 #[cfg(feature = "debug_refcell")]
561 location: self.borrowed_at.get().unwrap(),
562 })
563 }
564 }
565 #[cfg(not(any(feature = "checked", debug_assertions)))]
566 Ok(unsafe { &*self.value.get() })
567 }
568}
569
570impl<T: Default> UncheckedRefCell<T> {
571 /// Takes the wrapped value, leaving `Default::default()` in its place.
572 ///
573 /// # Panics
574 ///
575 /// Panics if the value is currently borrowed.
576 ///
577 /// # Examples
578 ///
579 /// ```
580 /// use unchecked_refcell::UncheckedRefCell;
581 ///
582 /// let c = UncheckedRefCell::new(5);
583 /// let five = c.take();
584 ///
585 /// assert_eq!(five, 5);
586 /// assert_eq!(c.into_inner(), 0);
587 /// ```
588 pub fn take(&self) -> T {
589 self.replace(Default::default())
590 }
591}
592
593unsafe impl<T: ?Sized> Send for UncheckedRefCell<T> where T: Send {}
594
595impl<T: Clone> Clone for UncheckedRefCell<T> {
596 /// # Panics
597 ///
598 /// Panics if the value is currently mutably borrowed.
599 #[inline]
600 #[track_caller]
601 fn clone(&self) -> UncheckedRefCell<T> {
602 UncheckedRefCell::new(self.borrow().clone())
603 }
604
605 /// # Panics
606 ///
607 /// Panics if `source` is currently mutably borrowed.
608 #[inline]
609 #[track_caller]
610 fn clone_from(&mut self, source: &Self) {
611 self.get_mut().clone_from(&source.borrow())
612 }
613}
614
615impl<T: Default> Default for UncheckedRefCell<T> {
616 /// Creates a `RefCell<T>`, with the `Default` value for T.
617 #[inline]
618 fn default() -> UncheckedRefCell<T> {
619 UncheckedRefCell::new(Default::default())
620 }
621}
622
623impl<T: ?Sized + PartialEq> PartialEq for UncheckedRefCell<T> {
624 /// # Panics
625 ///
626 /// Panics if the value in either `RefCell` is currently mutably borrowed.
627 #[inline]
628 fn eq(&self, other: &UncheckedRefCell<T>) -> bool {
629 *self.borrow() == *other.borrow()
630 }
631}
632
633impl<T: ?Sized + Eq> Eq for UncheckedRefCell<T> {}
634
635impl<T: ?Sized + PartialOrd> PartialOrd for UncheckedRefCell<T> {
636 /// # Panics
637 ///
638 /// Panics if the value in either `RefCell` is currently mutably borrowed.
639 #[inline]
640 fn partial_cmp(&self, other: &UncheckedRefCell<T>) -> Option<Ordering> {
641 self.borrow().partial_cmp(&*other.borrow())
642 }
643
644 /// # Panics
645 ///
646 /// Panics if the value in either `RefCell` is currently mutably borrowed.
647 #[inline]
648 fn lt(&self, other: &UncheckedRefCell<T>) -> bool {
649 *self.borrow() < *other.borrow()
650 }
651
652 /// # Panics
653 ///
654 /// Panics if the value in either `RefCell` is currently mutably borrowed.
655 #[inline]
656 fn le(&self, other: &UncheckedRefCell<T>) -> bool {
657 *self.borrow() <= *other.borrow()
658 }
659
660 /// # Panics
661 ///
662 /// Panics if the value in either `RefCell` is currently mutably borrowed.
663 #[inline]
664 fn gt(&self, other: &UncheckedRefCell<T>) -> bool {
665 *self.borrow() > *other.borrow()
666 }
667
668 /// # Panics
669 ///
670 /// Panics if the value in either `RefCell` is currently mutably borrowed.
671 #[inline]
672 fn ge(&self, other: &UncheckedRefCell<T>) -> bool {
673 *self.borrow() >= *other.borrow()
674 }
675}
676
677impl<T: ?Sized + Ord> Ord for UncheckedRefCell<T> {
678 /// # Panics
679 ///
680 /// Panics if the value in either `RefCell` is currently mutably borrowed.
681 #[inline]
682 fn cmp(&self, other: &UncheckedRefCell<T>) -> Ordering {
683 self.borrow().cmp(&*other.borrow())
684 }
685}
686
687impl<T> From<T> for UncheckedRefCell<T> {
688 /// Creates a new `RefCell<T>` containing the given value.
689 fn from(t: T) -> UncheckedRefCell<T> {
690 UncheckedRefCell::new(t)
691 }
692}
693
694struct BorrowRef<'b> {
695 borrow: &'b Cell<BorrowCounter>,
696}
697
698impl<'b> BorrowRef<'b> {
699 #[inline]
700 const fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRef<'b>> {
701 let b = borrow.get().wrapping_add(1);
702 if !is_reading(b) {
703 // Incrementing borrow can result in a non-reading value (<= 0) in these cases:
704 // 1. It was < 0, i.e. there are writing borrows, so we can't allow a read borrow
705 // due to Rust's reference aliasing rules
706 // 2. It was isize::MAX (the max amount of reading borrows) and it overflowed
707 // into isize::MIN (the max amount of writing borrows) so we can't allow
708 // an additional read borrow because isize can't represent so many read borrows
709 // (this can only happen if you mem::forget more than a small constant amount of
710 // `UncheckedRef`s, which is not good practice)
711 None
712 } else {
713 // Incrementing borrow can result in a reading value (> 0) in these cases:
714 // 1. It was = 0, i.e. it wasn't borrowed, and we are taking the first read borrow
715 // 2. It was > 0 and < isize::MAX, i.e. there were read borrows, and isize
716 // is large enough to represent having one more read borrow
717 borrow.replace(b);
718 Some(BorrowRef { borrow })
719 }
720 }
721}
722
723impl Drop for BorrowRef<'_> {
724 #[inline]
725 fn drop(&mut self) {
726 let borrow = self.borrow.get();
727 debug_assert!(is_reading(borrow));
728 self.borrow.replace(borrow - 1);
729 }
730}
731
732impl Clone for BorrowRef<'_> {
733 #[inline]
734 fn clone(&self) -> Self {
735 // Since this Ref exists, we know the borrow flag
736 // is a reading borrow.
737 let borrow = self.borrow.get();
738 debug_assert!(is_reading(borrow));
739 // Prevent the borrow counter from overflowing into
740 // a writing borrow.
741 assert!(borrow != BorrowCounter::MAX);
742 self.borrow.replace(borrow + 1);
743 BorrowRef {
744 borrow: self.borrow,
745 }
746 }
747}
748
749/// Wraps a borrowed reference to a value in a `RefCell` box.
750/// A wrapper type for an immutably borrowed value from a `RefCell<T>`.
751///
752/// See the [module-level documentation](self) for more.
753pub struct UncheckedRef<'b, T: ?Sized + 'b> {
754 // NB: we use a pointer instead of `&'b T` to avoid `noalias` violations, because a
755 // `UncheckedRef` argument doesn't hold immutability for its whole scope, only until it drops.
756 // `NonNull` is also covariant over `T`, just like we would have with `&T`.
757 value: NonNull<T>,
758 #[cfg(any(feature = "checked", debug_assertions))]
759 borrow: BorrowRef<'b>,
760 #[cfg(not(any(feature = "checked", debug_assertions)))]
761 marker: PhantomData<&'b ()>,
762}
763
764impl<T: ?Sized> Deref for UncheckedRef<'_, T> {
765 type Target = T;
766
767 #[inline]
768 fn deref(&self) -> &T {
769 // SAFETY: the value is accessible as long as we hold our borrow.
770 unsafe { self.value.as_ref() }
771 }
772}
773
774impl<'b, T: ?Sized> UncheckedRef<'b, T> {
775 /// Copies a `UncheckedRef`.
776 ///
777 /// The `RefCell` is already immutably borrowed, so this cannot fail.
778 ///
779 /// This is an associated function that needs to be used as
780 /// `UncheckedRef::clone(...)`. A `Clone` implementation or a method would interfere
781 /// with the widespread use of `r.borrow().clone()` to clone the contents of
782 /// a `RefCell`.
783 #[must_use]
784 #[inline]
785 pub fn clone(orig: &UncheckedRef<'b, T>) -> UncheckedRef<'b, T> {
786 UncheckedRef {
787 value: orig.value,
788 #[cfg(any(feature = "checked", debug_assertions))]
789 borrow: orig.borrow.clone(),
790 #[cfg(not(any(feature = "checked", debug_assertions)))]
791 marker: PhantomData,
792 }
793 }
794
795 /// Makes a new `UncheckedRef` for a component of the borrowed data.
796 ///
797 /// The `RefCell` is already immutably borrowed, so this cannot fail.
798 ///
799 /// This is an associated function that needs to be used as `UncheckedRef::map(...)`.
800 /// A method would interfere with methods of the same name on the contents
801 /// of a `RefCell` used through `Deref`.
802 ///
803 /// # Examples
804 ///
805 /// ```
806 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRef};
807 ///
808 /// let c = UncheckedRefCell::new((5, 'b'));
809 /// let b1: UncheckedRef<'_, (u32, char)> = c.borrow();
810 /// let b2: UncheckedRef<'_, u32> = UncheckedRef::map(b1, |t| &t.0);
811 /// assert_eq!(*b2, 5)
812 /// ```
813 #[inline]
814 pub fn map<U: ?Sized, F>(orig: UncheckedRef<'b, T>, f: F) -> UncheckedRef<'b, U>
815 where
816 F: FnOnce(&T) -> &U,
817 {
818 UncheckedRef {
819 value: NonNull::from(f(&*orig)),
820 #[cfg(any(feature = "checked", debug_assertions))]
821 borrow: orig.borrow,
822 #[cfg(not(any(feature = "checked", debug_assertions)))]
823 marker: PhantomData,
824 }
825 }
826
827 /// Makes a new `UncheckedRef` for an optional component of the borrowed data. The
828 /// original guard is returned as an `Err(..)` if the closure returns
829 /// `None`.
830 ///
831 /// The `RefCell` is already immutably borrowed, so this cannot fail.
832 ///
833 /// This is an associated function that needs to be used as
834 /// `UncheckedRef::filter_map(...)`. A method would interfere with methods of the same
835 /// name on the contents of a `RefCell` used through `Deref`.
836 ///
837 /// # Examples
838 ///
839 /// ```
840 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRef};
841 ///
842 /// let c = UncheckedRefCell::new(vec![1, 2, 3]);
843 /// let b1: UncheckedRef<'_, Vec<u32>> = c.borrow();
844 /// let b2: Result<UncheckedRef<'_, u32>, _> = UncheckedRef::filter_map(b1, |v| v.get(1));
845 /// assert_eq!(*b2.unwrap(), 2);
846 /// ```
847 #[inline]
848 pub fn filter_map<U: ?Sized, F>(orig: UncheckedRef<'b, T>, f: F) -> Result<UncheckedRef<'b, U>, Self>
849 where
850 F: FnOnce(&T) -> Option<&U>,
851 {
852 match f(&*orig) {
853 Some(value) => Ok(UncheckedRef {
854 value: NonNull::from(value),
855 #[cfg(any(feature = "checked", debug_assertions))]
856 borrow: orig.borrow,
857 #[cfg(not(any(feature = "checked", debug_assertions)))]
858 marker: PhantomData,
859 }),
860 None => Err(orig),
861 }
862 }
863
864 /// Tries to makes a new `UncheckedRef` for a component of the borrowed data.
865 /// On failure, the original guard is returned alongside with the error
866 /// returned by the closure.
867 ///
868 /// The `RefCell` is already immutably borrowed, so this cannot fail.
869 ///
870 /// This is an associated function that needs to be used as
871 /// `UncheckedRef::try_map(...)`. A method would interfere with methods of the same
872 /// name on the contents of a `RefCell` used through `Deref`.
873 ///
874 /// # Examples
875 ///
876 /// ```
877 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRef};
878 /// use std::str::{from_utf8, Utf8Error};
879 ///
880 /// let c = UncheckedRefCell::new(vec![0xF0, 0x9F, 0xA6 ,0x80]);
881 /// let b1: UncheckedRef<'_, Vec<u8>> = c.borrow();
882 /// let b2: Result<UncheckedRef<'_, str>, _> = UncheckedRef::try_map(b1, |v| from_utf8(v));
883 /// assert_eq!(&*b2.unwrap(), "🦀");
884 ///
885 /// let c = UncheckedRefCell::new(vec![0xF0, 0x9F, 0xA6]);
886 /// let b1: UncheckedRef<'_, Vec<u8>> = c.borrow();
887 /// let b2: Result<_, (UncheckedRef<'_, Vec<u8>>, Utf8Error)> = UncheckedRef::try_map(b1, |v| from_utf8(v));
888 /// let (b3, e) = b2.unwrap_err();
889 /// assert_eq!(*b3, vec![0xF0, 0x9F, 0xA6]);
890 /// assert_eq!(e.valid_up_to(), 0);
891 /// ```
892 #[inline]
893 pub fn try_map<U: ?Sized, E>(
894 orig: UncheckedRef<'b, T>,
895 f: impl FnOnce(&T) -> Result<&U, E>,
896 ) -> Result<UncheckedRef<'b, U>, (Self, E)> {
897 match f(&*orig) {
898 Ok(value) => Ok(UncheckedRef {
899 value: NonNull::from(value),
900 #[cfg(any(feature = "checked", debug_assertions))]
901 borrow: orig.borrow,
902 #[cfg(not(any(feature = "checked", debug_assertions)))]
903 marker: PhantomData,
904 }),
905 Err(e) => Err((orig, e)),
906 }
907 }
908
909 /// Splits a `UncheckedRef` into multiple `UncheckedRef`s for different components of the
910 /// borrowed data.
911 ///
912 /// The `RefCell` is already immutably borrowed, so this cannot fail.
913 ///
914 /// This is an associated function that needs to be used as
915 /// `UncheckedRef::map_split(...)`. A method would interfere with methods of the same
916 /// name on the contents of a `RefCell` used through `Deref`.
917 ///
918 /// # Examples
919 ///
920 /// ```
921 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRef};
922 ///
923 /// let cell = UncheckedRefCell::new([1, 2, 3, 4]);
924 /// let borrow = cell.borrow();
925 /// let (begin, end) = UncheckedRef::map_split(borrow, |slice| slice.split_at(2));
926 /// assert_eq!(*begin, [1, 2]);
927 /// assert_eq!(*end, [3, 4]);
928 /// ```
929 #[inline]
930 pub fn map_split<U: ?Sized, V: ?Sized, F>(orig: UncheckedRef<'b, T>, f: F) -> (UncheckedRef<'b, U>, UncheckedRef<'b, V>)
931 where
932 F: FnOnce(&T) -> (&U, &V),
933 {
934 let (a, b) = f(&*orig);
935 #[cfg(any(feature = "checked", debug_assertions))]
936 let borrow = orig.borrow.clone();
937 (
938 UncheckedRef {
939 value: NonNull::from(a),
940 #[cfg(any(feature = "checked", debug_assertions))]
941 borrow,
942 #[cfg(not(any(feature = "checked", debug_assertions)))]
943 marker: PhantomData,
944 },
945 UncheckedRef {
946 value: NonNull::from(b),
947 #[cfg(any(feature = "checked", debug_assertions))]
948 borrow: orig.borrow,
949 #[cfg(not(any(feature = "checked", debug_assertions)))]
950 marker: PhantomData,
951 },
952 )
953 }
954
955 /// Converts into a reference to the underlying data.
956 ///
957 /// The underlying `RefCell` can never be mutably borrowed from again and will always appear
958 /// already immutably borrowed. It is not a good idea to leak more than a constant number of
959 /// references. The `RefCell` can be immutably borrowed again if only a smaller number of leaks
960 /// have occurred in total.
961 ///
962 /// This is an associated function that needs to be used as
963 /// `UncheckedRef::leak(...)`. A method would interfere with methods of the
964 /// same name on the contents of a `RefCell` used through `Deref`.
965 ///
966 /// # Examples
967 ///
968 /// ```
969 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRef};
970 /// let cell = UncheckedRefCell::new(0);
971 ///
972 /// let value = UncheckedRef::leak(cell.borrow());
973 /// assert_eq!(*value, 0);
974 ///
975 /// assert!(cell.try_borrow().is_ok());
976 /// assert!(cell.try_borrow_mut().is_err());
977 /// ```
978 pub fn leak(orig: UncheckedRef<'b, T>) -> &'b T {
979 // By forgetting this Ref we ensure that the borrow counter in the RefCell can't go back to
980 // UNUSED within the lifetime `'b`. Resetting the reference tracking state would require a
981 // unique reference to the borrowed RefCell. No further mutable references can be created
982 // from the original cell.
983 #[cfg(any(feature = "checked", debug_assertions))]
984 mem::forget(orig.borrow);
985 // SAFETY: after forgetting, we can form a reference for the rest of lifetime `'b`.
986 unsafe { orig.value.as_ref() }
987 }
988}
989
990impl<T: ?Sized + fmt::Display> fmt::Display for UncheckedRef<'_, T> {
991 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
992 (**self).fmt(f)
993 }
994}
995
996impl<'b, T: ?Sized> UncheckedRefMut<'b, T> {
997 /// Makes a new `UncheckedRefMut` for a component of the borrowed data, e.g., an enum
998 /// variant.
999 ///
1000 /// The `RefCell` is already mutably borrowed, so this cannot fail.
1001 ///
1002 /// This is an associated function that needs to be used as
1003 /// `UncheckedRefMut::map(...)`. A method would interfere with methods of the same
1004 /// name on the contents of a `RefCell` used through `Deref`.
1005 ///
1006 /// # Examples
1007 ///
1008 /// ```
1009 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRefMut};
1010 ///
1011 /// let c = UncheckedRefCell::new((5, 'b'));
1012 /// {
1013 /// let b1: UncheckedRefMut<'_, (u32, char)> = c.borrow_mut();
1014 /// let mut b2: UncheckedRefMut<'_, u32> = UncheckedRefMut::map(b1, |t| &mut t.0);
1015 /// assert_eq!(*b2, 5);
1016 /// *b2 = 42;
1017 /// }
1018 /// assert_eq!(*c.borrow(), (42, 'b'));
1019 /// ```
1020 #[inline]
1021 pub fn map<U: ?Sized, F>(mut orig: UncheckedRefMut<'b, T>, f: F) -> UncheckedRefMut<'b, U>
1022 where
1023 F: FnOnce(&mut T) -> &mut U,
1024 {
1025 let value = NonNull::from(f(&mut *orig));
1026 UncheckedRefMut {
1027 value,
1028 #[cfg(any(feature = "checked", debug_assertions))]
1029 borrow: orig.borrow,
1030 marker: PhantomData,
1031 }
1032 }
1033
1034 /// Makes a new `UncheckedRefMut` for an optional component of the borrowed data. The
1035 /// original guard is returned as an `Err(..)` if the closure returns
1036 /// `None`.
1037 ///
1038 /// The `RefCell` is already mutably borrowed, so this cannot fail.
1039 ///
1040 /// This is an associated function that needs to be used as
1041 /// `UncheckedRefMut::filter_map(...)`. A method would interfere with methods of the
1042 /// same name on the contents of a `RefCell` used through `Deref`.
1043 ///
1044 /// # Examples
1045 ///
1046 /// ```
1047 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRefMut};
1048 ///
1049 /// let c = UncheckedRefCell::new(vec![1, 2, 3]);
1050 ///
1051 /// {
1052 /// let b1: UncheckedRefMut<'_, Vec<u32>> = c.borrow_mut();
1053 /// let mut b2: Result<UncheckedRefMut<'_, u32>, _> = UncheckedRefMut::filter_map(b1, |v| v.get_mut(1));
1054 ///
1055 /// if let Ok(mut b2) = b2 {
1056 /// *b2 += 2;
1057 /// }
1058 /// }
1059 ///
1060 /// assert_eq!(*c.borrow(), vec![1, 4, 3]);
1061 /// ```
1062 #[inline]
1063 pub fn filter_map<U: ?Sized, F>(mut orig: UncheckedRefMut<'b, T>, f: F) -> Result<UncheckedRefMut<'b, U>, Self>
1064 where
1065 F: FnOnce(&mut T) -> Option<&mut U>,
1066 {
1067 // SAFETY: function holds onto an exclusive reference for the duration
1068 // of its call through `orig`, and the pointer is only de-referenced
1069 // inside of the function call never allowing the exclusive reference to
1070 // escape.
1071 match f(&mut *orig) {
1072 Some(value) => Ok(UncheckedRefMut {
1073 value: NonNull::from(value),
1074 #[cfg(any(feature = "checked", debug_assertions))]
1075 borrow: orig.borrow,
1076 marker: PhantomData,
1077 }),
1078 None => Err(orig),
1079 }
1080 }
1081
1082 /// Tries to makes a new `UncheckedRefMut` for a component of the borrowed data.
1083 /// On failure, the original guard is returned alongside with the error
1084 /// returned by the closure.
1085 ///
1086 /// The `RefCell` is already mutably borrowed, so this cannot fail.
1087 ///
1088 /// This is an associated function that needs to be used as
1089 /// `UncheckedRefMut::try_map(...)`. A method would interfere with methods of the same
1090 /// name on the contents of a `RefCell` used through `Deref`.
1091 ///
1092 /// # Examples
1093 ///
1094 /// ```
1095 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRefMut};
1096 /// use std::str::{from_utf8_mut, Utf8Error};
1097 ///
1098 /// let c = UncheckedRefCell::new(vec![0x68, 0x65, 0x6C, 0x6C, 0x6F]);
1099 /// {
1100 /// let b1: UncheckedRefMut<'_, Vec<u8>> = c.borrow_mut();
1101 /// let b2: Result<UncheckedRefMut<'_, str>, _> = UncheckedRefMut::try_map(b1, |v| from_utf8_mut(v));
1102 /// let mut b2 = b2.unwrap();
1103 /// assert_eq!(&*b2, "hello");
1104 /// b2.make_ascii_uppercase();
1105 /// }
1106 /// assert_eq!(*c.borrow(), "HELLO".as_bytes());
1107 ///
1108 /// let c = UncheckedRefCell::new(vec![0xFF]);
1109 /// let b1: UncheckedRefMut<'_, Vec<u8>> = c.borrow_mut();
1110 /// let b2: Result<_, (UncheckedRefMut<'_, Vec<u8>>, Utf8Error)> = UncheckedRefMut::try_map(b1, |v| from_utf8_mut(v));
1111 /// let (b3, e) = b2.unwrap_err();
1112 /// assert_eq!(*b3, vec![0xFF]);
1113 /// assert_eq!(e.valid_up_to(), 0);
1114 /// ```
1115 #[inline]
1116 pub fn try_map<U: ?Sized, E>(
1117 mut orig: UncheckedRefMut<'b, T>,
1118 f: impl FnOnce(&mut T) -> Result<&mut U, E>,
1119 ) -> Result<UncheckedRefMut<'b, U>, (Self, E)> {
1120 // SAFETY: function holds onto an exclusive reference for the duration
1121 // of its call through `orig`, and the pointer is only de-referenced
1122 // inside of the function call never allowing the exclusive reference to
1123 // escape.
1124 match f(&mut *orig) {
1125 Ok(value) => Ok(UncheckedRefMut {
1126 value: NonNull::from(value),
1127 #[cfg(any(feature = "checked", debug_assertions))]
1128 borrow: orig.borrow,
1129 marker: PhantomData,
1130 }),
1131 Err(e) => Err((orig, e)),
1132 }
1133 }
1134
1135 /// Splits a `UncheckedRefMut` into multiple `UncheckedRefMut`s for different components of the
1136 /// borrowed data.
1137 ///
1138 /// The underlying `RefCell` will remain mutably borrowed until both
1139 /// returned `UncheckedRefMut`s go out of scope.
1140 ///
1141 /// The `RefCell` is already mutably borrowed, so this cannot fail.
1142 ///
1143 /// This is an associated function that needs to be used as
1144 /// `UncheckedRefMut::map_split(...)`. A method would interfere with methods of the
1145 /// same name on the contents of a `RefCell` used through `Deref`.
1146 ///
1147 /// # Examples
1148 ///
1149 /// ```
1150 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRefMut};
1151 ///
1152 /// let cell = UncheckedRefCell::new([1, 2, 3, 4]);
1153 /// let borrow = cell.borrow_mut();
1154 /// let (mut begin, mut end) = UncheckedRefMut::map_split(borrow, |slice| slice.split_at_mut(2));
1155 /// assert_eq!(*begin, [1, 2]);
1156 /// assert_eq!(*end, [3, 4]);
1157 /// begin.copy_from_slice(&[4, 3]);
1158 /// end.copy_from_slice(&[2, 1]);
1159 /// ```
1160 #[inline]
1161 pub fn map_split<U: ?Sized, V: ?Sized, F>(
1162 mut orig: UncheckedRefMut<'b, T>,
1163 f: F,
1164 ) -> (UncheckedRefMut<'b, U>, UncheckedRefMut<'b, V>)
1165 where
1166 F: FnOnce(&mut T) -> (&mut U, &mut V),
1167 {
1168 #[cfg(any(feature = "checked", debug_assertions))]
1169 let borrow = orig.borrow.clone();
1170 let (a, b) = f(&mut *orig);
1171 (
1172 UncheckedRefMut {
1173 value: NonNull::from(a),
1174 #[cfg(any(feature = "checked", debug_assertions))]
1175 borrow,
1176 marker: PhantomData,
1177 },
1178 UncheckedRefMut {
1179 value: NonNull::from(b),
1180 #[cfg(any(feature = "checked", debug_assertions))]
1181 borrow: orig.borrow,
1182 marker: PhantomData,
1183 },
1184 )
1185 }
1186
1187 /// Converts into a mutable reference to the underlying data.
1188 ///
1189 /// The underlying `RefCell` can not be borrowed from again and will always appear already
1190 /// mutably borrowed, making the returned reference the only to the interior.
1191 ///
1192 /// This is an associated function that needs to be used as
1193 /// `UncheckedRefMut::leak(...)`. A method would interfere with methods of the
1194 /// same name on the contents of a `RefCell` used through `Deref`.
1195 ///
1196 /// # Examples
1197 ///
1198 /// ```
1199 /// use unchecked_refcell::{UncheckedRefCell, UncheckedRefMut};
1200 /// let cell = UncheckedRefCell::new(0);
1201 ///
1202 /// let value = UncheckedRefMut::leak(cell.borrow_mut());
1203 /// assert_eq!(*value, 0);
1204 /// *value = 1;
1205 ///
1206 /// assert!(cell.try_borrow_mut().is_err());
1207 /// ```
1208 pub fn leak(mut orig: UncheckedRefMut<'b, T>) -> &'b mut T {
1209 // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell can't
1210 // go back to UNUSED within the lifetime `'b`. Resetting the reference tracking state would
1211 // require a unique reference to the borrowed RefCell. No further references can be created
1212 // from the original cell within that lifetime, making the current borrow the only
1213 // reference for the remaining lifetime.
1214 #[cfg(any(feature = "checked", debug_assertions))]
1215 mem::forget(orig.borrow);
1216 // SAFETY: after forgetting, we can form a reference for the rest of lifetime `'b`.
1217 unsafe { orig.value.as_mut() }
1218 }
1219}
1220
1221struct BorrowRefMut<'b> {
1222 borrow: &'b Cell<BorrowCounter>,
1223}
1224
1225impl Drop for BorrowRefMut<'_> {
1226 #[inline]
1227 fn drop(&mut self) {
1228 let borrow = self.borrow.get();
1229 debug_assert!(is_writing(borrow));
1230 self.borrow.replace(borrow + 1);
1231 }
1232}
1233
1234impl<'b> BorrowRefMut<'b> {
1235 #[inline]
1236 const fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRefMut<'b>> {
1237 // NOTE: Unlike BorrowRefMut::clone, new is called to create the initial
1238 // mutable reference, and so there must currently be no existing
1239 // references. Thus, while clone increments the mutable refcount, here
1240 // we explicitly only allow going from UNUSED to UNUSED - 1.
1241 match borrow.get() {
1242 UNUSED => {
1243 borrow.replace(UNUSED - 1);
1244 Some(BorrowRefMut { borrow })
1245 }
1246 _ => None,
1247 }
1248 }
1249
1250 // Clones a `BorrowRefMut`.
1251 //
1252 // This is only valid if each `BorrowRefMut` is used to track a mutable
1253 // reference to a distinct, nonoverlapping range of the original object.
1254 // This isn't in a Clone impl so that code doesn't call this implicitly.
1255 #[inline]
1256 fn clone(&self) -> BorrowRefMut<'b> {
1257 let borrow = self.borrow.get();
1258 debug_assert!(is_writing(borrow));
1259 // Prevent the borrow counter from underflowing.
1260 assert!(borrow != BorrowCounter::MIN);
1261 self.borrow.set(borrow - 1);
1262 BorrowRefMut {
1263 borrow: self.borrow,
1264 }
1265 }
1266}
1267
1268/// A wrapper type for a mutably borrowed value from a `RefCell<T>`.
1269///
1270/// See the [module-level documentation](self) for more.
1271pub struct UncheckedRefMut<'b, T: ?Sized + 'b> {
1272 // NB: we use a pointer instead of `&'b mut T` to avoid `noalias` violations, because a
1273 // `UncheckedRefMut` argument doesn't hold exclusivity for its whole scope, only until it drops.
1274 value: NonNull<T>,
1275 #[cfg(any(feature = "checked", debug_assertions))]
1276 borrow: BorrowRefMut<'b>,
1277 // `NonNull` is covariant over `T`, so we need to reintroduce invariance.
1278 marker: PhantomData<&'b mut T>,
1279}
1280
1281impl<T: ?Sized> Deref for UncheckedRefMut<'_, T> {
1282 type Target = T;
1283
1284 #[inline]
1285 fn deref(&self) -> &T {
1286 // SAFETY: the value is accessible as long as we hold our borrow.
1287 unsafe { self.value.as_ref() }
1288 }
1289}
1290
1291impl<T: ?Sized> DerefMut for UncheckedRefMut<'_, T> {
1292 #[inline]
1293 fn deref_mut(&mut self) -> &mut T {
1294 // SAFETY: the value is accessible as long as we hold our borrow.
1295 unsafe { self.value.as_mut() }
1296 }
1297}
1298
1299impl<T: ?Sized + fmt::Display> fmt::Display for UncheckedRefMut<'_, T> {
1300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1301 (**self).fmt(f)
1302 }
1303}
1304
1305//************************************************************************//
1306
1307impl<T: ?Sized + Debug> Debug for UncheckedRefCell<T> {
1308 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1309 let mut d = f.debug_struct("RefCell");
1310 match self.try_borrow() {
1311 Ok(borrow) => d.field("value", &borrow),
1312 Err(_) => d.field("value", &format_args!("<borrowed>")),
1313 };
1314 d.finish()
1315 }
1316}
1317
1318impl<T: ?Sized + Debug> Debug for UncheckedRef<'_, T> {
1319 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1320 Debug::fmt(&**self, f)
1321 }
1322}
1323
1324impl<T: ?Sized + Debug> Debug for UncheckedRefMut<'_, T> {
1325 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1326 Debug::fmt(&*(self.deref()), f)
1327 }
1328}