auto merge of #10514 : sfackler/rust/mut, r=cmr

This is based off of @blake2-ppc's work on #9429. That PR bitrotted and I haven't been able to contact the original author so I decided to take up the cause.

Overview
======
`Mut` encapsulates a mutable, non-nullable slot. The `Cell` type is currently used to do this, but `Cell` is much more commonly used as a workaround for the inability to move values into non-once functions. `Mut` provides a more robust API.

`Mut` duplicates the semantics of borrowed pointers with enforcement at runtime instead of compile time.
```rust
let x = Mut::new(0);

{
    // make some immutable borrows
    let p = x.borrow();
    let y = *p.get() + 10;

    // multiple immutable borrows are allowed simultaneously
    let p2 = x.borrow();

    // this would throw a runtime failure
    // let p_mut = x.borrow_mut();
}

// now we can mutably borrow
let p = x.borrow_mut();
*p.get() = 10;
```
`borrow` returns a `Ref` type and `borrow_mut` returns a `RefMut` type, both of which are simple smart pointer types with a single method, `get`, which returns a reference to the wrapped data.

This also allows `RcMut<T>` to be deleted, as it can be replaced with `Rc<Mut<T>>`.

Changes
======
I've done things a little bit differently than the original proposal.

* I've added `try_borrow` and `try_borrow_mut` methods that return `Option<Ref<T>>` and `Option<RefMut<T>>` respectively instead of failing on a borrow check failure. I'm not totally sure when that'd be useful, but I don't see any reason to not put them in and @cmr requested them.
* `ReadPtr` and `WritePtr` have been renamed to `Ref` and `RefMut` respectively, as `Ref` is to `ref foo` and `RefMut` is to `ref mut foo` as `Mut` is to `mut foo`.
* `get` on `MutRef` now takes `&self` instead of `&mut self` for consistency with `&mut`. As @alexcrichton pointed, out this violates soundness by allowing aliasing `&mut` references.
* `Cell` is being left as is. It solves a different problem than `Mut` is designed to solve.
* There are no longer methods implemented for `Mut<Option<T>>`. Since `Cell` isn't going away, there's less of a need for these, and I didn't feel like they provided a huge benefit, especially as that kind of `impl` is very uncommon in the standard library.

Open Questions
============
* `Cell` should now be used exclusively for movement into closures. Should this be enforced by reducing its API to `new` and `take`? It seems like this use case will be completely going away once the transition to `proc` and co. finishes.
* Should there be `try_map` and `try_map_mut` methods along with `map` and `map_mut`?
This commit is contained in:
bors 2013-11-23 20:01:42 -08:00
commit 33375a31e8
12 changed files with 437 additions and 360 deletions

View File

