Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add map function to Ref and MutRef of RefCell #19220

Closed
wants to merge 2 commits into from
Closed
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
17 changes: 9 additions & 8 deletions src/libarena/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl Chunk {
}

unsafe fn as_ptr(&self) -> *const u8 {
self.data.borrow().as_ptr()
(*self.data.borrow()).as_ptr()
}
}

Expand Down Expand Up @@ -120,8 +120,9 @@ fn chunk(size: uint, is_copy: bool) -> Chunk {
impl Drop for Arena {
fn drop(&mut self) {
unsafe {
destroy_chunk(&*self.head.borrow());
for chunk in self.chunks.borrow().iter() {
destroy_chunk(&**self.head.borrow());
let chunks = self.chunks.borrow();
for chunk in chunks.iter() {
if !chunk.is_copy.get() {
destroy_chunk(chunk);
}
Expand Down Expand Up @@ -186,7 +187,7 @@ impl Arena {
let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
self.chunks.borrow_mut().push(self.copy_head.borrow().clone());

*self.copy_head.borrow_mut() =
**self.copy_head.borrow_mut() =
chunk((new_min_chunk_size + 1u).next_power_of_two(), true);

return self.alloc_copy_inner(n_bytes, align);
Expand Down Expand Up @@ -227,7 +228,7 @@ impl Arena {
let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
self.chunks.borrow_mut().push(self.head.borrow().clone());

*self.head.borrow_mut() =
**self.head.borrow_mut() =
chunk((new_min_chunk_size + 1u).next_power_of_two(), false);

return self.alloc_noncopy_inner(n_bytes, align);
Expand Down Expand Up @@ -480,12 +481,12 @@ impl<T> TypedArena<T> {
#[inline(never)]
fn grow(&self) {
unsafe {
let chunk = *self.first.borrow_mut();
let chunk = **self.first.borrow_mut();
let new_capacity = (*chunk).capacity.checked_mul(2).unwrap();
let chunk = TypedArenaChunk::<T>::new(chunk, new_capacity);
self.ptr.set((*chunk).start() as *const T);
self.end.set((*chunk).end() as *const T);
*self.first.borrow_mut() = chunk
**self.first.borrow_mut() = chunk
}
}
}
Expand All @@ -500,7 +501,7 @@ impl<T> Drop for TypedArena<T> {
let diff = (end - start) / mem::size_of::<T>();

// Pass that to the `destroy` method.
(**self.first.borrow_mut()).destroy(diff)
(***self.first.borrow_mut()).destroy(diff)
}
}
}
Expand Down
165 changes: 118 additions & 47 deletions src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,10 @@ impl<T> RefCell<T> {
///
/// Returns `None` if the value is currently mutably borrowed.
#[unstable = "may be renamed, depending on global conventions"]
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
match self.borrow.get() {
WRITING => None,
borrow => {
self.borrow.set(borrow + 1);
Some(Ref { _parent: self })
}
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, &'a T>> {
match BorrowRef::new(&self.borrow) {
Some(b) => Some(Ref { _value: unsafe { &*self.value.get() }, _borrow: b }),
None => None,
}
}

Expand All @@ -288,7 +285,7 @@ impl<T> RefCell<T> {
///
/// Panics if the value is currently mutably borrowed.
#[unstable]
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
pub fn borrow<'a>(&'a self) -> Ref<'a, &'a T> {
match self.try_borrow() {
Some(ptr) => ptr,
None => panic!("RefCell<T> already mutably borrowed")
Expand All @@ -302,13 +299,10 @@ impl<T> RefCell<T> {
///
/// Returns `None` if the value is currently borrowed.
#[unstable = "may be renamed, depending on global conventions"]
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
match self.borrow.get() {
UNUSED => {
self.borrow.set(WRITING);
Some(RefMut { _parent: self })
},
_ => None
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, &'a mut T>> {
match BorrowRefMut::new(&self.borrow) {
Some(b) => Some(RefMut { _value: unsafe { &mut *self.value.get() }, _borrow: b }),
None => None,
}
}

Expand All @@ -321,13 +315,19 @@ impl<T> RefCell<T> {
///
/// Panics if the value is currently borrowed.
#[unstable]
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, &'a mut T> {
match self.try_borrow_mut() {
Some(ptr) => ptr,
None => panic!("RefCell<T> already borrowed")
}
}

/// Mutably borrows the wrapped value, with static borrow checking.
#[unstable]
pub fn static_borrow_mut<'a>(&'a mut self) -> &'a mut T {
unsafe { &mut *self.value.get() }
}

/// Get a reference to the underlying `UnsafeCell`.
///
/// This can be used to circumvent `RefCell`'s safety checks.
Expand Down Expand Up @@ -361,29 +361,75 @@ impl<T: PartialEq> PartialEq for RefCell<T> {
}
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
#[unstable]
pub struct Ref<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_parent: &'b RefCell<T>
struct BorrowRef<'b> {
_borrow: &'b Cell<BorrowFlag>,
}

impl<'b> BorrowRef<'b> {
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
match borrow.get() {
WRITING => None,
b => {
borrow.set(b + 1);
Some(BorrowRef { _borrow: borrow })
},
}
}
}

#[unsafe_destructor]
#[unstable]
impl<'b, T> Drop for Ref<'b, T> {
impl<'b> Drop for BorrowRef<'b> {
fn drop(&mut self) {
let borrow = self._parent.borrow.get();
let borrow = self._borrow.get();
debug_assert!(borrow != WRITING && borrow != UNUSED);
self._borrow.set(borrow - 1);
}
}

impl<'b> Clone for BorrowRef<'b> {
fn clone(&self) -> BorrowRef<'b> {
// Since this Ref exists, we know the borrow flag
// is not set to WRITING.
let borrow = self._borrow.get();
debug_assert!(borrow != WRITING && borrow != UNUSED);
self._parent.borrow.set(borrow - 1);
self._borrow.set(borrow + 1);
BorrowRef { _borrow: self._borrow }
}
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
#[unstable]
pub struct Ref<'b, T: 'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_value: T,
_borrow: BorrowRef<'b>,
}

#[unstable = "waiting for `Deref` to become stable"]
impl<'b, T> Deref<T> for Ref<'b, T> {
#[inline]
fn deref<'a>(&'a self) -> &'a T {
unsafe { &*self._parent.value.get() }
&self._value
}
}

impl<'b, T:'b> Ref<'b, T> {
/// Modifies the reference so that it points to other data in the same
/// `RefCell`.
pub fn map<U:'b>(self, map_fn: |T| -> U) -> Ref<'b, U> {
let Ref { _value: value, _borrow: borrow } = self;
Ref {
// The user provided function may panic, however everything is in a
// consistent state if it actually does:
//
// The value is moved into the function so the function takes care
// of deleting it in that case. The borrow flag is dropped
// afterwards, in the stack frame of this function, after the inner
// value has been dropped.
_value: map_fn(value),
_borrow: borrow,
}
}
}

Expand All @@ -394,49 +440,74 @@ impl<'b, T> Deref<T> for Ref<'b, T> {
/// A `Clone` implementation would interfere with the widespread
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
#[experimental = "likely to be moved to a method, pending language changes"]
pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
// Since this Ref exists, we know the borrow flag
// is not set to WRITING.
let borrow = orig._parent.borrow.get();
debug_assert!(borrow != WRITING && borrow != UNUSED);
orig._parent.borrow.set(borrow + 1);

pub fn clone_ref<'b, T:Clone>(orig: &Ref<'b, T>) -> Ref<'b, T> {
Ref {
_parent: orig._parent,
_value: orig._value.clone(),
_borrow: orig._borrow.clone(),
}
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
#[unstable]
pub struct RefMut<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_parent: &'b RefCell<T>
struct BorrowRefMut<'b> {
_borrow: &'b Cell<BorrowFlag>,
}

#[unsafe_destructor]
#[unstable]
impl<'b, T> Drop for RefMut<'b, T> {
impl<'b> Drop for BorrowRefMut<'b> {
fn drop(&mut self) {
let borrow = self._parent.borrow.get();
let borrow = self._borrow.get();
debug_assert!(borrow == WRITING);
self._parent.borrow.set(UNUSED);
self._borrow.set(UNUSED);
}
}

impl<'b> BorrowRefMut<'b> {
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
match borrow.get() {
UNUSED => {
borrow.set(WRITING);
Some(BorrowRefMut { _borrow: borrow })
},
_ => None,
}
}
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
#[unstable]
pub struct RefMut<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_value: T,
_borrow: BorrowRefMut<'b>,
}

#[unstable = "waiting for `Deref` to become stable"]
impl<'b, T> Deref<T> for RefMut<'b, T> {
#[inline]
fn deref<'a>(&'a self) -> &'a T {
unsafe { &*self._parent.value.get() }
&self._value
}
}

