Making everything thread safe

This commit is contained in:
Pauan 2018-06-11 10:54:47 -10:00
parent b203b0e030
commit b8e18b3d25
2 changed files with 67 additions and 71 deletions

View File

@ -1,6 +1,5 @@
use std::fmt; use std::fmt;
use std::rc::{Rc, Weak}; use std::sync::{Arc, Weak, Mutex, RwLock};
use std::cell::RefCell;
use futures_core::Async; use futures_core::Async;
use futures_core::future::Future; use futures_core::future::Future;
use futures_core::task::{Context, Waker}; use futures_core::task::{Context, Waker};
@ -51,12 +50,12 @@ impl Drop for Raf {
struct TimestampsInner { struct TimestampsInner {
raf: Option<Raf>, raf: Option<Raf>,
// TODO make this more efficient // TODO make this more efficient
states: Vec<Weak<RefCell<TimestampsState>>>, states: Vec<Weak<Mutex<TimestampsState>>>,
} }
struct TimestampsGlobal { struct TimestampsGlobal {
inner: RefCell<TimestampsInner>, inner: Mutex<TimestampsInner>,
value: Rc<RefCell<Option<f64>>>, value: Arc<RwLock<Option<f64>>>,
} }
enum TimestampsEnum { enum TimestampsEnum {
@ -71,9 +70,9 @@ struct TimestampsState {
} }
pub struct Timestamps { pub struct Timestamps {
state: Rc<RefCell<TimestampsState>>, state: Arc<Mutex<TimestampsState>>,
// TODO verify that there aren't any Rc cycles // TODO verify that there aren't any Arc cycles
value: Rc<RefCell<Option<f64>>>, value: Arc<RwLock<Option<f64>>>,
} }
impl Signal for Timestamps { impl Signal for Timestamps {
@ -81,12 +80,12 @@ impl Signal for Timestamps {
// TODO implement Async::Ready(None) // TODO implement Async::Ready(None)
fn poll_change(&mut self, cx: &mut Context) -> Async<Option<Self::Item>> { fn poll_change(&mut self, cx: &mut Context) -> Async<Option<Self::Item>> {
let mut lock = self.state.borrow_mut(); let mut lock = self.state.lock().unwrap();
match lock.state { match lock.state {
TimestampsEnum::Changed => { TimestampsEnum::Changed => {
lock.state = TimestampsEnum::NotChanged; lock.state = TimestampsEnum::NotChanged;
Async::Ready(Some(*self.value.borrow())) Async::Ready(Some(*self.value.read().unwrap()))
}, },
TimestampsEnum::First => { TimestampsEnum::First => {
lock.state = TimestampsEnum::NotChanged; lock.state = TimestampsEnum::NotChanged;
@ -100,69 +99,67 @@ impl Signal for Timestamps {
} }
} }
thread_local! { lazy_static! {
static TIMESTAMPS: Rc<TimestampsGlobal> = Rc::new(TimestampsGlobal { static ref TIMESTAMPS: Arc<TimestampsGlobal> = Arc::new(TimestampsGlobal {
inner: RefCell::new(TimestampsInner { inner: Mutex::new(TimestampsInner {
raf: None, raf: None,
states: vec![], states: vec![],
}), }),
value: Rc::new(RefCell::new(None)), value: Arc::new(RwLock::new(None)),
}); });
} }
pub fn timestamps() -> Timestamps { pub fn timestamps() -> Timestamps {
TIMESTAMPS.with(|global| { let timestamps = Timestamps {
let timestamps = Timestamps { state: Arc::new(Mutex::new(TimestampsState {
state: Rc::new(RefCell::new(TimestampsState { state: TimestampsEnum::First,
state: TimestampsEnum::First, waker: None,
waker: None, })),
})), value: TIMESTAMPS.value.clone(),
value: global.value.clone(), };
};
{ {
let mut lock = global.inner.borrow_mut(); let mut lock = TIMESTAMPS.inner.lock().unwrap();
lock.states.push(Rc::downgrade(&timestamps.state)); lock.states.push(Arc::downgrade(&timestamps.state));
if let None = lock.raf { if let None = lock.raf {
let global = global.clone(); let global = TIMESTAMPS.clone();
lock.raf = Some(Raf::new(move |time| { lock.raf = Some(Raf::new(move |time| {
let mut lock = global.inner.borrow_mut(); let mut lock = global.inner.lock().unwrap();
let mut value = global.value.borrow_mut(); let mut value = global.value.write().unwrap();
*value = Some(time); *value = Some(time);
lock.states.retain(|state| { lock.states.retain(|state| {
if let Some(state) = state.upgrade() { if let Some(state) = state.upgrade() {
let mut lock = state.borrow_mut(); let mut lock = state.lock().unwrap();
lock.state = TimestampsEnum::Changed; lock.state = TimestampsEnum::Changed;
if let Some(waker) = lock.waker.take() { if let Some(waker) = lock.waker.take() {
drop(lock); drop(lock);
waker.wake(); waker.wake();
}
true
} else {
false
} }
});
if lock.states.len() == 0 { true
lock.raf = None;
// TODO is this a good idea ? } else {
lock.states = vec![]; false
} }
})); });
}
}
timestamps if lock.states.len() == 0 {
}) lock.raf = None;
// TODO is this a good idea ?
lock.states = vec![];
}
}));
}
}
timestamps
} }
@ -497,17 +494,17 @@ struct MutableAnimationState {
} }
struct MutableAnimationInner { struct MutableAnimationInner {
state: RefCell<MutableAnimationState>, state: Mutex<MutableAnimationState>,
value: Mutable<Percentage>, value: Mutable<Percentage>,
} }
pub struct MutableAnimation { pub struct MutableAnimation {
inner: Rc<MutableAnimationInner>, inner: Arc<MutableAnimationInner>,
} }
impl fmt::Debug for MutableAnimation { impl fmt::Debug for MutableAnimation {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let state = self.inner.state.borrow(); let state = self.inner.state.lock().unwrap();
fmt.debug_struct("MutableAnimation") fmt.debug_struct("MutableAnimation")
.field("playing", &state.playing) .field("playing", &state.playing)
@ -524,8 +521,8 @@ impl MutableAnimation {
debug_assert!(duration >= 0.0); debug_assert!(duration >= 0.0);
Self { Self {
inner: Rc::new(MutableAnimationInner { inner: Arc::new(MutableAnimationInner {
state: RefCell::new(MutableAnimationState { state: Mutex::new(MutableAnimationState {
playing: true, playing: true,
duration: duration, duration: duration,
end: initial, end: initial,
@ -578,7 +575,7 @@ impl MutableAnimation {
// TODO don't update if the new value is the same as the old value // TODO don't update if the new value is the same as the old value
if diff >= 1.0 { if diff >= 1.0 {
{ {
let mut lock = state.inner.state.borrow_mut(); let mut lock = state.inner.state.lock().unwrap();
Self::stop_animating(&mut lock); Self::stop_animating(&mut lock);
} }
state.inner.value.set(Percentage::new_unchecked(end)); state.inner.value.set(Percentage::new_unchecked(end));
@ -607,7 +604,7 @@ impl MutableAnimation {
pub fn set_duration(&self, duration: f64) { pub fn set_duration(&self, duration: f64) {
debug_assert!(duration >= 0.0); debug_assert!(duration >= 0.0);
let mut lock = self.inner.state.borrow_mut(); let mut lock = self.inner.state.lock().unwrap();
if lock.duration != duration { if lock.duration != duration {
lock.duration = duration; lock.duration = duration;
@ -617,7 +614,7 @@ impl MutableAnimation {
#[inline] #[inline]
pub fn pause(&self) { pub fn pause(&self) {
let mut lock = self.inner.state.borrow_mut(); let mut lock = self.inner.state.lock().unwrap();
if lock.playing { if lock.playing {
lock.playing = false; lock.playing = false;
@ -627,7 +624,7 @@ impl MutableAnimation {
#[inline] #[inline]
pub fn play(&self) { pub fn play(&self) {
let mut lock = self.inner.state.borrow_mut(); let mut lock = self.inner.state.lock().unwrap();
if !lock.playing { if !lock.playing {
lock.playing = true; lock.playing = true;
@ -647,13 +644,13 @@ impl MutableAnimation {
} }
pub fn jump_to(&self, end: Percentage) { pub fn jump_to(&self, end: Percentage) {
let mut lock = self.inner.state.borrow_mut(); let mut lock = self.inner.state.lock().unwrap();
Self::_jump_to(&mut lock, &self.inner.value, end); Self::_jump_to(&mut lock, &self.inner.value, end);
} }
pub fn animate_to(&self, end: Percentage) { pub fn animate_to(&self, end: Percentage) {
let mut lock = self.inner.state.borrow_mut(); let mut lock = self.inner.state.lock().unwrap();
if lock.end != end { if lock.end != end {
if lock.duration <= 0.0 { if lock.duration <= 0.0 {

View File

@ -1,5 +1,4 @@
use std::rc::Rc; use std::sync::{Arc, Mutex};
use std::cell::RefCell;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use stdweb::PromiseFuture; use stdweb::PromiseFuture;
use discard::{Discard, DiscardOnDrop}; use discard::{Discard, DiscardOnDrop};
@ -143,8 +142,8 @@ pub fn insert_children_signal_vec<A, B>(element: &A, callbacks: &mut Callbacks,
children: Vec<Dom>, children: Vec<Dom>,
} }
// TODO use two separate Rcs ? // TODO use two separate Arcs ?
let state = Rc::new(RefCell::new(State { let state = Arc::new(Mutex::new(State {
is_inserted: false, is_inserted: false,
children: vec![], children: vec![],
})); }));
@ -153,7 +152,7 @@ pub fn insert_children_signal_vec<A, B>(element: &A, callbacks: &mut Callbacks,
let state = state.clone(); let state = state.clone();
callbacks.after_insert(move |_| { callbacks.after_insert(move |_| {
let mut state = state.borrow_mut(); let mut state = state.lock().unwrap();
if !state.is_inserted { if !state.is_inserted {
state.is_inserted = true; state.is_inserted = true;
@ -167,7 +166,7 @@ pub fn insert_children_signal_vec<A, B>(element: &A, callbacks: &mut Callbacks,
// TODO verify that this will drop `children` // TODO verify that this will drop `children`
callbacks.after_remove(for_each_vec(signal.into_signal_vec(), move |change| { callbacks.after_remove(for_each_vec(signal.into_signal_vec(), move |change| {
let mut state = state.borrow_mut(); let mut state = state.lock().unwrap();
match change { match change {
VecDiff::Replace { values } => { VecDiff::Replace { values } => {