usecoroutine.rs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. use dioxus_core::{AnyContext, Context, Scope};
  2. use futures::Future;
  3. use std::{
  4. cell::{Cell, RefCell},
  5. pin::Pin,
  6. rc::Rc,
  7. };
  8. pub fn use_coroutine<'a, F: Future<Output = ()> + 'static>(
  9. cx: &dyn AnyContext<'a>,
  10. mut f: impl FnMut() -> F + 'a,
  11. ) -> CoroutineHandle<'a> {
  12. let cx = cx.get_scope();
  13. cx.use_hook(
  14. move |_| State {
  15. running: Default::default(),
  16. fut: Default::default(),
  17. submit: Default::default(),
  18. },
  19. |state| {
  20. let fut_slot = state.fut.clone();
  21. let running = state.running.clone();
  22. let submit: Box<dyn FnOnce() + 'a> = Box::new(move || {
  23. let g = async move {
  24. running.set(true);
  25. f().await;
  26. running.set(false);
  27. };
  28. let p: Pin<Box<dyn Future<Output = ()>>> = Box::pin(g);
  29. fut_slot
  30. .borrow_mut()
  31. .replace(unsafe { std::mem::transmute(p) });
  32. });
  33. let submit = unsafe { std::mem::transmute(submit) };
  34. state.submit.get_mut().replace(submit);
  35. if state.running.get() {
  36. let mut fut = state.fut.borrow_mut();
  37. cx.push_task(|| fut.as_mut().unwrap().as_mut());
  38. } else {
  39. // make sure to drop the old future
  40. if let Some(fut) = state.fut.borrow_mut().take() {
  41. drop(fut);
  42. }
  43. }
  44. CoroutineHandle { cx, inner: state }
  45. },
  46. )
  47. }
  48. struct State {
  49. running: Rc<Cell<bool>>,
  50. submit: RefCell<Option<Box<dyn FnOnce()>>>,
  51. fut: Rc<RefCell<Option<Pin<Box<dyn Future<Output = ()>>>>>>,
  52. }
  53. pub struct CoroutineHandle<'a> {
  54. cx: &'a Scope,
  55. inner: &'a State,
  56. }
  57. impl Clone for CoroutineHandle<'_> {
  58. fn clone(&self) -> Self {
  59. CoroutineHandle {
  60. cx: self.cx,
  61. inner: self.inner,
  62. }
  63. }
  64. }
  65. impl Copy for CoroutineHandle<'_> {}
  66. impl<'a> CoroutineHandle<'a> {
  67. pub fn start(&self) {
  68. if self.is_running() {
  69. return;
  70. }
  71. if let Some(submit) = self.inner.submit.borrow_mut().take() {
  72. submit();
  73. let mut fut = self.inner.fut.borrow_mut();
  74. self.cx.push_task(|| fut.as_mut().unwrap().as_mut());
  75. }
  76. }
  77. pub fn is_running(&self) -> bool {
  78. self.inner.running.get()
  79. }
  80. pub fn resume(&self) {}
  81. }