#[unstable = "waiting for `DerefMut` to become stable"]
impl<'b, T> DerefMut<T> for RefMut<'b, T> {
#[inline]
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
unsafe { &mut *self._parent.value.get() }
&mut self._value
}
}

impl<'b, T:'b> RefMut<'b, T> {
/// Modifies the reference so that it points to other data in the same
/// `RefCell`.
pub fn map<U:'b>(self, map_fn: |T| -> U) -> RefMut<'b, U> {
let RefMut { _value: value, _borrow: borrow } = self;
RefMut {
// For the reasoning why the following is safe even when `map_fn`
// panics, see the `Ref::map` function.
_value: map_fn(value),
_borrow: borrow,
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ impl<'a, 'tcx> Context<'a, 'tcx> {
krate: &'a ast::Crate,
exported_items: &'a ExportedItems) -> Context<'a, 'tcx> {
// We want to own the lint store, so move it out of the session.
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
let lint_store = mem::replace(&mut **tcx.sess.lint_store.borrow_mut(),
LintStore::new());

Context {
Expand Down Expand Up @@ -827,5 +827,5 @@ pub fn check_crate(tcx: &ty::ctxt,
}

tcx.sess.abort_if_errors();
*tcx.node_lint_levels.borrow_mut() = cx.node_levels.unwrap();
**tcx.node_lint_levels.borrow_mut() = cx.node_levels.unwrap();
}
8 changes: 4 additions & 4 deletions src/librustc/metadata/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,14 @@ impl CStore {

pub fn add_used_crate_source(&self, src: CrateSource) {
let mut used_crate_sources = self.used_crate_sources.borrow_mut();
if !used_crate_sources.contains(&src) {
used_crate_sources.push(src);
if !(*used_crate_sources).contains(&src) {
(*used_crate_sources).push(src);
}
}

pub fn get_used_crate_source(&self, cnum: ast::CrateNum)
-> Option<CrateSource> {
self.used_crate_sources.borrow_mut()
(*self.used_crate_sources.borrow_mut())
.iter().find(|source| source.cnum == cnum)
.map(|source| source.clone())
}
Expand Down Expand Up @@ -174,7 +174,7 @@ impl CStore {
}
ordering.as_mut_slice().reverse();
let ordering = ordering.as_slice();
let mut libs = self.used_crate_sources.borrow()
let mut libs = (*self.used_crate_sources.borrow())
.iter()
.map(|src| (src.cnum, match prefer {
RequireDynamic => src.dylib.clone(),
Expand Down
10 changes: 4 additions & 6 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -961,9 +961,7 @@ fn encode_repr_attrs(rbml_w: &mut Encoder,
fn encode_inlined_item(ecx: &EncodeContext,
rbml_w: &mut Encoder,
ii: InlinedItemRef) {
let mut eii = ecx.encode_inlined_item.borrow_mut();
let eii: &mut EncodeInlinedItem = &mut *eii;
(*eii)(ecx, rbml_w, ii)
(*&mut **ecx.encode_inlined_item.borrow_mut())(ecx, rbml_w, ii)
}

const FN_FAMILY: char = 'f';
Expand Down Expand Up @@ -1001,7 +999,7 @@ fn encode_extension_implementations(ecx: &EncodeContext,
match ecx.tcx.trait_impls.borrow().get(&trait_def_id) {
None => {}
Some(implementations) => {
for &impl_def_id in implementations.borrow().iter() {
for &impl_def_id in (*implementations.borrow()).iter() {
rbml_w.start_tag(tag_items_data_item_extension_impl);
encode_def_id(rbml_w, impl_def_id);
rbml_w.end_tag();
Expand Down Expand Up @@ -1759,8 +1757,8 @@ fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) {
fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) {
rbml_w.start_tag(tag_native_libraries);

for &(ref lib, kind) in ecx.tcx.sess.cstore.get_used_libraries()
.borrow().iter() {
for &(ref lib, kind) in (*ecx.tcx.sess.cstore.get_used_libraries()
.borrow()).iter() {
match kind {
cstore::NativeStatic => {} // these libraries are not propagated
cstore::NativeFramework | cstore::NativeUnknown => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/metadata/filesearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl<'a> FileSearch<'a> {

debug!("filesearch: searching additional lib search paths [{}]",
self.addl_lib_search_paths.borrow().len());
for path in self.addl_lib_search_paths.borrow().iter() {
for path in (*self.addl_lib_search_paths.borrow()).iter() {
match f(path) {
FileMatches => found = true,
FileDoesntMatch => ()
Expand Down
Loading