usefuture.rs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. #![allow(missing_docs)]
  2. use dioxus_core::{ScopeState, TaskId};
  3. use std::{
  4. any::Any,
  5. cell::{Cell, RefCell},
  6. future::{Future, IntoFuture},
  7. rc::Rc,
  8. sync::Arc,
  9. };
  10. /// A future that resolves to a value.
  11. ///
  12. /// This runs the future only once - though the future may be regenerated
  13. /// through the [`UseFuture::restart`] method.
  14. ///
  15. /// This is commonly used for components that cannot be rendered until some
  16. /// asynchronous operation has completed.
  17. ///
  18. /// Whenever the hooks dependencies change, the future will be re-evaluated.
  19. /// If a future is pending when the dependencies change, the previous future
  20. /// will be allowed to continue
  21. ///
  22. /// - dependencies: a tuple of references to values that are PartialEq + Clone
  23. pub fn use_future<T, F, D>(
  24. cx: &ScopeState,
  25. dependencies: D,
  26. future: impl FnOnce(D::Out) -> F,
  27. ) -> &UseFuture<T>
  28. where
  29. T: 'static,
  30. F: Future<Output = T> + 'static,
  31. D: UseFutureDep,
  32. {
  33. let state = cx.use_hook(move || UseFuture {
  34. update: cx.schedule_update(),
  35. needs_regen: Cell::new(true),
  36. values: Default::default(),
  37. task: Cell::new(None),
  38. dependencies: Vec::new(),
  39. waker: Default::default(),
  40. });
  41. *state.waker.borrow_mut() = None;
  42. if dependencies.clone().apply(&mut state.dependencies) || state.needs_regen.get() {
  43. // We don't need regen anymore
  44. state.needs_regen.set(false);
  45. // Create the new future
  46. let fut = future(dependencies.out());
  47. // Clone in our cells
  48. let values = state.values.clone();
  49. let schedule_update = state.update.clone();
  50. let waker = state.waker.clone();
  51. // Cancel the current future
  52. if let Some(current) = state.task.take() {
  53. cx.remove_future(current);
  54. }
  55. state.task.set(Some(cx.push_future(async move {
  56. let res = fut.await;
  57. values.borrow_mut().push(Box::leak(Box::new(res)));
  58. // if there's a waker, we dont re-render the component. Instead we just progress that future
  59. match waker.borrow().as_ref() {
  60. Some(waker) => waker.wake_by_ref(),
  61. None => schedule_update(),
  62. }
  63. })));
  64. }
  65. state
  66. }
  67. pub enum FutureState<'a, T> {
  68. Pending,
  69. Complete(&'a T),
  70. Regenerating(&'a T), // the old value
  71. }
  72. pub struct UseFuture<T> {
  73. update: Arc<dyn Fn()>,
  74. needs_regen: Cell<bool>,
  75. task: Cell<Option<TaskId>>,
  76. dependencies: Vec<Box<dyn Any>>,
  77. waker: Rc<RefCell<Option<std::task::Waker>>>,
  78. values: Rc<RefCell<Vec<*mut T>>>,
  79. }
  80. pub enum UseFutureState<'a, T> {
  81. Pending,
  82. Complete(&'a T),
  83. Reloading(&'a T),
  84. }
  85. impl<T> UseFuture<T> {
  86. /// Restart the future with new dependencies.
  87. ///
  88. /// Will not cancel the previous future, but will ignore any values that it
  89. /// generates.
  90. pub fn restart(&self) {
  91. self.needs_regen.set(true);
  92. (self.update)();
  93. }
  94. /// Forcefully cancel a future
  95. pub fn cancel(&self, cx: &ScopeState) {
  96. if let Some(task) = self.task.take() {
  97. cx.remove_future(task);
  98. }
  99. }
  100. // clears the value in the future slot without starting the future over
  101. pub fn clear(&self) -> Option<T> {
  102. todo!()
  103. // (self.update)();
  104. // self.slot.replace(None)
  105. }
  106. // Manually set the value in the future slot without starting the future over
  107. pub fn set(&self, _new_value: T) {
  108. // self.slot.set(Some(new_value));
  109. // self.needs_regen.set(true);
  110. // (self.update)();
  111. todo!()
  112. }
  113. /// Return any value, even old values if the future has not yet resolved.
  114. ///
  115. /// If the future has never completed, the returned value will be `None`.
  116. pub fn value(&self) -> Option<&T> {
  117. self.values
  118. .borrow_mut()
  119. .last()
  120. .cloned()
  121. .map(|x| unsafe { &*x })
  122. }
  123. /// Get the ID of the future in Dioxus' internal scheduler
  124. pub fn task(&self) -> Option<TaskId> {
  125. self.task.get()
  126. }
  127. /// Get the current stateof the future.
  128. pub fn state(&self) -> UseFutureState<T> {
  129. todo!()
  130. // match (&self.task.get(), &self.value) {
  131. // // If we have a task and an existing value, we're reloading
  132. // (Some(_), Some(val)) => UseFutureState::Reloading(val),
  133. // // no task, but value - we're done
  134. // (None, Some(val)) => UseFutureState::Complete(val),
  135. // // no task, no value - something's wrong? return pending
  136. // (None, None) => UseFutureState::Pending,
  137. // // Task, no value - we're still pending
  138. // (Some(_), None) => UseFutureState::Pending,
  139. // }
  140. }
  141. }
  142. impl<'a, T> IntoFuture for &'a UseFuture<T> {
  143. type Output = &'a T;
  144. type IntoFuture = UseFutureAwait<'a, T>;
  145. fn into_future(self) -> Self::IntoFuture {
  146. UseFutureAwait { hook: self }
  147. }
  148. }
  149. pub struct UseFutureAwait<'a, T> {
  150. hook: &'a UseFuture<T>,
  151. }
  152. impl<'a, T> Future for UseFutureAwait<'a, T> {
  153. type Output = &'a T;
  154. fn poll(
  155. self: std::pin::Pin<&mut Self>,
  156. cx: &mut std::task::Context<'_>,
  157. ) -> std::task::Poll<Self::Output> {
  158. match self.hook.values.borrow_mut().last().cloned() {
  159. Some(value) => std::task::Poll::Ready(unsafe { &*value }),
  160. None => {
  161. self.hook.waker.replace(Some(cx.waker().clone()));
  162. std::task::Poll::Pending
  163. }
  164. }
  165. }
  166. }
  167. pub trait UseFutureDep: Sized + Clone {
  168. type Out;
  169. fn out(&self) -> Self::Out;
  170. fn apply(self, state: &mut Vec<Box<dyn Any>>) -> bool;
  171. }
  172. impl UseFutureDep for () {
  173. type Out = ();
  174. fn out(&self) -> Self::Out {}
  175. fn apply(self, _state: &mut Vec<Box<dyn Any>>) -> bool {
  176. false
  177. }
  178. }
  179. pub trait Dep: 'static + PartialEq + Clone {}
  180. impl<T> Dep for T where T: 'static + PartialEq + Clone {}
  181. impl<A: Dep> UseFutureDep for &A {
  182. type Out = A;
  183. fn out(&self) -> Self::Out {
  184. (*self).clone()
  185. }
  186. fn apply(self, state: &mut Vec<Box<dyn Any>>) -> bool {
  187. match state.get_mut(0).and_then(|f| f.downcast_mut::<A>()) {
  188. Some(val) => {
  189. if *val != *self {
  190. *val = self.clone();
  191. return true;
  192. }
  193. }
  194. None => {
  195. state.push(Box::new(self.clone()));
  196. return true;
  197. }
  198. }
  199. false
  200. }
  201. }
  202. macro_rules! impl_dep {
  203. (
  204. $($el:ident=$name:ident,)*
  205. ) => {
  206. impl< $($el),* > UseFutureDep for ($(&$el,)*)
  207. where
  208. $(
  209. $el: Dep
  210. ),*
  211. {
  212. type Out = ($($el,)*);
  213. fn out(&self) -> Self::Out {
  214. let ($($name,)*) = self;
  215. ($((*$name).clone(),)*)
  216. }
  217. #[allow(unused)]
  218. fn apply(self, state: &mut Vec<Box<dyn Any>>) -> bool {
  219. let ($($name,)*) = self;
  220. let mut idx = 0;
  221. let mut needs_regen = false;
  222. $(
  223. match state.get_mut(idx).map(|f| f.downcast_mut::<$el>()).flatten() {
  224. Some(val) => {
  225. if *val != *$name {
  226. *val = $name.clone();
  227. needs_regen = true;
  228. }
  229. }
  230. None => {
  231. state.push(Box::new($name.clone()));
  232. needs_regen = true;
  233. }
  234. }
  235. idx += 1;
  236. )*
  237. needs_regen
  238. }
  239. }
  240. };
  241. }
  242. impl_dep!(A = a,);
  243. impl_dep!(A = a, B = b,);
  244. impl_dep!(A = a, B = b, C = c,);
  245. impl_dep!(A = a, B = b, C = c, D = d,);
  246. impl_dep!(A = a, B = b, C = c, D = d, E = e,);
  247. impl_dep!(A = a, B = b, C = c, D = d, E = e, F = f,);
  248. impl_dep!(A = a, B = b, C = c, D = d, E = e, F = f, G = g,);
  249. impl_dep!(A = a, B = b, C = c, D = d, E = e, F = f, G = g, H = h,);
  250. /// A helper macro that merges uses the closure syntax to elaborate the dependency array
  251. #[macro_export]
  252. macro_rules! use_future {
  253. ($cx:ident, || $($rest:tt)*) => { use_future( $cx, (), |_| $($rest)* ) };
  254. ($cx:ident, | $($args:tt),* | $($rest:tt)*) => {
  255. use_future(
  256. $cx,
  257. ($($args),*),
  258. |($($args),*)| $($rest)*
  259. )
  260. };
  261. }
  262. #[cfg(test)]
  263. mod tests {
  264. use super::*;
  265. #[allow(unused)]
  266. #[test]
  267. fn test_use_future() {
  268. use dioxus_core::prelude::*;
  269. struct MyProps {
  270. a: String,
  271. b: i32,
  272. c: i32,
  273. d: i32,
  274. e: i32,
  275. }
  276. async fn app(cx: Scope<'_, MyProps>) -> Element {
  277. // should only ever run once
  278. let fut = use_future(cx, (), |_| async move {});
  279. // runs when a is changed
  280. let fut = use_future(cx, (&cx.props.a,), |(a,)| async move {});
  281. // runs when a or b is changed
  282. let fut = use_future(cx, (&cx.props.a, &cx.props.b), |(a, b)| async move { 123 });
  283. let a = use_future!(cx, || async move {
  284. // do the thing!
  285. });
  286. let b = &123;
  287. let c = &123;
  288. let a = use_future!(cx, |b, c| async move {
  289. let a = b + c;
  290. let blah = "asd";
  291. });
  292. let g2 = a.await;
  293. let g = fut.await;
  294. todo!()
  295. }
  296. }
  297. }