ferroui_base/animation/
animation_task.rs1use crate::animation::AnimationError;
9use std::cell::RefCell;
10use std::future::Future;
11use std::pin::Pin;
12use std::rc::Rc;
13use std::task::{Context, Poll, Waker};
14
15#[derive(Default)]
16struct State {
17 result: Option<Result<(), AnimationError>>,
18 wakers: Vec<Waker>,
19 continuations: Vec<Box<dyn FnOnce()>>,
20}
21
22#[derive(Clone, Default)]
28pub struct AnimationTask {
29 state: Rc<RefCell<State>>,
30}
31
32impl AnimationTask {
33 pub(crate) fn pending() -> Self {
35 Self::default()
36 }
37
38 pub fn completed() -> Self {
40 let task = Self::default();
41 task.state.borrow_mut().result = Some(Ok(()));
42 task
43 }
44
45 pub fn is_completed(&self) -> bool {
47 self.state.borrow().result.is_some()
48 }
49
50 pub fn result(&self) -> Option<Result<(), AnimationError>> {
52 self.state.borrow().result.clone()
53 }
54
55 pub fn on_completed(&self, continuation: impl FnOnce() + 'static) {
58 if self.is_completed() {
59 continuation();
60 } else {
61 self.state.borrow_mut().continuations.push(Box::new(continuation));
62 }
63 }
64
65 pub(crate) fn try_set(&self, result: Result<(), AnimationError>) -> bool {
68 let (wakers, continuations) = {
69 let mut state = self.state.borrow_mut();
70 if state.result.is_some() {
71 return false;
72 }
73 state.result = Some(result);
74 (std::mem::take(&mut state.wakers), std::mem::take(&mut state.continuations))
75 };
76 for continuation in continuations {
77 continuation();
78 }
79 for waker in wakers {
80 waker.wake();
81 }
82 true
83 }
84
85 pub(crate) fn try_set_result(&self) -> bool {
86 self.try_set(Ok(()))
87 }
88
89 pub fn when_all(tasks: impl IntoIterator<Item = AnimationTask>) -> AnimationTask {
92 let tasks: Vec<AnimationTask> = tasks.into_iter().collect();
93 let all = AnimationTask::pending();
94 let complete = {
95 let all = all.clone();
96 let tasks = tasks.clone();
97 Rc::new(move || {
98 if tasks.iter().all(AnimationTask::is_completed) {
99 let error = tasks.iter().find_map(|task| task.result().and_then(Result::err));
100 all.try_set(match error {
101 Some(error) => Err(error),
102 None => Ok(()),
103 });
104 }
105 })
106 };
107 if tasks.is_empty() {
108 all.try_set_result();
109 }
110 for task in &tasks {
111 let complete = complete.clone();
112 task.on_completed(move || complete());
113 }
114 all
115 }
116}
117
118impl Future for AnimationTask {
119 type Output = Result<(), AnimationError>;
120
121 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
122 let mut state = self.state.borrow_mut();
123 match &state.result {
124 Some(result) => Poll::Ready(result.clone()),
125 None => {
126 if !state.wakers.iter().any(|waker| waker.will_wake(cx.waker())) {
127 state.wakers.push(cx.waker().clone());
128 }
129 Poll::Pending
130 }
131 }
132 }
133}