use crate::{VirtualDom, WriteMutations, innerlude::MountId, nodes::VNode};
pub(crate) struct DiffState<'dom, 'ctx, 'writer, 'mutation> {
pub(crate) dom: &'dom mut VirtualDom,
pub(crate) to: Option<&'writer mut (dyn WriteMutations + 'mutation)>,
pub(crate) context: Option<DiffContext<'ctx>>,
}
impl<'dom, 'ctx, 'writer, 'mutation> DiffState<'dom, 'ctx, 'writer, 'mutation> {
pub(crate) fn new(
dom: &'dom mut VirtualDom,
to: Option<&'writer mut (dyn WriteMutations + 'mutation)>,
) -> Self {
Self::new_with_context(dom, to, None)
}
pub(crate) fn new_with_context(
dom: &'dom mut VirtualDom,
to: Option<&'writer mut (dyn WriteMutations + 'mutation)>,
context: Option<DiffContext<'ctx>>,
) -> Self {
Self { dom, to, context }
}
pub(crate) fn reborrow_for_mount(
&mut self,
mount: MountId,
) -> DiffState<'_, 'ctx, '_, 'mutation> {
let write = self.dom.mount_should_render(mount) && self.to.is_some();
DiffState {
dom: &mut *self.dom,
to: self.to.as_deref_mut().filter(|_| write),
context: self.context,
}
}
pub(crate) fn context(&self) -> Option<DiffContext<'ctx>> {
self.context
}
pub(crate) fn has_writer(&mut self) -> bool {
self.to.is_some()
}
pub(crate) fn replace_live_mounted_dynamic_node_slot<R>(
&mut self,
mount: MountId,
dyn_node_idx: usize,
create_new: impl FnOnce(&mut DiffState<'_, 'ctx, '_, 'mutation>) -> R,
remove_old: impl FnOnce(&mut DiffState<'_, 'ctx, '_, 'mutation>),
) -> R {
let old_slot = self
.dom
.mounted_dynamic_node_slot_snapshot(mount, dyn_node_idx);
self.replace_mounted_dynamic_node_slot(mount, dyn_node_idx, create_new, |state| {
state
.dom
.restore_mounted_dynamic_node_slot(mount, dyn_node_idx, old_slot);
remove_old(state);
})
}
pub(crate) fn replace_mounted_dynamic_node_slot<R>(
&mut self,
mount: MountId,
dyn_node_idx: usize,
create_new: impl FnOnce(&mut DiffState<'_, 'ctx, '_, 'mutation>) -> R,
before_commit_new: impl FnOnce(&mut DiffState<'_, 'ctx, '_, 'mutation>),
) -> R {
self.dom
.clear_mounted_dynamic_node_slot(mount, dyn_node_idx);
let result = create_new(self);
let new_slot = self
.dom
.mounted_dynamic_node_slot_snapshot(mount, dyn_node_idx);
before_commit_new(self);
self.dom
.restore_mounted_dynamic_node_slot(mount, dyn_node_idx, new_slot);
result
}
pub(crate) fn enter_context(&mut self, mount: MountId, old: &'ctx VNode, new: &'ctx VNode) {
let context = self.context.map_or_else(
|| DiffContext::new(mount, old, new),
|context| context.enter(mount, old, new),
);
self.context = Some(context);
}
}
#[derive(Clone, Copy)]
pub(crate) struct DiffFrame<'a> {
pub(crate) mount: MountId,
pub(crate) old: &'a VNode,
pub(crate) new: &'a VNode,
}
impl<'a> DiffFrame<'a> {
pub(crate) fn new(mount: MountId, old: &'a VNode, new: &'a VNode) -> Self {
Self { mount, old, new }
}
}
#[derive(Clone, Copy)]
pub(crate) struct DiffContext<'a> {
current: DiffFrame<'a>,
parent: Option<DiffFrame<'a>>,
}
impl<'a> DiffContext<'a> {
pub(crate) fn new(mount: MountId, old: &'a VNode, new: &'a VNode) -> Self {
Self {
current: DiffFrame { mount, old, new },
parent: None,
}
}
pub(crate) fn enter(self, mount: MountId, old: &'a VNode, new: &'a VNode) -> Self {
Self {
current: DiffFrame { mount, old, new },
parent: Some(self.current),
}
}
pub(crate) fn for_mount(self, mount: MountId) -> Option<DiffFrame<'a>> {
if self.current.mount == mount {
Some(self.current)
} else {
self.parent.filter(|frame| frame.mount == mount)
}
}
}