task.rs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. use super::{waker::RcWake, Scheduler, SchedulerMsg};
  2. use crate::ScopeId;
  3. use std::cell::RefCell;
  4. use std::future::Future;
  5. use std::task::Context;
  6. use std::{pin::Pin, rc::Rc, task::Poll};
  7. #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
  8. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
  9. pub struct TaskId(pub usize);
  10. /// the task itself is the waker
  11. pub(crate) struct LocalTask {
  12. pub scope: ScopeId,
  13. id: TaskId,
  14. tx: futures_channel::mpsc::UnboundedSender<SchedulerMsg>,
  15. task: RefCell<Pin<Box<dyn Future<Output = ()> + 'static>>>,
  16. }
  17. impl LocalTask {
  18. /// Poll this task and return whether or not it is complete
  19. pub(super) fn progress(self: &Rc<Self>) -> bool {
  20. let waker = self.waker();
  21. let mut cx = Context::from_waker(&waker);
  22. match self.task.borrow_mut().as_mut().poll(&mut cx) {
  23. Poll::Ready(_) => true,
  24. _ => false,
  25. }
  26. }
  27. }
  28. impl Scheduler {
  29. /// Start a new future on the same thread as the rest of the VirtualDom.
  30. ///
  31. /// This future will not contribute to suspense resolving, so you should primarily use this for reacting to changes
  32. /// and long running tasks.
  33. ///
  34. /// Whenever the component that owns this future is dropped, the future will be dropped as well.
  35. ///
  36. /// Spawning a future onto the root scope will cause it to be dropped when the root component is dropped - which
  37. /// will only occur when the VirtuaalDom itself has been dropped.
  38. pub fn spawn(&self, scope: ScopeId, task: impl Future<Output = ()> + 'static) -> TaskId {
  39. let mut tasks = self.tasks.borrow_mut();
  40. let entry = tasks.vacant_entry();
  41. let task_id = TaskId(entry.key());
  42. entry.insert(Rc::new(LocalTask {
  43. id: task_id,
  44. tx: self.sender.clone(),
  45. task: RefCell::new(Box::pin(task)),
  46. scope,
  47. }));
  48. self.sender
  49. .unbounded_send(SchedulerMsg::TaskNotified(task_id))
  50. .expect("Scheduler should exist");
  51. task_id
  52. }
  53. /// Drop the future with the given TaskId
  54. ///
  55. /// This does nto abort the task, so you'll want to wrap it in an aborthandle if that's important to you
  56. pub fn remove(&self, id: TaskId) {
  57. self.tasks.borrow_mut().remove(id.0);
  58. }
  59. }
  60. impl RcWake for LocalTask {
  61. fn wake_by_ref(arc_self: &Rc<Self>) {
  62. _ = arc_self
  63. .tx
  64. .unbounded_send(SchedulerMsg::TaskNotified(arc_self.id));
  65. }
  66. }