use crate::{ScopeId, Template, scheduler::ScopeOrder, virtual_dom::VirtualDom};
use slab::Slab;
use std::collections::HashMap;
use std::num::NonZeroUsize;
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ElementId(usize);
impl ElementId {
pub const ROOT: Self = Self(0);
pub(crate) const fn new(index: usize) -> Self {
Self(index)
}
pub(crate) const fn index(self) -> usize {
self.0
}
pub const fn from_raw(index: usize) -> Self {
Self(index)
}
pub const fn raw(self) -> usize {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct MountedElementId(NonZeroUsize);
impl MountedElementId {
pub(crate) fn new(id: ElementId) -> Self {
Self::from_index(id.index())
}
pub(crate) fn from_index(index: usize) -> Self {
Self(NonZeroUsize::new(index).expect("root id"))
}
pub(crate) fn element_id(self) -> ElementId {
ElementId::new(self.index())
}
pub(crate) fn index(self) -> usize {
self.0.get()
}
}
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct RenderTargetId(usize);
impl RenderTargetId {
pub const ROOT: Self = Self(0);
pub(crate) const fn new(index: usize) -> Self {
Self(index)
}
pub(crate) const fn index(self) -> usize {
self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum MountedDynamicNodeSlot {
Empty,
Text(MountedElementId),
Component(ScopeId),
Fragment(usize),
}
#[derive(Debug)]
pub(crate) struct RenderTargetState {
pub(crate) elements: Slab<Option<MountId>>,
pub(crate) template_roots: HashMap<(Template, usize), MountedElementId>,
}
impl RenderTargetState {
pub(crate) fn new() -> Self {
let mut elements = Slab::default();
elements.insert(None);
Self {
elements,
template_roots: HashMap::new(),
}
}
}
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct MountId(pub(crate) usize);
impl VirtualDom {
pub(crate) fn current_render_target_id(&self) -> RenderTargetId {
self.runtime.current_render_target_id()
}
pub(crate) fn next_element_in_target(&mut self, target_id: RenderTargetId) -> MountedElementId {
let mut targets = self.runtime.render_targets.borrow_mut();
let target = targets.get_mut(target_id.index()).expect("target");
MountedElementId::new(ElementId::new(target.elements.insert(None)))
}
pub(crate) fn cached_template_root(
&self,
target_id: RenderTargetId,
template: Template,
root_anchor_idx: usize,
) -> Option<MountedElementId> {
self.runtime
.render_targets
.borrow()
.get(target_id.index())
.and_then(|target| {
target
.template_roots
.get(&(template, root_anchor_idx))
.copied()
})
}
pub(crate) fn allocate_template_root(
&mut self,
target_id: RenderTargetId,
template: Template,
root_anchor_idx: usize,
) -> MountedElementId {
let mut targets = self.runtime.render_targets.borrow_mut();
let target = targets.get_mut(target_id.index()).expect("target");
let id = MountedElementId::new(ElementId::new(target.elements.insert(None)));
target
.template_roots
.insert((template, root_anchor_idx), id);
id
}
pub(crate) fn set_element_ref_for_mount(&self, mount: MountId, el: MountedElementId) {
let target_id = self.mount_target_id(mount);
let mut targets = self.runtime.render_targets.borrow_mut();
let target = targets.get_mut(target_id.index()).expect("target");
let element = target.elements.get_mut(el.index()).expect("element");
*element = Some(mount);
}
pub(crate) fn reclaim_for_mount(&mut self, mount: MountId, el: MountedElementId) {
let target_id = self.mount_target_id(mount);
let mut targets = self.runtime.render_targets.borrow_mut();
let target = targets
.get_mut(target_id.index())
.expect("reclaim target must still be registered");
target.elements.try_remove(el.index());
}
pub(crate) fn drop_scope(&mut self, id: ScopeId) {
let height = {
let scope = self.scopes.remove(id.index());
let context = scope.state();
context.height
};
self.dirty_scopes.remove(&ScopeOrder::new(height, id));
self.resolved_scopes.retain(|s| s != &id);
}
}