aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-11-01 14:54:24 -0500
committerGitHub <noreply@github.com>2016-11-01 14:54:24 -0500
commit070dee354204711eb085159fb9f234e080d181f4 (patch)
tree5624f521d863fb33eddb122d39823d56b3de1ab8
parentcf9d282914c65d712635b14636a62003b863bdf0 (diff)
parentd252c8e42af8df5a4d9e605a4730deb2f347e0fb (diff)
downloadservo-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.rs75
-rw-r--r--tests/unit/style/atomic_refcell.rs41
-rw-r--r--tests/unit/style/lib.rs1
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;