diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-11-01 14:54:24 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-01 14:54:24 -0500 |
commit | 070dee354204711eb085159fb9f234e080d181f4 (patch) | |
tree | 5624f521d863fb33eddb122d39823d56b3de1ab8 | |
parent | cf9d282914c65d712635b14636a62003b863bdf0 (diff) | |
parent | d252c8e42af8df5a4d9e605a4730deb2f347e0fb (diff) | |
download | servo-070dee354204711eb085159fb9f234e080d181f4.tar.gz servo-070dee354204711eb085159fb9f234e080d181f4.zip |
Auto merge of #13797 - bholley:atomic_refcell_map, r=SimonSapin
Implement AtomicRef{,Mut}::map
I was originally bundling this with #13777 but am splitting it out since that's been deprioritized.
r? @SimonSapin
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13797)
<!-- Reviewable:end -->
-rw-r--r-- | components/style/atomic_refcell.rs | 75 | ||||
-rw-r--r-- | tests/unit/style/atomic_refcell.rs | 41 | ||||
-rw-r--r-- | tests/unit/style/lib.rs | 1 |
3 files changed, 113 insertions, 4 deletions
diff --git a/components/style/atomic_refcell.rs b/components/style/atomic_refcell.rs index 409d669b595..9fb8c99a375 100644 --- a/components/style/atomic_refcell.rs +++ b/components/style/atomic_refcell.rs @@ -2,7 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![allow(unsafe_code)] + +use owning_ref::{OwningRef, StableAddress}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::ops::{Deref, DerefMut}; /// Container type providing RefCell-like semantics for objects shared across /// threads. @@ -20,17 +24,41 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; /// RefCell, so we newtype it with some API sugar. pub struct AtomicRefCell<T>(RwLock<T>); -pub type AtomicRef<'a, T> = RwLockReadGuard<'a, T>; -pub type AtomicRefMut<'a, T> = RwLockWriteGuard<'a, T>; +pub struct AtomicRef<'a, T: 'a>(RwLockReadGuard<'a, T>); +unsafe impl<'a, T> StableAddress for AtomicRef<'a, T> {} + +impl<'a, T> Deref for AtomicRef<'a, T> { + type Target = T; + fn deref(&self) -> &T { + self.0.deref() + } +} + +pub struct AtomicRefMut<'a, T: 'a>(RwLockWriteGuard<'a, T>); +unsafe impl<'a, T> StableAddress for AtomicRefMut<'a, T> {} + +impl<'a, T> Deref for AtomicRefMut<'a, T> { + type Target = T; + fn deref(&self) -> &T { + self.0.deref() + } +} + +impl<'a, T> DerefMut for AtomicRefMut<'a, T> { + fn deref_mut(&mut self) -> &mut T { + self.0.deref_mut() + } +} + impl<T> AtomicRefCell<T> { pub fn new(value: T) -> Self { AtomicRefCell(RwLock::new(value)) } pub fn borrow(&self) -> AtomicRef<T> { - self.0.try_read().expect("already mutably borrowed") + AtomicRef(self.0.try_read().expect("already mutably borrowed")) } pub fn borrow_mut(&self) -> AtomicRefMut<T> { - self.0.try_write().expect("already borrowed") + AtomicRefMut(self.0.try_write().expect("already borrowed")) } } @@ -39,3 +67,42 @@ impl<T: Default> Default for AtomicRefCell<T> { Self::new(T::default()) } } + +/* + * Implement Ref{,Mut}::map()-like semantics for AtomicRef{,Mut}. We can't quite + * use AtomicRef{,Mut} as the mapped type, but we can use some trait tricks to + * allow us to pass MappedAtomicRef{,Mut} back into AtomicRef{,Mut}::map(). + * + * Note: We cannot implement an AtomicRefMut::map() method until we have mutable + * OwningRef. See https://github.com/Kimundi/owning-ref-rs/pull/16 + */ +pub type MappedAtomicRef<'a, T: 'a, U: 'a> = OwningRef<AtomicRef<'a, T>, U>; + +pub trait Map<'a, Base, Curr> { + fn map<New, F>(self, f: F) -> MappedAtomicRef<'a, Base, New> + where F: FnOnce(&Curr) -> &New; +} + +impl<'a, Base> Map<'a, Base, Base> for AtomicRef<'a, Base> { + fn map<New, F>(self, f: F) -> MappedAtomicRef<'a, Base, New> + where F: FnOnce(&Base) -> &New + { + OwningRef::new(self).map(f) + } +} + +impl<'a, Base, Curr> Map<'a, Base, Curr> for MappedAtomicRef<'a, Base, Curr> { + fn map<New, F>(self, f: F) -> MappedAtomicRef<'a, Base, New> + where F: FnOnce(&Curr) -> &New + { + self.map(f) + } +} + +impl<'a, Base> AtomicRef<'a, Base> { + pub fn map<Curr, New, M, F>(orig: M, f: F) -> MappedAtomicRef<'a, Base, New> + where F: FnOnce(&Curr) -> &New, M: Map<'a, Base, Curr> + { + orig.map(f) + } +} diff --git a/tests/unit/style/atomic_refcell.rs b/tests/unit/style/atomic_refcell.rs new file mode 100644 index 00000000000..4aba6bf6c00 --- /dev/null +++ b/tests/unit/style/atomic_refcell.rs @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use style::atomic_refcell::{AtomicRef, AtomicRefCell}; + +struct Foo { + u: u32, +} + +struct Bar { + f: Foo, +} + +#[test] +fn map() { + let a = AtomicRefCell::new(Bar { f: Foo { u: 42 } }); + let b = a.borrow(); + assert_eq!(b.f.u, 42); + let c = AtomicRef::map(b, |x| &x.f); + assert_eq!(c.u, 42); + let d = AtomicRef::map(c, |x| &x.u); + assert_eq!(*d, 42); +} + +/* FIXME(bholley): Enable once we have AtomicRefMut::map(), which is blocked on + * https://github.com/Kimundi/owning-ref-rs/pull/16 +#[test] +fn map_mut() { + let a = AtomicRefCell::new(Bar { f: Foo { u: 42 } }); + let mut b = a.borrow_mut(); + assert_eq!(b.f.u, 42); + b.f.u = 43; + let mut c = AtomicRefMut::map(b, |x| &x.f); + assert_eq!(c.u, 43); + c.u = 44; + let mut d = AtomicRefMut::map(c, |x| &x.u); + assert_eq!(*d, 44); + *d. = 45; + assert_eq!(*d, 45); +}*/ diff --git a/tests/unit/style/lib.rs b/tests/unit/style/lib.rs index 240cac4eb79..1e3e7ac2313 100644 --- a/tests/unit/style/lib.rs +++ b/tests/unit/style/lib.rs @@ -19,6 +19,7 @@ extern crate style_traits; extern crate url; extern crate util; +mod atomic_refcell; mod attr; mod cache; mod logical_geometry; |