mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 14:44:12 +00:00
Fix borrowmut error in nested spawns
This commit is contained in:
parent
bcca307a9a
commit
728a26a2cc
5 changed files with 37 additions and 26 deletions
|
@ -27,7 +27,7 @@ pub struct Runtime {
|
|||
pub(crate) rendering: Cell<bool>,
|
||||
|
||||
/// Tasks created with cx.spawn
|
||||
pub(crate) tasks: RefCell<slab::Slab<LocalTask>>,
|
||||
pub(crate) tasks: RefCell<slab::Slab<Rc<LocalTask>>>,
|
||||
|
||||
/// Queued tasks that are waiting to be polled
|
||||
pub(crate) queued_tasks: Rc<RefCell<VecDeque<Task>>>,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::innerlude::{remove_future, spawn, Runtime};
|
||||
use crate::ScopeId;
|
||||
use futures_util::task::ArcWake;
|
||||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::Waker;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
/// A task's unique identifier.
|
||||
///
|
||||
|
@ -47,21 +47,32 @@ impl Runtime {
|
|||
/// Spawning a future onto the root scope will cause it to be dropped when the root component is dropped - which
|
||||
/// will only occur when the VirtualDom itself has been dropped.
|
||||
pub fn spawn(&self, scope: ScopeId, task: impl Future<Output = ()> + 'static) -> Task {
|
||||
let mut tasks = self.tasks.borrow_mut();
|
||||
// Insert the task, temporarily holding a borrow on the tasks map
|
||||
let (task, task_id) = {
|
||||
let mut tasks = self.tasks.borrow_mut();
|
||||
|
||||
let entry = tasks.vacant_entry();
|
||||
let task_id = Task(entry.key());
|
||||
let entry = tasks.vacant_entry();
|
||||
let task_id = Task(entry.key());
|
||||
|
||||
let task = LocalTask {
|
||||
parent: self.current_task(),
|
||||
task: RefCell::new(Box::pin(task)),
|
||||
scope,
|
||||
waker: futures_util::task::waker(Arc::new(LocalTaskHandle {
|
||||
id: task_id,
|
||||
tx: self.sender.clone(),
|
||||
})),
|
||||
let task = Rc::new(LocalTask {
|
||||
parent: self.current_task(),
|
||||
task: RefCell::new(Box::pin(task)),
|
||||
scope,
|
||||
waker: futures_util::task::waker(Arc::new(LocalTaskHandle {
|
||||
id: task_id,
|
||||
tx: self.sender.clone(),
|
||||
})),
|
||||
});
|
||||
|
||||
entry.insert(task.clone());
|
||||
|
||||
(task, task_id)
|
||||
};
|
||||
|
||||
// Get a borrow on the task, holding no borrows on the tasks map
|
||||
debug_assert!(self.tasks.try_borrow_mut().is_ok());
|
||||
debug_assert!(task.task.try_borrow_mut().is_ok());
|
||||
|
||||
let mut cx = std::task::Context::from_waker(&task.waker);
|
||||
|
||||
if !task.task.borrow_mut().as_mut().poll(&mut cx).is_ready() {
|
||||
|
@ -70,23 +81,18 @@ impl Runtime {
|
|||
.expect("Scheduler should exist");
|
||||
}
|
||||
|
||||
entry.insert(task);
|
||||
|
||||
task_id
|
||||
}
|
||||
|
||||
pub(crate) fn handle_task_wakeup(&self, id: Task) {
|
||||
let mut tasks = self.tasks.borrow_mut();
|
||||
let task = self.tasks.borrow().get(id.0).cloned();
|
||||
|
||||
let task = match tasks.get(id.0) {
|
||||
Some(task) => task,
|
||||
// The task was removed from the scheduler, so we can just ignore it
|
||||
None => return,
|
||||
// The task was removed from the scheduler, so we can just ignore it
|
||||
let Some(task) = task else {
|
||||
return;
|
||||
};
|
||||
|
||||
use std::task::Context;
|
||||
|
||||
let mut cx = Context::from_waker(&task.waker);
|
||||
let mut cx = std::task::Context::from_waker(&task.waker);
|
||||
|
||||
// update the scope stack
|
||||
self.scope_stack.borrow_mut().push(task.scope);
|
||||
|
@ -103,7 +109,7 @@ impl Runtime {
|
|||
.remove(&id);
|
||||
|
||||
// Remove it from the scheduler
|
||||
tasks.try_remove(id.0);
|
||||
self.tasks.borrow_mut().try_remove(id.0);
|
||||
}
|
||||
|
||||
// Remove the scope from the stack
|
||||
|
@ -120,7 +126,7 @@ impl Runtime {
|
|||
/// Drop the future with the given TaskId
|
||||
///
|
||||
/// This does not abort the task, so you'll want to wrap it in an abort handle if that's important to you
|
||||
pub(crate) fn remove_task(&self, id: Task) -> Option<LocalTask> {
|
||||
pub(crate) fn remove_task(&self, id: Task) -> Option<Rc<LocalTask>> {
|
||||
let task = self.tasks.borrow_mut().try_remove(id.0);
|
||||
|
||||
// Remove the task from the queued tasks so we don't poll a different task with the same id
|
||||
|
|
|
@ -138,6 +138,7 @@ impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> {
|
|||
.platform_config
|
||||
.and_then(|c| c.downcast().ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
(self.launch_fn)(app, self.contexts, *cfg)
|
||||
}
|
||||
}
|
||||
|
@ -145,12 +146,16 @@ impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> {
|
|||
mod current_platform {
|
||||
#[cfg(all(feature = "desktop", not(feature = "fullstack")))]
|
||||
pub use dioxus_desktop::launch::*;
|
||||
|
||||
#[cfg(feature = "fullstack")]
|
||||
pub use dioxus_fullstack::launch::*;
|
||||
|
||||
#[cfg(all(feature = "web", not(any(feature = "desktop", feature = "fullstack"))))]
|
||||
pub use dioxus_web::launch::*;
|
||||
|
||||
#[cfg(not(any(feature = "desktop", feature = "web", feature = "fullstack")))]
|
||||
pub type Config = ();
|
||||
|
||||
#[cfg(not(any(feature = "desktop", feature = "web", feature = "fullstack")))]
|
||||
pub fn launch(
|
||||
root: fn() -> dioxus_core::Element,
|
||||
|
|
|
@ -48,6 +48,7 @@ async fn get_server_data() -> Result<String, ServerFnError> {
|
|||
fn main() {
|
||||
#[cfg(feature = "web")]
|
||||
tracing_wasm::set_as_global_default();
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! This module contains the `launch` function, which is the main entry point for dioxus fullstack
|
||||
|
||||
use core::panic;
|
||||
use std::any::Any;
|
||||
|
||||
use dioxus_lib::prelude::{Element, VirtualDom};
|
||||
|
|
Loading…
Reference in a new issue