Express unique ownership of arc in StyleStructRef, add vacated state

MozReview-Commit-ID: GwOw0HaC9S7
This commit is contained in:
Manish Goregaokar 2017-05-03 14:48:35 -07:00 committed by Manish Goregaokar
parent c85aae4abd
commit dd3159f2f5
2 changed files with 79 additions and 7 deletions

View file

@ -14,7 +14,7 @@ use std::borrow::Cow;
use std::collections::HashSet;
use std::fmt;
use std::ops::Deref;
use stylearc::Arc;
use stylearc::{Arc, UniqueArc};
use app_units::Au;
#[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
@ -2057,7 +2057,9 @@ pub enum StyleStructRef<'a, T: 'a> {
/// A borrowed struct from the parent, for example, for inheriting style.
Borrowed(&'a Arc<T>),
/// An owned struct, that we've already mutated.
Owned(Arc<T>),
Owned(UniqueArc<T>),
/// Temporarily vacated, will panic if accessed
Vacated,
}
impl<'a, T: 'a> StyleStructRef<'a, T>
@ -2067,21 +2069,45 @@ impl<'a, T: 'a> StyleStructRef<'a, T>
/// borrowed value, or returning the owned one.
pub fn mutate(&mut self) -> &mut T {
if let StyleStructRef::Borrowed(v) = *self {
*self = StyleStructRef::Owned(Arc::new((**v).clone()));
*self = StyleStructRef::Owned(UniqueArc::new((**v).clone()));
}
match *self {
StyleStructRef::Owned(ref mut v) => Arc::get_mut(v).unwrap(),
StyleStructRef::Owned(ref mut v) => v,
StyleStructRef::Borrowed(..) => unreachable!(),
StyleStructRef::Vacated => panic!("Accessed vacated style struct")
}
}
/// Extract a unique Arc from this struct, vacating it.
///
/// The vacated state is a transient one, please put the Arc back
/// when done via `put()`. This function is to be used to separate
/// the struct being mutated from the computed context
pub fn take(&mut self) -> UniqueArc<T> {
use std::mem::replace;
let inner = replace(self, StyleStructRef::Vacated);
match inner {
StyleStructRef::Owned(arc) => arc,
StyleStructRef::Borrowed(arc) => UniqueArc::new((**arc).clone()),
StyleStructRef::Vacated => panic!("Accessed vacated style struct"),
}
}
/// Replace vacated ref with an arc
pub fn put(&mut self, arc: UniqueArc<T>) {
debug_assert!(matches!(*self, StyleStructRef::Vacated));
*self = StyleStructRef::Owned(arc);
}
/// Get a mutable reference to the owned struct, or `None` if the struct
/// hasn't been mutated.
pub fn get_if_mutated(&mut self) -> Option<<&mut T> {
match *self {
StyleStructRef::Owned(ref mut v) => Some(Arc::get_mut(v).unwrap()),
StyleStructRef::Owned(ref mut v) => Some(v),
StyleStructRef::Borrowed(..) => None,
StyleStructRef::Vacated => panic!("Accessed vacated style struct")
}
}
@ -2089,8 +2115,9 @@ impl<'a, T: 'a> StyleStructRef<'a, T>
/// appropriate.
pub fn build(self) -> Arc<T> {
match self {
StyleStructRef::Owned(v) => v,
StyleStructRef::Owned(v) => v.shareable(),
StyleStructRef::Borrowed(v) => v.clone(),
StyleStructRef::Vacated => panic!("Accessed vacated style struct")
}
}
}
@ -2102,6 +2129,7 @@ impl<'a, T: 'a> Deref for StyleStructRef<'a, T> {
match *self {
StyleStructRef::Owned(ref v) => &**v,
StyleStructRef::Borrowed(v) => &**v,
StyleStructRef::Vacated => panic!("Accessed vacated style struct")
}
}
}
@ -2183,6 +2211,16 @@ impl<'a> StyleBuilder<'a> {
self.${style_struct.ident}.mutate()
}
/// Gets a mutable view of the current `${style_struct.name}` style.
pub fn take_${style_struct.name_lower}(&mut self) -> UniqueArc<style_structs::${style_struct.name}> {
self.${style_struct.ident}.take()
}
/// Gets a mutable view of the current `${style_struct.name}` style.
pub fn put_${style_struct.name_lower}(&mut self, s: UniqueArc<style_structs::${style_struct.name}>) {
self.${style_struct.ident}.put(s)
}
/// Gets a mutable view of the current `${style_struct.name}` style,
/// only if it's been mutated before.
pub fn get_${style_struct.name_lower}_if_mutated(&mut self)

View file

@ -31,7 +31,7 @@ use std::convert::From;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::ops::{Deref, DerefMut};
use std::sync::atomic;
use std::sync::atomic::Ordering::{Acquire, Relaxed, Release};
@ -71,6 +71,40 @@ pub struct Arc<T: ?Sized> {
ptr: *mut ArcInner<T>,
}
/// An Arc that is known to be uniquely owned
///
/// This lets us build arcs that we can mutate before
/// freezing, without needing to change the allocation
pub struct UniqueArc<T: ?Sized>(Arc<T>);
impl<T> UniqueArc<T> {
#[inline]
/// Construct a new UniqueArc
pub fn new(data: T) -> Self {
UniqueArc(Arc::new(data))
}
#[inline]
/// Convert to a shareable Arc<T> once we're done using it
pub fn shareable(self) -> Arc<T> {
self.0
}
}
impl<T> Deref for UniqueArc<T> {
type Target = T;
fn deref(&self) -> &T {
&*self.0
}
}
impl<T> DerefMut for UniqueArc<T> {
fn deref_mut(&mut self) -> &mut T {
// We know this to be uniquely owned
unsafe { &mut (*self.0.ptr).data }
}
}
unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}