#![forbid(unsafe_code)]
use crate::{
create_rw_signal, create_signal, queue_microtask, store_value, ReadSignal,
RwSignal, Scope, SignalUpdate, StoredValue, WriteSignal,
};
use futures::Future;
use std::{borrow::Cow, pin::Pin};
#[derive(Copy, Clone, Debug)]
pub struct SuspenseContext {
pub pending_resources: ReadSignal<usize>,
set_pending_resources: WriteSignal<usize>,
pub(crate) pending_serializable_resources: RwSignal<usize>,
pub(crate) has_local_only: StoredValue<bool>,
}
impl SuspenseContext {
pub fn has_local_only(&self) -> bool {
self.has_local_only.get_value()
}
}
impl std::hash::Hash for SuspenseContext {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.pending_resources.id.hash(state);
}
}
impl PartialEq for SuspenseContext {
fn eq(&self, other: &Self) -> bool {
self.pending_resources.id == other.pending_resources.id
}
}
impl Eq for SuspenseContext {}
impl SuspenseContext {
pub fn new(cx: Scope) -> Self {
let (pending_resources, set_pending_resources) = create_signal(cx, 0);
let pending_serializable_resources = create_rw_signal(cx, 0);
let has_local_only = store_value(cx, true);
Self {
pending_resources,
set_pending_resources,
pending_serializable_resources,
has_local_only,
}
}
pub fn increment(&self, serializable: bool) {
let setter = self.set_pending_resources;
let serializable_resources = self.pending_serializable_resources;
let has_local_only = self.has_local_only;
queue_microtask(move || {
setter.update(|n| *n += 1);
if serializable {
serializable_resources.update(|n| *n += 1);
has_local_only.set_value(false);
}
});
}
pub fn decrement(&self, serializable: bool) {
let setter = self.set_pending_resources;
let serializable_resources = self.pending_serializable_resources;
queue_microtask(move || {
setter.update(|n| {
if *n > 0 {
*n -= 1
}
});
if serializable {
serializable_resources.update(|n| {
if *n > 0 {
*n -= 1;
}
});
}
});
}
pub fn ready(&self) -> bool {
self.pending_resources
.try_with(|n| *n == 0)
.unwrap_or(false)
}
}
pub enum StreamChunk {
Sync(Cow<'static, str>),
Async(Pin<Box<dyn Future<Output = Vec<StreamChunk>>>>),
}
impl std::fmt::Debug for StreamChunk {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StreamChunk::Sync(data) => write!(f, "StreamChunk::Sync({data:?})"),
StreamChunk::Async(_) => write!(f, "StreamChunk::Async(_)"),
}
}
}