From d252c8e42af8df5a4d9e605a4730deb2f347e0fb Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 6 Oct 2016 23:23:18 -0700 Subject: [PATCH] Implement AtomicRef::map. MozReview-Commit-ID: 8iOALQylOuK --- components/style/atomic_refcell.rs | 75 ++++++++++++++++++++++++++++-- tests/unit/style/atomic_refcell.rs | 41 ++++++++++++++++ tests/unit/style/lib.rs | 1 + 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 tests/unit/style/atomic_refcell.rs diff --git a/components/style/atomic_refcell.rs b/components/style/atomic_refcell.rs index 409d669b5958..9fb8c99a3752 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(RwLock); -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 AtomicRefCell { pub fn new(value: T) -> Self { AtomicRefCell(RwLock::new(value)) } pub fn borrow(&self) -> AtomicRef { - self.0.try_read().expect("already mutably borrowed") + AtomicRef(self.0.try_read().expect("already mutably borrowed")) } pub fn borrow_mut(&self) -> AtomicRefMut { - self.0.try_write().expect("already borrowed") + AtomicRefMut(self.0.try_write().expect("already borrowed")) } } @@ -39,3 +67,42 @@ impl Default for AtomicRefCell { 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, U>; + +pub trait Map<'a, Base, Curr> { + fn map(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(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(self, f: F) -> MappedAtomicRef<'a, Base, New> + where F: FnOnce(&Curr) -> &New + { + self.map(f) + } +} + +impl<'a, Base> AtomicRef<'a, Base> { + pub fn map(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 000000000000..4aba6bf6c009 --- /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 240cac4eb79b..1e3e7ac2313e 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;