Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ mod cell;
mod unsafe_cell;

pub use self::cell::Cell;
pub use self::unsafe_cell::{ConstPtr, MutPtr, UnsafeCell};
pub use self::unsafe_cell::{ConstPtr, MutPtr, MutRef, UnsafeCell};
46 changes: 45 additions & 1 deletion src/cell/unsafe_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,26 @@ pub struct ConstPtr<T: ?Sized> {
/// [here]: #correct-usage
#[derive(Debug)]
pub struct MutPtr<T: ?Sized> {
/// Drop guard representing the lifetime of the `ConstPtr`'s access.
/// Drop guard representing the lifetime of the `MutPtr`'s access.
_guard: rt::cell::Writing,
ptr: *mut T,
}

/// A checked mutable reference to an [`UnsafeCell`].
///
/// This type is essentially a [`&mut T`], but with the added ability to
/// participate in Loom's [`UnsafeCell`] access tracking. While a `MutRef` to a
/// given [`UnsafeCell`] exists, Loom will track that the [`UnsafeCell`] is
/// being accessed mutably.
///
/// [`MutRef`]s are produced by [`UnsafeCell::as_mut`].
#[derive(Debug)]
pub struct MutRef<'a, T: ?Sized> {
/// Drop guard representing the lifetime of the `MutRef`'s access.
_guard: rt::cell::Writing,
ptr: &'a mut T,
}

impl<T> UnsafeCell<T> {
/// Constructs a new instance of `UnsafeCell` which will wrap the specified value.
#[track_caller]
Expand Down Expand Up @@ -200,6 +215,21 @@ impl<T: ?Sized> UnsafeCell<T> {
ptr: self.data.get(),
}
}

/// Get a mutable reference to the wrapped value.
///
/// This function returns a [`MutRef`] guard, which is analogous to a
/// `&mut T`, but tracked by Loom. As long as the returned `MutRef`
/// exists, Loom will consider the cell to be accessed mutably.
///
/// This is analogous to [`core::cell::UnsafeCell::get_mut`].
#[track_caller]
pub fn as_mut(&mut self) -> MutRef<'_, T> {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely certain we even need tracking: if we can mutably borrow the value, we already have exclusive access to it, right? And because we borrow it mutably, no one can re-borrow it immutably until the borrow is dropped.

I've added the in-between struct so that someone can double-check my thoughts, but would be great to get some external input on it.

MutRef {
_guard: self.state.start_write(location!()),
ptr: self.data.get_mut(),
}
}
}

impl<T: Default> Default for UnsafeCell<T> {
Expand Down Expand Up @@ -382,6 +412,20 @@ impl<T: ?Sized> ConstPtr<T> {
}
}

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

fn deref(&self) -> &Self::Target {
self.ptr
}
}

impl<T: ?Sized> core::ops::DerefMut for MutRef<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.ptr
}
}

impl<T: ?Sized> MutPtr<T> {
/// Dereference the raw pointer.
///
Expand Down
9 changes: 9 additions & 0 deletions tests/unsafe_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,12 @@ fn unsafe_cell_access_after_sync() {
}
});
}

#[test]
fn as_mut_is_ergonomical_and_safe() {
loom::model(|| {
let mut value = UnsafeCell::new(-3i32);
let mut mut_ref = value.as_mut();
*mut_ref = mut_ref.abs();
});
}