freya_core/lifecycle/
future_task.rs1use crate::prelude::*;
2pub enum FutureState<D> {
3 Pending,
5 Loading,
7 Fulfilled(D),
9}
10
11impl<D> FutureState<D> {
12 pub fn try_as_fulfilled(&self) -> Option<&D> {
13 if let Self::Fulfilled(d) = &self {
14 Some(d)
15 } else {
16 None
17 }
18 }
19
20 pub fn as_fulfilled(&self) -> &D {
21 self.try_as_fulfilled()
22 .expect("Future state is not fulfilled")
23 }
24
25 pub fn is_loading(&self) -> bool {
26 matches!(self, Self::Loading)
27 }
28
29 pub fn is_pending(&self) -> bool {
30 matches!(self, Self::Pending)
31 }
32}
33
34pub struct FutureTask<D, F> {
35 future: State<Box<dyn FnMut() -> F>>,
36 state: State<FutureState<D>>,
37 task: State<Option<TaskHandle>>,
38}
39
40impl<D, F> Clone for FutureTask<D, F> {
41 fn clone(&self) -> Self {
42 *self
43 }
44}
45
46impl<D, F> Copy for FutureTask<D, F> {}
47
48impl<D: 'static, F: Future<Output = D> + 'static> FutureTask<D, F> {
49 pub fn create(future: impl FnMut() -> F + 'static) -> FutureTask<D, F> {
51 Self {
52 future: State::create(Box::new(future)),
53 state: State::create(FutureState::Pending),
54 task: State::create(None),
55 }
56 }
57
58 pub fn cancel(&mut self) {
60 if let Some(task) = self.task.take() {
61 task.cancel();
62 }
63 }
64
65 pub fn start(&mut self) {
67 self.cancel();
68 let mut this = *self;
69 let task = spawn(async move {
70 let future = this.future.write()();
71 this.state.set(FutureState::Loading);
72 let data = future.await;
73 this.state.set(FutureState::Fulfilled(data));
74 });
75 self.task.set(Some(task));
76 }
77
78 pub fn state(&self) -> ReadRef<'static, FutureState<D>> {
80 self.state.read()
81 }
82}
83
84pub fn use_future<D: 'static, F: Future<Output = D> + 'static>(
91 future: impl FnMut() -> F + 'static,
92) -> FutureTask<D, F> {
93 use_hook(|| {
94 let mut future = FutureTask::create(future);
95 future.start();
96 future
97 })
98}