Minor improvement to the animation implementation

This commit is contained in:
Pauan 2019-08-29 04:56:06 +02:00
parent ae65e7db23
commit 88261d875b
1 changed files with 45 additions and 49 deletions

View File

@ -3,7 +3,7 @@ use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use std::pin::Pin; use std::pin::Pin;
use std::marker::Unpin; use std::marker::Unpin;
use std::sync::{Arc, Weak, Mutex, RwLock}; use std::sync::{Arc, Weak, Mutex};
use std::task::{Poll, Waker, Context}; use std::task::{Poll, Waker, Context};
use futures_util::future::{ready, FutureExt}; use futures_util::future::{ready, FutureExt};
@ -77,36 +77,51 @@ impl Drop for Raf {
} }
struct TimestampsInner { struct TimestampsManager {
raf: Option<Raf>, raf: Option<Raf>,
// TODO make this more efficient // TODO make this more efficient
states: Vec<Weak<Mutex<TimestampsState>>>, states: Vec<Weak<Mutex<TimestampsState>>>,
} }
struct TimestampsGlobal { impl TimestampsManager {
inner: Mutex<TimestampsInner>, fn new() -> Self {
value: Arc<RwLock<Option<f64>>>, Self {
raf: None,
states: vec![],
}
}
} }
#[derive(Debug)]
enum TimestampsEnum {
First,
Changed,
NotChanged,
}
#[derive(Debug)] #[derive(Debug)]
struct TimestampsState { struct TimestampsState {
state: TimestampsEnum, changed: bool,
value: Option<f64>,
waker: Option<Waker>, waker: Option<Waker>,
} }
// TODO must_use ? impl TimestampsState {
fn new() -> Self {
Self {
changed: true,
value: None,
waker: None,
}
}
}
#[must_use = "Signals do nothing unless polled"]
#[derive(Debug)] #[derive(Debug)]
pub struct Timestamps { pub struct Timestamps {
state: Arc<Mutex<TimestampsState>>, state: Arc<Mutex<TimestampsState>>,
// TODO verify that there aren't any Arc cycles }
value: Arc<RwLock<Option<f64>>>,
impl Timestamps {
fn new() -> Self {
Self {
state: Arc::new(Mutex::new(TimestampsState::new())),
}
}
} }
impl Signal for Timestamps { impl Signal for Timestamps {
@ -116,63 +131,44 @@ impl Signal for Timestamps {
fn poll_change(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> { fn poll_change(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let mut lock = self.state.lock().unwrap_throw(); let mut lock = self.state.lock().unwrap_throw();
match lock.state { if lock.changed {
TimestampsEnum::Changed => { lock.changed = false;
lock.state = TimestampsEnum::NotChanged; Poll::Ready(Some(lock.value))
Poll::Ready(Some(*self.value.read().unwrap_throw()))
}, } else {
TimestampsEnum::First => { lock.waker = Some(cx.waker().clone());
lock.state = TimestampsEnum::NotChanged; Poll::Pending
Poll::Ready(Some(None))
},
TimestampsEnum::NotChanged => {
lock.waker = Some(cx.waker().clone());
Poll::Pending
},
} }
} }
} }
// TODO somehow share this safely between threads ? // TODO somehow share this safely between threads ?
thread_local! { thread_local! {
static TIMESTAMPS_MANAGER: Arc<TimestampsGlobal> = Arc::new(TimestampsGlobal { static TIMESTAMPS_MANAGER: Arc<Mutex<TimestampsManager>> = Arc::new(Mutex::new(TimestampsManager::new()));
inner: Mutex::new(TimestampsInner {
raf: None,
states: vec![],
}),
value: Arc::new(RwLock::new(None)),
});
} }
pub fn timestamps() -> Timestamps { pub fn timestamps() -> Timestamps {
TIMESTAMPS_MANAGER.with(|timestamps_manager| { TIMESTAMPS_MANAGER.with(|timestamps_manager| {
let timestamps = Timestamps { let timestamps = Timestamps::new();
state: Arc::new(Mutex::new(TimestampsState {
state: TimestampsEnum::First,
waker: None,
})),
value: timestamps_manager.value.clone(),
};
{ {
let mut lock = timestamps_manager.inner.lock().unwrap_throw(); let mut lock = timestamps_manager.lock().unwrap_throw();
lock.states.push(Arc::downgrade(&timestamps.state)); lock.states.push(Arc::downgrade(&timestamps.state));
if let None = lock.raf { if let None = lock.raf {
let global = timestamps_manager.clone(); let timestamps_manager = timestamps_manager.clone();
lock.raf = Some(Raf::new(move |time| { lock.raf = Some(Raf::new(move |time| {
let mut lock = global.inner.lock().unwrap_throw(); let mut lock = timestamps_manager.lock().unwrap_throw();
let mut value = global.value.write().unwrap_throw();
*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.lock().unwrap_throw(); let mut lock = state.lock().unwrap_throw();
lock.state = TimestampsEnum::Changed; lock.changed = true;
lock.value = Some(time);
if let Some(waker) = lock.waker.take() { if let Some(waker) = lock.waker.take() {
drop(lock); drop(lock);