Minor improvement to the animation implementation
This commit is contained in:
parent
ae65e7db23
commit
88261d875b
|
@ -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.state = TimestampsEnum::NotChanged;
|
|
||||||
Poll::Ready(Some(None))
|
|
||||||
},
|
|
||||||
TimestampsEnum::NotChanged => {
|
|
||||||
lock.waker = Some(cx.waker().clone());
|
lock.waker = Some(cx.waker().clone());
|
||||||
Poll::Pending
|
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(×tamps.state));
|
lock.states.push(Arc::downgrade(×tamps.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);
|
||||||
|
|
Loading…
Reference in New Issue