mod component;
pub use component::*;
use crate::innerlude::*;
use std::{
cell::{Cell, Ref, RefCell},
fmt::Debug,
rc::Rc,
};
#[derive(Clone, PartialEq, Debug)]
pub struct SuspendedFuture {
origin: ScopeId,
task: TaskId,
}
impl SuspendedFuture {
pub fn new(task: Task) -> Self {
Self {
task: task.id,
origin: current_scope_id(),
}
}
pub fn task(&self) -> Task {
Task::from_id(self.task)
}
pub(crate) fn deep_clone(&self) -> Self {
Self {
task: self.task,
origin: self.origin,
}
}
}
impl std::fmt::Display for SuspendedFuture {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SuspendedFuture {{ task: {:?} }}", self.task)
}
}
#[derive(Debug, Clone)]
pub struct SuspenseContext {
inner: Rc<SuspenseBoundaryInner>,
}
impl PartialEq for SuspenseContext {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.inner, &other.inner)
}
}
impl SuspenseContext {
pub(crate) fn new() -> Self {
Self {
inner: Rc::new(SuspenseBoundaryInner {
rt: Runtime::current(),
suspended_tasks: RefCell::new(vec![]),
id: Cell::new(ScopeId::ROOT),
suspended_nodes: Default::default(),
frozen: Default::default(),
after_suspense_resolved: Default::default(),
}),
}
}
pub(crate) fn mount(&self, scope: ScopeId) {
self.inner.id.set(scope);
}
pub fn suspended_nodes(&self) -> Option<VNode> {
self.inner
.suspended_nodes
.borrow()
.as_ref()
.map(|node| node.clone())
}
pub(crate) fn set_suspended_nodes(&self, suspended_nodes: VNode) {
self.inner
.suspended_nodes
.borrow_mut()
.replace(suspended_nodes);
}
pub(crate) fn take_suspended_nodes(&self) -> Option<VNode> {
self.inner.suspended_nodes.borrow_mut().take()
}
pub fn frozen(&self) -> bool {
self.inner.frozen.get()
}
pub fn freeze(&self) {
self.inner.frozen.set(true);
}
pub fn has_suspended_tasks(&self) -> bool {
!self.inner.suspended_tasks.borrow().is_empty()
}
pub fn is_suspended(&self) -> bool {
self.inner.suspended_nodes.borrow().is_some()
}
pub(crate) fn add_suspended_task(&self, task: SuspendedFuture) {
self.inner.suspended_tasks.borrow_mut().push(task);
self.inner.rt.needs_update(self.inner.id.get());
}
pub(crate) fn remove_suspended_task(&self, task: Task) {
self.inner
.suspended_tasks
.borrow_mut()
.retain(|t| t.task != task.id);
self.inner.rt.needs_update(self.inner.id.get());
}
pub fn suspended_futures(&self) -> Ref<'_, [SuspendedFuture]> {
Ref::map(self.inner.suspended_tasks.borrow(), |tasks| {
tasks.as_slice()
})
}
pub fn after_suspense_resolved(&self, callback: impl FnOnce() + 'static) {
let mut closures = self.inner.after_suspense_resolved.borrow_mut();
closures.push(Box::new(callback));
}
pub(crate) fn run_resolved_closures(&self, runtime: &Runtime) {
runtime.while_not_rendering(|| {
self.inner
.after_suspense_resolved
.borrow_mut()
.drain(..)
.for_each(|f| f());
})
}
}
pub struct SuspenseBoundaryInner {
rt: Rc<Runtime>,
suspended_tasks: RefCell<Vec<SuspendedFuture>>,
id: Cell<ScopeId>,
suspended_nodes: RefCell<Option<VNode>>,
frozen: Cell<bool>,
after_suspense_resolved: RefCell<Vec<Box<dyn FnOnce()>>>,
}
impl Debug for SuspenseBoundaryInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SuspenseBoundaryInner")
.field("suspended_tasks", &self.suspended_tasks)
.field("id", &self.id)
.field("suspended_nodes", &self.suspended_nodes)
.field("frozen", &self.frozen)
.finish()
}
}