@ -24,7 +24,6 @@ use middle::graph::{Direction, NodeIndex};
use util::common::indenter;
use util::ppaux::{Repr};
use std::cell::Cell;
use std::hashmap::{HashMap, HashSet};
use std::uint;
use std::vec;
@ -106,16 +105,15 @@ pub struct RegionVarBindings {
undo_log: ~[UndoLogEntry],
// This contains the results of inference. It begins as an empty
// cell and only acquires a value after inference is complete.
// We use a cell vs a mutable option to circumvent borrowck errors.
values: Cell<~[VarValue]>,
// option and only acquires a value after inference is complete.
values: Option<~[VarValue]>,
}
pub fn RegionVarBindings(tcx: ty::ctxt) -> RegionVarBindings {
RegionVarBindings {
tcx: tcx,
var_origins: ~[],
values: Cell::new_empty(),
values: None,
constraints: HashMap::new(),
lubs: HashMap::new(),
glbs: HashMap::new(),
@ -226,7 +224,7 @@ impl RegionVarBindings {
constraint: Constraint,
origin: SubregionOrigin) {
// cannot add constraints once regions are resolved
assert!(self.values.is_empty());
assert!(self.values.is_none());
debug!("RegionVarBindings: add_constraint({:?})", constraint);
@ -242,7 +240,7 @@ impl RegionVarBindings {
sub: Region,
sup: Region) {
// cannot add constraints once regions are resolved
assert!(self.values.is_empty());
assert!(self.values.is_none());
debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup);
match (sub, sup) {
@ -277,7 +275,7 @@ impl RegionVarBindings {
b: Region)
-> Region {
// cannot add constraints once regions are resolved
assert!(self.values.is_empty());
assert!(self.values.is_none());
debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
match (a, b) {
@ -300,7 +298,7 @@ impl RegionVarBindings {
b: Region)
-> Region {
// cannot add constraints once regions are resolved
assert!(self.values.is_empty());
assert!(self.values.is_none());
debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
match (a, b) {
@ -319,14 +317,14 @@ impl RegionVarBindings {
}
pub fn resolve_var(&mut self, rid: RegionVid) -> ty::Region {
if self.values.is_empty() {
self.tcx.sess.span_bug(
let v = match self.values {
None => self.tcx.sess.span_bug(
self.var_origins[rid.to_uint()].span(),
format!("Attempt to resolve region variable before values have \
been computed!"));
}
been computed!")),
Some(ref values) => values[rid.to_uint()]
};
let v = self.values.with_ref(|values| values[rid.to_uint()]);
debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
rid, rid.to_uint(), v);
match v {
@ -482,7 +480,7 @@ impl RegionVarBindings {
debug!("RegionVarBindings: resolve_regions()");
let mut errors = opt_vec::Empty;
let v = self.infer_variable_values(&mut errors);
self.values.put_back(v);
self.values = Some(v);
errors
}
}

View File

@ -8,13 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A mutable, nullable memory location
//! Types dealing with dynamic mutability
#[missing_doc];
use cast::transmute_mut;
use unstable::finally::Finally;
use prelude::*;
use cast;
use util::NonCopyable;
/*
A dynamic, mutable location.
@ -35,14 +36,9 @@ impl<T> Cell<T> {
Cell { value: Some(value) }
}
/// Creates a new empty cell with no value inside.
pub fn new_empty() -> Cell<T> {
Cell { value: None }
}
/// Yields the value, failing if the cell is empty.
pub fn take(&self) -> T {
let this = unsafe { transmute_mut(self) };
let this = unsafe { cast::transmute_mut(self) };
if this.is_empty() {
fail!("attempt to take an empty cell");
}
@ -52,38 +48,14 @@ impl<T> Cell<T> {
/// Yields the value if the cell is full, or `None` if it is empty.
pub fn take_opt(&self) -> Option<T> {
let this = unsafe { transmute_mut(self) };
let this = unsafe { cast::transmute_mut(self) };
this.value.take()
}
/// Returns the value, failing if the cell is full.
pub fn put_back(&self, value: T) {
let this = unsafe { transmute_mut(self) };
if !this.is_empty() {
fail!("attempt to put a value back into a full cell");
}
this.value = Some(value);
}
/// Returns true if the cell is empty and false if the cell is full.
pub fn is_empty(&self) -> bool {
self.value.is_none()
}
/// Calls a closure with a reference to the value.
pub fn with_ref<R>(&self, op: |v: &T| -> R) -> R {
do self.with_mut_ref |ptr| { op(ptr) }
}
/// Calls a closure with a mutable reference to the value.
pub fn with_mut_ref<R>(&self, op: |v: &mut T| -> R) -> R {
let mut v = Some(self.take());
do (|| {
op(v.get_mut_ref())
}).finally {
self.put_back(v.take_unwrap());
}
}
}
#[test]
@ -93,38 +65,304 @@ fn test_basic() {
let value = value_cell.take();
assert!(value == ~10);
assert!(value_cell.is_empty());
value_cell.put_back(value);
assert!(!value_cell.is_empty());
}
#[test]
#[should_fail]
fn test_take_empty() {
let value_cell: Cell<~int> = Cell::new_empty();
let value_cell: Cell<~int> = Cell::new(~0);
value_cell.take();
value_cell.take();
}
#[test]
#[should_fail]
fn test_put_back_non_empty() {
let value_cell = Cell::new(~10);
value_cell.put_back(~20);
/// A mutable memory location with dynamically checked borrow rules
#[no_freeze]
pub struct RefCell<T> {
priv value: T,
priv borrow: BorrowFlag,
priv nc: NonCopyable
}
#[test]
fn test_with_ref() {
let good = 6;
let c = Cell::new(~[1, 2, 3, 4, 5, 6]);
let l = do c.with_ref() |v| { v.len() };
assert_eq!(l, good);
// Values [1, MAX-1] represent the number of `Ref` active
// (will not outgrow its range since `uint` is the size of the address space)
type BorrowFlag = uint;
static UNUSED: BorrowFlag = 0;
static WRITING: BorrowFlag = -1;
impl<T> RefCell<T> {
/// Create a new `RefCell` containing `value`
pub fn new(value: T) -> RefCell<T> {
RefCell {
value: value,
borrow: UNUSED,
nc: NonCopyable
}
}
/// Consumes the `RefCell`, returning the wrapped value.
pub fn unwrap(self) -> T {
assert!(self.borrow == UNUSED);
self.value
}
unsafe fn as_mut<'a>(&'a self) -> &'a mut RefCell<T> {
cast::transmute_mut(self)
}
/// Attempts to immutably borrow the wrapped value.
///
/// The borrow lasts until the returned `Ref` exits scope. Multiple
/// immutable borrows can be taken out at the same time.
///
/// Returns `None` if the value is currently mutably borrowed.
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
match self.borrow {
WRITING => None,
_ => {
unsafe { self.as_mut().borrow += 1; }
Some(Ref { parent: self })
}
}
}
/// Immutably borrows the wrapped value.
///
/// The borrow lasts until the returned `Ref` exits scope. Multiple
/// immutable borrows can be taken out at the same time.
///
/// # Failure
///
/// Fails if the value is currently mutably borrowed.
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
match self.try_borrow() {
Some(ptr) => ptr,
None => fail!("RefCell<T> already mutably borrowed")
}
}
/// Mutably borrows the wrapped value.
///
/// The borrow lasts untile the returned `RefMut` exits scope. The value
/// cannot be borrowed while this borrow is active.
///
/// Returns `None` if the value is currently borrowed.
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
match self.borrow {
UNUSED => unsafe {
let mut_self = self.as_mut();
mut_self.borrow = WRITING;
Some(RefMut { parent: mut_self })
},
_ => None
}
}
/// Mutably borrows the wrapped value.
///
/// The borrow lasts untile the returned `RefMut` exits scope. The value
/// cannot be borrowed while this borrow is active.
///
/// # Failure
///
/// Fails if the value is currently borrowed.
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
match self.try_borrow_mut() {
Some(ptr) => ptr,
None => fail!("RefCell<T> already borrowed")
}
}
/// Immutably borrows the wrapped value and applies `blk` to it.
///
/// # Failure
///
/// Fails if the value is currently mutably borrowed.
#[inline]
pub fn with<U>(&self, blk: |&T| -> U) -> U {
let ptr = self.borrow();
blk(ptr.get())
}
/// Mutably borrows the wrapped value and applies `blk` to it.
///
/// # Failure
///
/// Fails if the value is currently borrowed.
#[inline]
pub fn with_mut<U>(&self, blk: |&mut T| -> U) -> U {
let mut ptr = self.borrow_mut();
blk(ptr.get())
}
}
#[test]
fn test_with_mut_ref() {
let good = ~[1, 2, 3];
let v = ~[1, 2];
let c = Cell::new(v);
do c.with_mut_ref() |v| { v.push(3); }
let v = c.take();
assert_eq!(v, good);
impl<T: Clone> Clone for RefCell<T> {
fn clone(&self) -> RefCell<T> {
let x = self.borrow();
RefCell::new(x.get().clone())
}
}
impl<T: DeepClone> DeepClone for RefCell<T> {
fn deep_clone(&self) -> RefCell<T> {
let x = self.borrow();
RefCell::new(x.get().deep_clone())
}
}
impl<T: Eq> Eq for RefCell<T> {
fn eq(&self, other: &RefCell<T>) -> bool {
let a = self.borrow();
let b = other.borrow();
a.get() == b.get()
}
}
/// Wraps a borrowed reference to a value in a `RefCell` box.
pub struct Ref<'box, T> {
priv parent: &'box RefCell<T>
}
#[unsafe_destructor]
impl<'box, T> Drop for Ref<'box, T> {
fn drop(&mut self) {
assert!(self.parent.borrow != WRITING && self.parent.borrow != UNUSED);
unsafe { self.parent.as_mut().borrow -= 1; }
}
}
impl<'box, T> Ref<'box, T> {
/// Retrieve an immutable reference to the stored value.
#[inline]
pub fn get<'a>(&'a self) -> &'a T {
&self.parent.value
}
}
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'box, T> {
priv parent: &'box mut RefCell<T>
}
#[unsafe_destructor]
impl<'box, T> Drop for RefMut<'box, T> {
fn drop(&mut self) {
assert!(self.parent.borrow == WRITING);
self.parent.borrow = UNUSED;
}
}
impl<'box, T> RefMut<'box, T> {
/// Retrieve a mutable reference to the stored value.
#[inline]
pub fn get<'a>(&'a mut self) -> &'a mut T {
&mut self.parent.value
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn double_imm_borrow() {
let x = RefCell::new(0);
let _b1 = x.borrow();
x.borrow();
}
#[test]
fn no_mut_then_imm_borrow() {
let x = RefCell::new(0);
let _b1 = x.borrow_mut();
assert!(x.try_borrow().is_none());
}
#[test]
fn no_imm_then_borrow_mut() {
let x = RefCell::new(0);
let _b1 = x.borrow();
assert!(x.try_borrow_mut().is_none());
}
#[test]
fn no_double_borrow_mut() {
let x = RefCell::new(0);
let _b1 = x.borrow_mut();
assert!(x.try_borrow_mut().is_none());
}
#[test]
fn imm_release_borrow_mut() {
let x = RefCell::new(0);
{
let _b1 = x.borrow();
}
x.borrow_mut();
}
#[test]
fn mut_release_borrow_mut() {
let x = RefCell::new(0);
{
let _b1 = x.borrow_mut();
}
x.borrow();
}
#[test]
fn double_borrow_single_release_no_borrow_mut() {
let x = RefCell::new(0);
let _b1 = x.borrow();
{
let _b2 = x.borrow();
}
assert!(x.try_borrow_mut().is_none());
}
#[test]
fn with_ok() {
let x = RefCell::new(0);
assert_eq!(1, x.with(|x| *x+1));
}
#[test]
#[should_fail]
fn mut_borrow_with() {
let x = RefCell::new(0);
let _b1 = x.borrow_mut();
x.with(|x| *x+1);
}
#[test]
fn borrow_with() {
let x = RefCell::new(0);
let _b1 = x.borrow();
assert_eq!(1, x.with(|x| *x+1));
}
#[test]
fn with_mut_ok() {
let x = RefCell::new(0);
x.with_mut(|x| *x += 1);
let b = x.borrow();
assert_eq!(1, *b.get());
}
#[test]
#[should_fail]
fn borrow_with_mut() {
let x = RefCell::new(0);
let _b = x.borrow();
x.with_mut(|x| *x += 1);
}
#[test]
#[should_fail]
fn discard_doesnt_unborrow() {
let x = RefCell::new(0);
let _b = x.borrow();
let _ = _b;
let _b = x.borrow_mut();
}
}

View File

@ -55,26 +55,26 @@ impl<T: DeepClone + Send + 'static> DeepClone for Gc<T> {
#[cfg(test)]
mod tests {
use super::*;
use cell::Cell;
use cell::RefCell;
#[test]
fn test_clone() {
let x = Gc::new(Cell::new(5));
let x = Gc::new(RefCell::new(5));
let y = x.clone();
do x.borrow().with_mut_ref |inner| {
do x.borrow().with_mut |inner| {
*inner = 20;
}
assert_eq!(y.borrow().take(), 20);
assert_eq!(y.borrow().with(|x| *x), 20);
}
#[test]
fn test_deep_clone() {
let x = Gc::new(Cell::new(5));
let x = Gc::new(RefCell::new(5));
let y = x.deep_clone();
do x.borrow().with_mut_ref |inner| {
do x.borrow().with_mut |inner| {
*inner = 20;
}
assert_eq!(y.borrow().take(), 5);
assert_eq!(y.borrow().with(|x| *x), 5);
}
#[test]

View File

@ -14,10 +14,6 @@ The `Rc` type provides shared ownership of an immutable value. Destruction is de
will occur as soon as the last owner is gone. It is marked as non-sendable because it avoids the
overhead of atomic reference counting.
The `RcMut` type provides shared ownership of a mutable value. Since multiple owners prevent
inherited mutability, a dynamic freezing check is used to maintain the invariant that an `&mut`
reference is a unique handle and the type is marked as non-`Freeze`.
*/
use ptr::RawPtr;
@ -25,6 +21,7 @@ use unstable::intrinsics::transmute;
use ops::Drop;
use kinds::{Freeze, Send};
use clone::{Clone, DeepClone};
use cell::RefCell;
struct RcBox<T> {
value: T,
@ -58,6 +55,16 @@ impl<T: Send> Rc<T> {
}
}
impl<T: Freeze> Rc<RefCell<T>> {
/// Construct a new reference-counted box from a `RefCell`-wrapped `Freeze` value
#[inline]
pub fn from_mut(value: RefCell<T>) -> Rc<RefCell<T>> {
unsafe {
Rc::new_unchecked(value)
}
}
}
impl<T> Rc<T> {
/// Unsafety construct a new reference-counted box from any value.
///
@ -109,26 +116,26 @@ impl<T> Drop for Rc<T> {
#[cfg(test)]
mod test_rc {
use super::*;
use cell::Cell;
use cell::RefCell;
#[test]
fn test_clone() {
let x = Rc::from_send(Cell::new(5));
let x = Rc::from_send(RefCell::new(5));
let y = x.clone();
do x.borrow().with_mut_ref |inner| {
do x.borrow().with_mut |inner| {
*inner = 20;
}
assert_eq!(y.borrow().take(), 20);
assert_eq!(y.borrow().with(|v| *v), 20);
}
#[test]
fn test_deep_clone() {
let x = Rc::from_send(Cell::new(5));
let x = Rc::from_send(RefCell::new(5));
let y = x.deep_clone();
do x.borrow().with_mut_ref |inner| {
do x.borrow().with_mut |inner| {
*inner = 20;
}
assert_eq!(y.borrow().take(), 5);
assert_eq!(y.borrow().with(|v| *v), 5);
}
#[test]
@ -150,237 +157,10 @@ mod test_rc {
let x = Rc::from_send(~5);
assert_eq!(**x.borrow(), 5);
}
}
#[deriving(Eq)]
enum Borrow {
Mutable,
Immutable,
Nothing
}
struct RcMutBox<T> {
value: T,
count: uint,
borrow: Borrow
}
/// Mutable reference counted pointer type
#[no_send]
#[no_freeze]
#[unsafe_no_drop_flag]
pub struct RcMut<T> {
priv ptr: *mut RcMutBox<T>,
}
impl<T: Freeze> RcMut<T> {
/// Construct a new mutable reference-counted box from a `Freeze` value
#[inline]
pub fn new(value: T) -> RcMut<T> {
unsafe { RcMut::new_unchecked(value) }
}
}
impl<T: Send> RcMut<T> {
/// Construct a new mutable reference-counted box from a `Send` value
#[inline]
pub fn from_send(value: T) -> RcMut<T> {
unsafe { RcMut::new_unchecked(value) }
}
}
impl<T> RcMut<T> {
/// Unsafety construct a new mutable reference-counted box from any value.
///
/// It is possible to create cycles, which will leak, and may interact
/// poorly with managed pointers.
#[inline]
pub unsafe fn new_unchecked(value: T) -> RcMut<T> {
RcMut{ptr: transmute(~RcMutBox{value: value, count: 1, borrow: Nothing})}
}
}
impl<T> RcMut<T> {
/// Fails if there is already a mutable borrow of the box
#[inline]
pub fn with_borrow<U>(&self, f: |&T| -> U) -> U {
unsafe {
assert!((*self.ptr).borrow != Mutable);
let previous = (*self.ptr).borrow;
(*self.ptr).borrow = Immutable;
let res = f(&(*self.ptr).value);
(*self.ptr).borrow = previous;
res
}
}
/// Fails if there is already a mutable or immutable borrow of the box
#[inline]
pub fn with_mut_borrow<U>(&self, f: |&mut T| -> U) -> U {
unsafe {
assert_eq!((*self.ptr).borrow, Nothing);
(*self.ptr).borrow = Mutable;
let res = f(&mut (*self.ptr).value);
(*self.ptr).borrow = Nothing;
res
}
}
}
#[unsafe_destructor]
impl<T> Drop for RcMut<T> {
fn drop(&mut self) {
unsafe {
if self.ptr.is_not_null() {
(*self.ptr).count -= 1;
if (*self.ptr).count == 0 {
let _: ~RcMutBox<T> = transmute(self.ptr);
}
}
}
}
}
impl<T> Clone for RcMut<T> {
/// Return a shallow copy of the reference counted pointer.
#[inline]
fn clone(&self) -> RcMut<T> {
unsafe {
(*self.ptr).count += 1;
RcMut{ptr: self.ptr}
}
}
}
impl<T: DeepClone> DeepClone for RcMut<T> {
/// Return a deep copy of the reference counted pointer.
#[inline]
fn deep_clone(&self) -> RcMut<T> {
do self.with_borrow |x| {
// FIXME: #6497: should avoid freeze (slow)
unsafe { RcMut::new_unchecked(x.deep_clone()) }
}
}
}
#[cfg(test)]
mod test_rc_mut {
use super::*;
#[test]
fn test_clone() {
let x = RcMut::from_send(5);
let y = x.clone();
do x.with_mut_borrow |value| {
*value = 20;
}
do y.with_borrow |value| {
assert_eq!(*value, 20);
}
}
#[test]
fn test_deep_clone() {
let x = RcMut::new(5);
let y = x.deep_clone();
do x.with_mut_borrow |value| {
*value = 20;
}
do y.with_borrow |value| {
assert_eq!(*value, 5);
}
}
#[test]
fn borrow_many() {
let x = RcMut::from_send(5);
let y = x.clone();
do x.with_borrow |a| {
assert_eq!(*a, 5);
do y.with_borrow |b| {
assert_eq!(*b, 5);
do x.with_borrow |c| {
assert_eq!(*c, 5);
}
}
}
}
#[test]
fn modify() {
let x = RcMut::new(5);
let y = x.clone();
do y.with_mut_borrow |a| {
assert_eq!(*a, 5);
*a = 6;
}
do x.with_borrow |a| {
assert_eq!(*a, 6);
}
}
#[test]
fn release_immutable() {
let x = RcMut::from_send(5);
do x.with_borrow |_| {}
do x.with_mut_borrow |_| {}
}
#[test]
fn release_mutable() {
let x = RcMut::new(5);
do x.with_mut_borrow |_| {}
do x.with_borrow |_| {}
}
#[test]
#[should_fail]
fn frozen() {
let x = RcMut::from_send(5);
let y = x.clone();
do x.with_borrow |_| {
do y.with_mut_borrow |_| {
}
}
}
#[test]
#[should_fail]
fn mutable_dupe() {
let x = RcMut::new(5);
let y = x.clone();
do x.with_mut_borrow |_| {
do y.with_mut_borrow |_| {
}
}
}
#[test]
#[should_fail]
fn mutable_freeze() {
let x = RcMut::from_send(5);
let y = x.clone();
do x.with_mut_borrow |_| {
do y.with_borrow |_| {
}
}
}
#[test]
#[should_fail]
fn restore_freeze() {
let x = RcMut::new(5);
let y = x.clone();
do x.with_borrow |_| {
do x.with_borrow |_| {}
do y.with_mut_borrow |_| {}
}
fn test_from_mut() {
let a = 10;
let _x = Rc::from_mut(RefCell::new(&a));
}
}

View File

@ -22,9 +22,10 @@ use rt::select::{SelectInner, SelectPortInner};
use select::{Select, SelectPort};
use unstable::atomics::{AtomicUint, AtomicOption, Acquire, Relaxed, SeqCst};
use unstable::sync::UnsafeArc;
use util;
use util::Void;
use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable, SendDeferred};
use cell::Cell;
use cell::{Cell, RefCell};
use clone::Clone;
use tuple::ImmutableTuple;
@ -431,28 +432,28 @@ type StreamPortOne<T> = PortOne<StreamPayload<T>>;
/// A channel with unbounded size.
pub struct Chan<T> {
// FIXME #5372. Using Cell because we don't take &mut self
next: Cell<StreamChanOne<T>>
// FIXME #5372. Using RefCell because we don't take &mut self
next: RefCell<StreamChanOne<T>>
}
/// An port with unbounded size.
pub struct Port<T> {
// FIXME #5372. Using Cell because we don't take &mut self
next: Cell<StreamPortOne<T>>
// FIXME #5372. Using RefCell because we don't take &mut self
next: RefCell<Option<StreamPortOne<T>>>
}
pub fn stream<T: Send>() -> (Port<T>, Chan<T>) {
let (pone, cone) = oneshot();
let port = Port { next: Cell::new(pone) };
let chan = Chan { next: Cell::new(cone) };
let port = Port { next: RefCell::new(Some(pone)) };
let chan = Chan { next: RefCell::new(cone) };
return (port, chan);
}
impl<T: Send> Chan<T> {
fn try_send_inner(&self, val: T, do_resched: bool) -> bool {
let (next_pone, next_cone) = oneshot();
let cone = self.next.take();
self.next.put_back(next_cone);
let (next_pone, mut cone) = oneshot();
let mut b = self.next.borrow_mut();
util::swap(&mut cone, b.get());
cone.try_send_inner(StreamPayload { val: val, next: next_pone }, do_resched)
}
}
@ -489,10 +490,11 @@ impl<T: Send> GenericPort<T> for Port<T> {
}
fn try_recv(&self) -> Option<T> {
do self.next.take_opt().map_default(None) |pone| {
let mut b = self.next.borrow_mut();
do b.get().take().map_default(None) |pone| {
match pone.try_recv() {
Some(StreamPayload { val, next }) => {
self.next.put_back(next);
*b.get() = Some(next);
Some(val)
}
None => None
@ -503,7 +505,7 @@ impl<T: Send> GenericPort<T> for Port<T> {
impl<T: Send> Peekable<T> for Port<T> {
fn peek(&self) -> bool {
self.next.with_mut_ref(|p| p.peek())
self.next.with_mut(|p| p.get_mut_ref().peek())
}
}
@ -514,18 +516,18 @@ impl<T: Send> Peekable<T> for Port<T> {
impl<'self, T: Send> SelectInner for &'self Port<T> {
#[inline]
fn optimistic_check(&mut self) -> bool {
do self.next.with_mut_ref |pone| { pone.optimistic_check() }
do self.next.with_mut |pone| { pone.get_mut_ref().optimistic_check() }
}
#[inline]
fn block_on(&mut self, sched: &mut Scheduler, task: BlockedTask) -> bool {
let task = Cell::new(task);
do self.next.with_mut_ref |pone| { pone.block_on(sched, task.take()) }
let mut b = self.next.borrow_mut();
b.get().get_mut_ref().block_on(sched, task)
}
#[inline]
fn unblock_from(&mut self) -> bool {
do self.next.with_mut_ref |pone| { pone.unblock_from() }
do self.next.with_mut |pone| { pone.get_mut_ref().unblock_from() }
}
}
@ -552,9 +554,10 @@ impl<T: Send> Select for Port<T> { }
impl<'self, T: Send> SelectPortInner<T> for &'self Port<T> {
fn recv_ready(self) -> Option<T> {
match self.next.take().recv_ready() {
let mut b = self.next.borrow_mut();
match b.get().take_unwrap().recv_ready() {
Some(StreamPayload { val, next }) => {
self.next.put_back(next);
*b.get() = Some(next);
Some(val)
}
None => None
@ -571,7 +574,7 @@ pub struct SharedChan<T> {
impl<T: Send> SharedChan<T> {
pub fn new(chan: Chan<T>) -> SharedChan<T> {
let next = chan.next.take();
let next = chan.next.unwrap();
let next = AtomicOption::new(~next);
SharedChan { next: UnsafeArc::new(next) }
}
@ -625,7 +628,7 @@ pub struct SharedPort<T> {
impl<T: Send> SharedPort<T> {
pub fn new(port: Port<T>) -> SharedPort<T> {
// Put the data port into a new link pipe
let next_data_port = port.next.take();
let next_data_port = port.next.unwrap().unwrap();
let (next_link_port, next_link_chan) = oneshot();
next_link_chan.send(next_data_port);
let next_link = AtomicOption::new(~next_link_port);

View File

@ -81,8 +81,7 @@ fn main() {
let num_tasks = from_str::<uint>(args[1]).unwrap();
let msg_per_task = from_str::<uint>(args[2]).unwrap();
let (num_chan, num_port) = init();
let num_chan = Cell::new(num_chan);
let (mut num_chan, num_port) = init();
let start = time::precise_time_s();
@ -92,7 +91,7 @@ fn main() {
for i in range(1u, num_tasks) {
//error!("spawning %?", i);
let (new_chan, num_port) = init();
let num_chan2 = Cell::new(num_chan.take());
let num_chan2 = Cell::new(num_chan);
let num_port = Cell::new(num_port);
let new_future = do Future::spawn() {
let num_chan = num_chan2.take();
@ -100,11 +99,11 @@ fn main() {
thread_ring(i, msg_per_task, num_chan, num_port1)
};
futures.push(new_future);
num_chan.put_back(new_chan);
num_chan = new_chan;
};
// do our iteration
thread_ring(0, msg_per_task, num_chan.take(), num_port);
thread_ring(0, msg_per_task, num_chan, num_port);
// synchronize
for f in futures.mut_iter() {

View File

@ -77,8 +77,7 @@ fn main() {
let num_tasks = from_str::<uint>(args[1]).unwrap();
let msg_per_task = from_str::<uint>(args[2]).unwrap();
let (num_chan, num_port) = init();
let num_chan = Cell::new(num_chan);
let (mut num_chan, num_port) = init();
let start = time::precise_time_s();
@ -88,7 +87,7 @@ fn main() {
for i in range(1u, num_tasks) {
//error!("spawning %?", i);
let (new_chan, num_port) = init();
let num_chan2 = Cell::new(num_chan.take());
let num_chan2 = Cell::new(num_chan);
let num_port = Cell::new(num_port);
let new_future = do Future::spawn {
let num_chan = num_chan2.take();
@ -96,11 +95,11 @@ fn main() {
thread_ring(i, msg_per_task, num_chan, num_port1)
};
futures.push(new_future);
num_chan.put_back(new_chan);
num_chan = new_chan;
};
// do our iteration
thread_ring(0, msg_per_task, num_chan.take(), num_port);
thread_ring(0, msg_per_task, num_chan, num_port);
// synchronize
for f in futures.mut_iter() {

View File

@ -8,21 +8,22 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::rc::RcMut;
use std::rc::Rc;
use std::cell::RefCell;
trait Foo
{
fn set(&mut self, v: RcMut<A>);
fn set(&mut self, v: Rc<RefCell<A>>);
}
struct B
{
v: Option<RcMut<A>>
v: Option<Rc<RefCell<A>>>
}
impl Foo for B
{
fn set(&mut self, v: RcMut<A>)
fn set(&mut self, v: Rc<RefCell<A>>)
{
self.v = Some(v);
}
@ -36,7 +37,9 @@ struct A
fn main()
{
let a = A {v: ~B{v: None} as ~Foo}; //~ ERROR cannot pack type `~B`, which does not fulfill `Send`
let v = RcMut::new(a); //~ ERROR instantiating a type parameter with an incompatible type
let v = Rc::from_send(RefCell::new(a));
let w = v.clone();
v.with_mut_borrow(|p| {p.v.set(w.clone());})
let b = v.borrow();
let mut b = b.borrow_mut();
b.get().v.set(w.clone());
}

View File

@ -0,0 +1,18 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cell::RefCell;
fn main() {
let m = RefCell::new(0);
let mut b = m.borrow_mut();
let b1 = b.get();
let b2 = b.get(); //~ ERROR cannot borrow `b` as mutable more than once at a time
}

View File

@ -0,0 +1,18 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cell::RefCell;
fn f<T: Freeze>(_: T) {}
fn main() {
let x = RefCell::new(0);
f(x); //~ ERROR: which does not fulfill `Freeze`
}

View File

@ -0,0 +1,20 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cell::RefCell;
fn main() {
let m = RefCell::new(0);
let p;
{
let b = m.borrow();
p = b.get(); //~ ERROR borrowed value does not live long enough
}
}

View File

@ -8,13 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::rc::RcMut;
use std::cell::RefCell;
use std::rc::Rc;
fn o<T: Send>(_: &T) {}
fn c<T: Freeze>(_: &T) {}
fn main() {
let x = RcMut::from_send(0);
o(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::RcMut<int>`, which does not fulfill `Send`
c(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::RcMut<int>`, which does not fulfill `Freeze`
let x = Rc::from_send(RefCell::new(0));
o(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::Rc<std::cell::RefCell<int>>`, which does not fulfill `Send`
c(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::Rc<std::cell::RefCell<int>>`, which does not fulfill `Freeze`
}