dioxus_v04_optional_hooks/
lib.rs1use std::fmt::Debug;
2use std::future::Future;
3use dioxus::prelude::*;
4
5#[derive(Clone)]
7pub struct FutureHook<'a, T, E>
8 where
9 T: 'static + ?Sized + Clone,
10 E: 'static + ?Sized + Clone + Debug,
11{
12 future: &'a UseFuture<Result<T, E>>,
13 outdated_marker: &'a UseState<bool>,
14}
15
16impl<'a, T: ?Sized + Clone, E: ?Sized + Clone + Debug> Copy for FutureHook<'a, T, E> {}
17
18#[derive(PartialEq, Eq)]
19pub enum FutureState {
20 Empty,
21 Ready,
22 Error,
23 Outdated,
24 Reloading,
25}
26
27#[derive(PartialEq, Eq)]
28pub enum StartupGuard {
29 Disable = 0,
30 Enable = 1,
31}
32
33impl<'a, T, E> FutureHook<'a, T, E>
34 where
35 T: 'static + Clone,
36 E: 'static + Clone + Debug,
37{
38 pub fn new<
51 D: UseFutureDep,
52 F: Future<Output = Result<T, E>> + 'static
53 >(
54 cx: Scope<'a>,
55 startup_guard: StartupGuard,
56 dependencies: D,
57 fut: impl FnOnce(D::Out) -> F
58 ) -> Self {
59 let outdated = startup_guard == StartupGuard::Enable;
60 Self {
61 future: use_future(cx, dependencies, fut),
62 outdated_marker: use_state(cx, || outdated),
63 }
64 }
65
66 pub fn check_state(&self) -> FutureState {
68 let val = match self.future.state() {
69 UseFutureState::Pending => FutureState::Empty,
70 UseFutureState::Complete(Ok(_)) => FutureState::Ready,
71 UseFutureState::Complete(Err(_)) => FutureState::Error,
72 UseFutureState::Reloading(_) => FutureState::Reloading,
73 };
74 if (val == FutureState::Ready || val == FutureState::Error) && self.is_outdated() {
75 return FutureState::Outdated
76 }
77 val
78 }
79
80 pub fn read(&self, allow_cache_while_reloading: bool) -> Option<&'a T> {
82 if self.is_outdated() { return None }
83 if !allow_cache_while_reloading {
84 match self.check_state() {
85 FutureState::Empty | FutureState::Reloading | FutureState::Error | FutureState::Outdated => { None },
86 FutureState::Ready => {
87 let val = self.future.value().as_ref().unwrap().as_ref().unwrap();
88 Some(val)
89 },
90 }
91 } else {
92 match self.check_state() {
93 FutureState::Empty | FutureState::Error => { None },
94 FutureState::Ready | FutureState::Reloading => {
95 let val_p = self.future.value();
96 let val = val_p.as_ref().unwrap();
97 match val.as_ref() {
98 Err(_) => None,
99 Ok(val) => Some(val),
100 }
101 },
102 FutureState::Outdated => {
103 if let UseFutureState::Complete(Ok(val)) = self.future.state() {
104 Some(val)
105 } else {
106 None
107 }
108 },
109 }
110 }
111 }
112
113 pub fn read_clone(&self, allow_cache_while_reloading: bool) -> Option<T> {
115 self.read(allow_cache_while_reloading).cloned()
116 }
117
118 pub fn read_unchecked(&self) -> Option<&'a Result<T, E>> {
120 self.future.value()
121 }
122
123 pub fn restart(&self) {
125 if self.check_state() == FutureState::Empty || self.check_state() == FutureState::Reloading { return }
126
127 self.outdated_marker.set(false);
128 self.future.restart();
129 }
130
131 pub fn fetch(&self) {
133 if self.is_outdated() { self.restart(); }
134 }
135
136 pub fn lazy_fetch(&self) {
141 if self.is_outdated() {
142 self.outdated_marker.set(false);
143 self.restart();
144 } else {
145 self.fetch();
146 }
147 }
148
149 pub fn is_outdated(&self) -> bool {
151 **self.outdated_marker
152 }
153
154 pub fn set_outdated(&self) {
156 self.outdated_marker.set(true)
157 }
158
159 pub fn get_outdated_marker(&self) -> UseState<bool> {
161 self.outdated_marker.to_owned()
162 }
163}