Skip to content

Commit

Permalink
Make UnsafeCell, RefCell, Mutex, and RwLock accept DSTs
Browse files Browse the repository at this point in the history
This + DST coercions (#24619) would allow code like `Rc<RefCell<Box<Trait>>>` to
be simplified to `Rc<RefCell<Trait>>`.
  • Loading branch information
ftxqxd committed May 1, 2015
1 parent 5c710b5 commit 57d8289
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 68 deletions.
59 changes: 32 additions & 27 deletions src/libcore/cell.rs
Expand Up @@ -144,7 +144,7 @@
use clone::Clone;
use cmp::PartialEq;
use default::Default;
use marker::{Copy, Send, Sync};
use marker::{Copy, Send, Sync, Sized};
use ops::{Deref, DerefMut, Drop};
use option::Option;
use option::Option::{None, Some};
Expand Down Expand Up @@ -266,9 +266,9 @@ impl<T:PartialEq + Copy> PartialEq for Cell<T> {
///
/// See the [module-level documentation](index.html) for more.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RefCell<T> {
value: UnsafeCell<T>,
pub struct RefCell<T: ?Sized> {
borrow: Cell<BorrowFlag>,
value: UnsafeCell<T>,
}

/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
Expand Down Expand Up @@ -328,7 +328,9 @@ impl<T> RefCell<T> {
debug_assert!(self.borrow.get() == UNUSED);
unsafe { self.value.into_inner() }
}
}

impl<T: ?Sized> RefCell<T> {
/// Query the current state of this `RefCell`
///
/// The returned value can be dispatched on to determine if a call to
Expand Down Expand Up @@ -449,7 +451,7 @@ impl<T> RefCell<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T> Send for RefCell<T> where T: Send {}
unsafe impl<T: ?Sized> Send for RefCell<T> where T: Send {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone> Clone for RefCell<T> {
Expand All @@ -469,7 +471,7 @@ impl<T:Default> Default for RefCell<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialEq> PartialEq for RefCell<T> {
impl<T: ?Sized + PartialEq> PartialEq for RefCell<T> {
#[inline]
fn eq(&self, other: &RefCell<T>) -> bool {
*self.borrow() == *other.borrow()
Expand Down Expand Up @@ -519,15 +521,15 @@ impl<'b> Clone for BorrowRef<'b> {
///
/// See the [module-level documentation](index.html) for more.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Ref<'b, T:'b> {
pub struct Ref<'b, T: ?Sized + 'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_value: &'b T,
_borrow: BorrowRef<'b>,
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, T> Deref for Ref<'b, T> {
impl<'b, T: ?Sized> Deref for Ref<'b, T> {
type Target = T;

#[inline]
Expand Down Expand Up @@ -582,15 +584,15 @@ impl<'b> BorrowRefMut<'b> {
///
/// See the [module-level documentation](index.html) for more.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RefMut<'b, T:'b> {
pub struct RefMut<'b, T: ?Sized + 'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_value: &'b mut T,
_borrow: BorrowRefMut<'b>,
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, T> Deref for RefMut<'b, T> {
impl<'b, T: ?Sized> Deref for RefMut<'b, T> {
type Target = T;

#[inline]
Expand All @@ -600,7 +602,7 @@ impl<'b, T> Deref for RefMut<'b, T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, T> DerefMut for RefMut<'b, T> {
impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> {
#[inline]
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
self._value
Expand Down Expand Up @@ -633,7 +635,7 @@ impl<'b, T> DerefMut for RefMut<'b, T> {
/// recommended to access its fields directly, `get` should be used instead.
#[lang="unsafe_cell"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct UnsafeCell<T> {
pub struct UnsafeCell<T: ?Sized> {
/// Wrapped value
///
/// This field should not be accessed directly, it is made public for static
Expand All @@ -642,7 +644,7 @@ pub struct UnsafeCell<T> {
pub value: T,
}

impl<T> !Sync for UnsafeCell<T> {}
impl<T: ?Sized> !Sync for UnsafeCell<T> {}

impl<T> UnsafeCell<T> {
/// Constructs a new instance of `UnsafeCell` which will wrap the specified
Expand All @@ -664,7 +666,12 @@ impl<T> UnsafeCell<T> {
UnsafeCell { value: value }
}

/// Gets a mutable pointer to the wrapped value.
/// Unwraps the value.
///
/// # Unsafety
///
/// This function is unsafe because there is no guarantee that this or other threads are
/// currently inspecting the inner value.
///
/// # Examples
///
Expand All @@ -673,22 +680,15 @@ impl<T> UnsafeCell<T> {
///
/// let uc = UnsafeCell::new(5);
///
/// let five = uc.get();
/// let five = unsafe { uc.into_inner() };
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get(&self) -> *mut T {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
&self.value as *const T as *mut T
}
pub unsafe fn into_inner(self) -> T { self.value }
}

/// Unwraps the value.
///
/// # Unsafety
///
/// This function is unsafe because there is no guarantee that this or other threads are
/// currently inspecting the inner value.
impl<T: ?Sized> UnsafeCell<T> {
/// Gets a mutable pointer to the wrapped value.
///
/// # Examples
///
Expand All @@ -697,9 +697,14 @@ impl<T> UnsafeCell<T> {
///
/// let uc = UnsafeCell::new(5);
///
/// let five = unsafe { uc.into_inner() };
/// let five = uc.get();
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn into_inner(self) -> T { self.value }
pub fn get(&self) -> *mut T {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
&self.value as *const T as *mut T
}

}
6 changes: 3 additions & 3 deletions src/libcore/fmt/mod.rs
Expand Up @@ -1062,7 +1062,7 @@ impl<T: Copy + Debug> Debug for Cell<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for RefCell<T> {
impl<T: ?Sized + Debug> Debug for RefCell<T> {
fn fmt(&self, f: &mut Formatter) -> Result {
match self.borrow_state() {
BorrowState::Unused | BorrowState::Reading => {
Expand All @@ -1074,14 +1074,14 @@ impl<T: Debug> Debug for RefCell<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, T: Debug> Debug for Ref<'b, T> {
impl<'b, T: ?Sized + Debug> Debug for Ref<'b, T> {
fn fmt(&self, f: &mut Formatter) -> Result {
Debug::fmt(&**self, f)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, T: Debug> Debug for RefMut<'b, T> {
impl<'b, T: ?Sized + Debug> Debug for RefMut<'b, T> {
fn fmt(&self, f: &mut Formatter) -> Result {
Debug::fmt(&*(self.deref()), f)
}
Expand Down
24 changes: 24 additions & 0 deletions src/libcoretest/cell.rs
Expand Up @@ -159,3 +159,27 @@ fn refcell_default() {
let cell: RefCell<u64> = Default::default();
assert_eq!(0, *cell.borrow());
}

#[test]
fn unsafe_cell_unsized() {
let cell: &UnsafeCell<[i32]> = &UnsafeCell::new([1, 2, 3]);
{
let val: &mut [i32] = unsafe { &mut *cell.get() };
val[0] = 4;
val[2] = 5;
}
let comp: &mut [i32] = &mut [4, 2, 5];
assert_eq!(unsafe { &mut *cell.get() }, comp);
}

#[test]
fn refcell_unsized() {
let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]);
{
let b = &mut *cell.borrow_mut();
b[0] = 4;
b[2] = 5;
}
let comp: &mut [i32] = &mut [4, 2, 5];
assert_eq!(&*cell.borrow(), comp);
}
44 changes: 29 additions & 15 deletions src/libstd/sync/mutex.rs
Expand Up @@ -112,7 +112,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
/// *guard += 1;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Mutex<T> {
pub struct Mutex<T: ?Sized> {
// Note that this static mutex is in a *box*, not inlined into the struct
// itself. Once a native mutex has been used once, its address can never
// change (it can't be moved). This mutex type can be safely moved at any
Expand All @@ -124,9 +124,9 @@ pub struct Mutex<T> {

// these are the only places where `T: Send` matters; all other
// functionality works fine on a single thread.
unsafe impl<T: Send> Send for Mutex<T> { }
unsafe impl<T: ?Sized + Send> Send for Mutex<T> { }

unsafe impl<T: Send> Sync for Mutex<T> { }
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }

/// The static mutex type is provided to allow for static allocation of mutexes.
///
Expand Down Expand Up @@ -164,15 +164,15 @@ pub struct StaticMutex {
/// `Deref` and `DerefMut` implementations
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct MutexGuard<'a, T: 'a> {
pub struct MutexGuard<'a, T: ?Sized + 'a> {
// funny underscores due to how Deref/DerefMut currently work (they
// disregard field privacy).
__lock: &'a StaticMutex,
__data: &'a UnsafeCell<T>,
__poison: poison::Guard,
}

impl<'a, T> !marker::Send for MutexGuard<'a, T> {}
impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {}

/// Static initialization of a mutex. This constant can be used to initialize
/// other mutex constants.
Expand All @@ -192,7 +192,9 @@ impl<T> Mutex<T> {
data: UnsafeCell::new(t),
}
}
}

impl<T: ?Sized> Mutex<T> {
/// Acquires a mutex, blocking the current task until it is able to do so.
///
/// This function will block the local task until it is available to acquire
Expand Down Expand Up @@ -245,7 +247,7 @@ impl<T> Mutex<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Mutex<T> {
impl<T: ?Sized> Drop for Mutex<T> {
fn drop(&mut self) {
// This is actually safe b/c we know that there is no further usage of
// this mutex (it's up to the user to arrange for a mutex to get
Expand All @@ -255,12 +257,12 @@ impl<T> Drop for Mutex<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug + 'static> fmt::Debug for Mutex<T> {
impl<T: ?Sized + fmt::Debug + 'static> fmt::Debug for Mutex<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_lock() {
Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", *guard),
Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard),
Err(TryLockError::Poisoned(err)) => {
write!(f, "Mutex {{ data: Poisoned({:?}) }}", **err.get_ref())
write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
},
Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ <locked> }}")
}
Expand Down Expand Up @@ -310,7 +312,7 @@ impl StaticMutex {
}
}

impl<'mutex, T> MutexGuard<'mutex, T> {
impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {

fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
-> LockResult<MutexGuard<'mutex, T>> {
Expand All @@ -325,22 +327,22 @@ impl<'mutex, T> MutexGuard<'mutex, T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'mutex, T> Deref for MutexGuard<'mutex, T> {
impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> {
type Target = T;

fn deref<'a>(&'a self) -> &'a T {
unsafe { &*self.__data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'mutex, T> DerefMut for MutexGuard<'mutex, T> {
impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> {
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
unsafe { &mut *self.__data.get() }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for MutexGuard<'a, T> {
impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
#[inline]
fn drop(&mut self) {
unsafe {
Expand All @@ -350,11 +352,11 @@ impl<'a, T> Drop for MutexGuard<'a, T> {
}
}

pub fn guard_lock<'a, T>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
&guard.__lock.lock
}

pub fn guard_poison<'a, T>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
&guard.__lock.poison
}

Expand Down Expand Up @@ -528,4 +530,16 @@ mod tests {
let lock = arc.lock().unwrap();
assert_eq!(*lock, 2);
}

#[test]
fn test_mutex_unsized() {
let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
{
let b = &mut *mutex.lock().unwrap();
b[0] = 4;
b[2] = 5;
}
let comp: &[i32] = &[4, 2, 5];
assert_eq!(&*mutex.lock().unwrap(), comp);
}
}

0 comments on commit 57d8289

Please sign in to comment.