Making everything thread safe
This commit is contained in:
parent
b203b0e030
commit
b8e18b3d25
127
src/animation.rs
127
src/animation.rs
|
@ -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(×tamps.state));
|
lock.states.push(Arc::downgrade(×tamps.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 {
|
||||||
|
|
|
@ -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 } => {
|
||||||
|
|
Loading…
Reference in New Issue