Replacing pin-utils with pin-project

This commit is contained in:
Pauan 2020-06-02 14:27:36 +02:00
parent ccb9bcbf33
commit 4cf6acd71b
2 changed files with 50 additions and 51 deletions

View File

@ -18,7 +18,7 @@ default = ["wasm-bindgen/enable-interning"]
[dependencies] [dependencies]
lazy_static = "1.3.0" lazy_static = "1.3.0"
discard = "1.0.3" discard = "1.0.3"
pin-utils = "0.1.0-alpha.4" pin-project = "0.4"
futures-channel = "0.3.0" futures-channel = "0.3.0"
futures-util = "0.3.0" futures-util = "0.3.0"
futures-signals = "0.3.5" futures-signals = "0.3.5"

View File

@ -2,7 +2,6 @@ use std::fmt;
use std::rc::Rc; 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::sync::{Arc, Weak, Mutex}; use std::sync::{Arc, Weak, Mutex};
use std::task::{Poll, Waker, Context}; use std::task::{Poll, Waker, Context};
@ -11,7 +10,7 @@ use futures_signals::CancelableFutureHandle;
use futures_signals::signal::{Signal, SignalExt, WaitFor, MutableSignal, Mutable}; use futures_signals::signal::{Signal, SignalExt, WaitFor, MutableSignal, Mutable};
use futures_signals::signal_vec::{SignalVec, VecDiff}; use futures_signals::signal_vec::{SignalVec, VecDiff};
use discard::DiscardOnDrop; use discard::DiscardOnDrop;
use pin_utils::{unsafe_pinned, unsafe_unpinned}; use pin_project::pin_project;
use wasm_bindgen::{JsCast, UnwrapThrowExt}; use wasm_bindgen::{JsCast, UnwrapThrowExt};
use wasm_bindgen::closure::Closure; use wasm_bindgen::closure::Closure;
use web_sys::window; use web_sys::window;
@ -239,10 +238,12 @@ struct AnimatedMapState {
} }
// TODO move this into signals crate and also generalize it to work with any future, not just animations // TODO move this into signals crate and also generalize it to work with any future, not just animations
#[pin_project]
#[derive(Debug)] #[derive(Debug)]
pub struct AnimatedMap<A, B> { pub struct AnimatedMap<A, B> {
duration: f64, duration: f64,
animations: Vec<AnimatedMapState>, animations: Vec<AnimatedMapState>,
#[pin]
signal: Option<A>, signal: Option<A>,
callback: B, callback: B,
} }
@ -251,13 +252,9 @@ impl<A, F, S> AnimatedMap<S, F>
where S: SignalVec, where S: SignalVec,
F: FnMut(S::Item, AnimatedMapBroadcaster) -> A { F: FnMut(S::Item, AnimatedMapBroadcaster) -> A {
unsafe_unpinned!(animations: Vec<AnimatedMapState>); fn animated_state(duration: f64) -> AnimatedMapState {
unsafe_pinned!(signal: Option<S>);
unsafe_unpinned!(callback: F);
fn animated_state(&self) -> AnimatedMapState {
let state = AnimatedMapState { let state = AnimatedMapState {
animation: MutableAnimation::new(self.duration), animation: MutableAnimation::new(duration),
removing: None, removing: None,
}; };
@ -266,19 +263,19 @@ impl<A, F, S> AnimatedMap<S, F>
state state
} }
fn remove_index(mut self: Pin<&mut Self>, index: usize) -> Poll<Option<VecDiff<A>>> { fn remove_index(animations: &mut Vec<AnimatedMapState>, index: usize) -> Poll<Option<VecDiff<A>>> {
if index == (self.animations.len() - 1) { if index == (animations.len() - 1) {
self.as_mut().animations().pop(); animations.pop();
Poll::Ready(Some(VecDiff::Pop {})) Poll::Ready(Some(VecDiff::Pop {}))
} else { } else {
self.as_mut().animations().remove(index); animations.remove(index);
Poll::Ready(Some(VecDiff::RemoveAt { index })) Poll::Ready(Some(VecDiff::RemoveAt { index }))
} }
} }
fn should_remove(mut self: Pin<&mut Self>, cx: &mut Context, index: usize) -> bool { fn should_remove(animations: &mut Vec<AnimatedMapState>, cx: &mut Context, index: usize) -> bool {
let state = &mut self.as_mut().animations()[index]; let state = &mut animations[index];
state.animation.animate_to(Percentage::new_unchecked(0.0)); state.animation.animate_to(Percentage::new_unchecked(0.0));
@ -293,11 +290,11 @@ impl<A, F, S> AnimatedMap<S, F>
} }
} }
fn find_index(&self, parent_index: usize) -> Option<usize> { fn find_index(animations: &Vec<AnimatedMapState>, parent_index: usize) -> Option<usize> {
let mut seen = 0; let mut seen = 0;
// TODO is there a combinator that can simplify this ? // TODO is there a combinator that can simplify this ?
self.animations.iter().position(|state| { animations.iter().position(|state| {
if state.removing.is_none() { if state.removing.is_none() {
if seen == parent_index { if seen == parent_index {
true true
@ -314,40 +311,42 @@ impl<A, F, S> AnimatedMap<S, F>
} }
#[inline] #[inline]
fn find_last_index(&self) -> Option<usize> { fn find_last_index(animations: &Vec<AnimatedMapState>) -> Option<usize> {
self.animations.iter().rposition(|state| state.removing.is_none()) animations.iter().rposition(|state| state.removing.is_none())
} }
} }
impl<A, B> Unpin for AnimatedMap<A, B> where A: Unpin {}
impl<A, F, S> SignalVec for AnimatedMap<S, F> impl<A, F, S> SignalVec for AnimatedMap<S, F>
where S: SignalVec, where S: SignalVec,
F: FnMut(S::Item, AnimatedMapBroadcaster) -> A { F: FnMut(S::Item, AnimatedMapBroadcaster) -> A {
type Item = A; type Item = A;
// TODO this can probably be implemented more efficiently // TODO this can probably be implemented more efficiently
fn poll_vec_change(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<VecDiff<Self::Item>>> { #[pin_project::project]
fn poll_vec_change(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<VecDiff<Self::Item>>> {
let mut is_done = true; let mut is_done = true;
#[project]
let AnimatedMap { mut animations, mut signal, callback, duration, .. } = self.project();
// TODO is this loop correct ? // TODO is this loop correct ?
while let Some(result) = self.as_mut().signal().as_pin_mut().map(|signal| signal.poll_vec_change(cx)) { while let Some(result) = signal.as_mut().as_pin_mut().map(|signal| signal.poll_vec_change(cx)) {
match result { match result {
Poll::Ready(Some(change)) => return match change { Poll::Ready(Some(change)) => return match change {
// TODO maybe it should play remove / insert animations for this ? // TODO maybe it should play remove / insert animations for this ?
VecDiff::Replace { values } => { VecDiff::Replace { values } => {
*self.as_mut().animations() = Vec::with_capacity(values.len()); *animations = Vec::with_capacity(values.len());
Poll::Ready(Some(VecDiff::Replace { Poll::Ready(Some(VecDiff::Replace {
values: values.into_iter().map(|value| { values: values.into_iter().map(|value| {
let state = AnimatedMapState { let state = AnimatedMapState {
animation: MutableAnimation::new_with_initial(self.duration, Percentage::new_unchecked(1.0)), animation: MutableAnimation::new_with_initial(*duration, Percentage::new_unchecked(1.0)),
removing: None, removing: None,
}; };
let value = self.as_mut().callback()(value, AnimatedMapBroadcaster(state.animation.raw_clone())); let value = callback(value, AnimatedMapBroadcaster(state.animation.raw_clone()));
self.as_mut().animations().push(state); animations.push(state);
value value
}).collect() }).collect()
@ -355,49 +354,49 @@ impl<A, F, S> SignalVec for AnimatedMap<S, F>
}, },
VecDiff::InsertAt { index, value } => { VecDiff::InsertAt { index, value } => {
let index = self.find_index(index).unwrap_or_else(|| self.animations.len()); let index = Self::find_index(&animations, index).unwrap_or_else(|| animations.len());
let state = self.animated_state(); let state = Self::animated_state(*duration);
let value = self.as_mut().callback()(value, AnimatedMapBroadcaster(state.animation.raw_clone())); let value = callback(value, AnimatedMapBroadcaster(state.animation.raw_clone()));
self.as_mut().animations().insert(index, state); animations.insert(index, state);
Poll::Ready(Some(VecDiff::InsertAt { index, value })) Poll::Ready(Some(VecDiff::InsertAt { index, value }))
}, },
VecDiff::Push { value } => { VecDiff::Push { value } => {
let state = self.animated_state(); let state = Self::animated_state(*duration);
let value = self.as_mut().callback()(value, AnimatedMapBroadcaster(state.animation.raw_clone())); let value = callback(value, AnimatedMapBroadcaster(state.animation.raw_clone()));
self.as_mut().animations().push(state); animations.push(state);
Poll::Ready(Some(VecDiff::Push { value })) Poll::Ready(Some(VecDiff::Push { value }))
}, },
VecDiff::UpdateAt { index, value } => { VecDiff::UpdateAt { index, value } => {
let index = self.find_index(index).unwrap_throw(); let index = Self::find_index(&animations, index).unwrap_throw();
let state = { let state = {
let state = &self.as_mut().animations()[index]; let state = &animations[index];
AnimatedMapBroadcaster(state.animation.raw_clone()) AnimatedMapBroadcaster(state.animation.raw_clone())
}; };
let value = self.as_mut().callback()(value, state); let value = callback(value, state);
Poll::Ready(Some(VecDiff::UpdateAt { index, value })) Poll::Ready(Some(VecDiff::UpdateAt { index, value }))
}, },
// TODO test this // TODO test this
// TODO should this be treated as a removal + insertion ? // TODO should this be treated as a removal + insertion ?
VecDiff::Move { old_index, new_index } => { VecDiff::Move { old_index, new_index } => {
let old_index = self.find_index(old_index).unwrap_throw(); let old_index = Self::find_index(&animations, old_index).unwrap_throw();
let state = self.as_mut().animations().remove(old_index); let state = animations.remove(old_index);
let new_index = self.find_index(new_index).unwrap_or_else(|| self.animations.len()); let new_index = Self::find_index(&animations, new_index).unwrap_or_else(|| animations.len());
self.animations().insert(new_index, state); animations.insert(new_index, state);
Poll::Ready(Some(VecDiff::Move { old_index, new_index })) Poll::Ready(Some(VecDiff::Move { old_index, new_index }))
}, },
VecDiff::RemoveAt { index } => { VecDiff::RemoveAt { index } => {
let index = self.find_index(index).unwrap_throw(); let index = Self::find_index(&animations, index).unwrap_throw();
if self.as_mut().should_remove(cx, index) { if Self::should_remove(&mut animations, cx, index) {
self.remove_index(index) Self::remove_index(&mut animations, index)
} else { } else {
continue; continue;
@ -405,10 +404,10 @@ impl<A, F, S> SignalVec for AnimatedMap<S, F>
}, },
VecDiff::Pop {} => { VecDiff::Pop {} => {
let index = self.find_last_index().unwrap_throw(); let index = Self::find_last_index(&animations).unwrap_throw();
if self.as_mut().should_remove(cx, index) { if Self::should_remove(&mut animations, cx, index) {
self.remove_index(index) Self::remove_index(&mut animations, index)
} else { } else {
continue; continue;
@ -417,12 +416,12 @@ impl<A, F, S> SignalVec for AnimatedMap<S, F>
// TODO maybe it should play remove animation for this ? // TODO maybe it should play remove animation for this ?
VecDiff::Clear {} => { VecDiff::Clear {} => {
self.animations().clear(); animations.clear();
Poll::Ready(Some(VecDiff::Clear {})) Poll::Ready(Some(VecDiff::Clear {}))
}, },
}, },
Poll::Ready(None) => { Poll::Ready(None) => {
self.as_mut().signal().set(None); signal.set(None);
break; break;
}, },
Poll::Pending => { Poll::Pending => {
@ -436,7 +435,7 @@ impl<A, F, S> SignalVec for AnimatedMap<S, F>
// TODO make this more efficient (e.g. using a similar strategy as FuturesUnordered) // TODO make this more efficient (e.g. using a similar strategy as FuturesUnordered)
// This uses rposition so that way it will return VecDiff::Pop in more situations // This uses rposition so that way it will return VecDiff::Pop in more situations
let index = self.as_mut().animations().iter_mut().rposition(|state| { let index = animations.iter_mut().rposition(|state| {
if let Some(ref mut future) = state.removing { if let Some(ref mut future) = state.removing {
is_removing = true; is_removing = true;
future.poll_unpin(cx).is_ready() future.poll_unpin(cx).is_ready()
@ -448,7 +447,7 @@ impl<A, F, S> SignalVec for AnimatedMap<S, F>
match index { match index {
Some(index) => { Some(index) => {
self.remove_index(index) Self::remove_index(&mut animations, index)
}, },
None => if is_done && !is_removing { None => if is_done && !is_removing {
Poll::Ready(None) Poll::Ready(None)