use std::cell::{Cell, Ref, RefCell};
use crate::{
backend::{tree::*, Backend},
component::*,
error::Error,
node::{OwnerWeak, SlotChange, SlotKindTrait},
prop::Prop,
BackendContext,
};
pub struct TemplateInit<C> {
pub(crate) updater: ComponentWeak<C>,
}
pub trait TemplateHelper<C: ?Sized, S, L>: Default {
fn mark_dirty(&self)
where
C: 'static;
fn clear_dirty(&self) -> bool
where
C: 'static;
fn is_initialized(&self) -> bool;
fn structure(&self) -> Option<Ref<S>>;
fn slot_scopes(&self) -> Ref<L>;
fn component_rc(&self) -> Result<ComponentRc<C>, Error>
where
C: 'static + Sized;
fn component_weak(&self) -> Result<ComponentWeak<C>, Error>
where
C: 'static + Sized;
#[doc(hidden)]
fn extract_pending_slot_changes(
&self,
new_changes: Vec<SlotChange<(), ForestToken, ()>>,
) -> Vec<SlotChange<(), ForestToken, ()>>;
fn self_owner_weak(&self) -> &Box<dyn OwnerWeak>;
}
pub struct Template<C, S, L: Default> {
#[doc(hidden)]
pub __m_self_owner_weak: Option<Box<dyn OwnerWeak>>,
updater: Option<ComponentWeak<C>>,
dirty: Cell<bool>,
#[doc(hidden)]
pub __m_structure: Option<RefCell<S>>,
#[doc(hidden)]
pub __m_slot_scopes: RefCell<L>,
#[doc(hidden)]
pub __m_pending_slot_changes: Cell<Vec<SlotChange<(), ForestToken, ()>>>,
}
impl<C, S, L: Default> Default for Template<C, S, L> {
fn default() -> Self {
Self {
__m_self_owner_weak: None,
updater: None,
dirty: Cell::new(false),
__m_structure: None,
__m_slot_scopes: RefCell::new(L::default()),
__m_pending_slot_changes: Cell::new(Vec::with_capacity(0)),
}
}
}
impl<C: 'static, S, L: Default> Template<C, S, L> {
#[doc(hidden)]
#[inline]
pub fn init(&mut self, init: TemplateInit<C>) {
self.__m_self_owner_weak = Some(init.updater.to_owner_weak());
self.updater = Some(init.updater);
}
}
impl<C, S, L: Default> TemplateHelper<C, S, L> for Template<C, S, L> {
#[inline]
fn mark_dirty(&self)
where
C: 'static,
{
if self.__m_structure.is_some() {
self.dirty.set(true);
}
}
#[inline]
fn clear_dirty(&self) -> bool
where
C: 'static,
{
self.dirty.replace(false)
}
#[inline]
fn is_initialized(&self) -> bool {
self.__m_structure.is_some()
}
#[inline]
fn structure(&self) -> Option<Ref<S>> {
self.__m_structure
.as_ref()
.and_then(|x| x.try_borrow().ok())
}
#[inline]
fn slot_scopes(&self) -> Ref<L> {
self.__m_slot_scopes.borrow()
}
#[inline]
fn component_rc(&self) -> Result<ComponentRc<C>, Error>
where
C: 'static,
{
self.updater
.as_ref()
.and_then(|x| x.upgrade())
.ok_or(Error::TreeNotCreated)
}
#[inline]
fn component_weak(&self) -> Result<ComponentWeak<C>, Error>
where
C: 'static,
{
self.updater
.as_ref()
.map(|x| x.clone())
.ok_or(Error::TreeNotCreated)
}
#[inline]
fn extract_pending_slot_changes(
&self,
new_changes: Vec<SlotChange<(), ForestToken, ()>>,
) -> Vec<SlotChange<(), ForestToken, ()>> {
self.__m_pending_slot_changes.replace(new_changes)
}
#[inline]
fn self_owner_weak(&self) -> &Box<dyn OwnerWeak> {
self.__m_self_owner_weak.as_ref().unwrap()
}
}
pub trait ComponentSlotKind {
type SlotChildren<SlotContent>: SlotKindTrait<ForestTokenAddr, SlotContent>;
type SlotData: 'static;
}
pub trait ComponentTemplate<B: Backend>: ComponentSlotKind {
type TemplateField: TemplateHelper<
Self,
Self::TemplateStructure,
Self::SlotChildren<(ForestToken, Prop<Self::SlotData>)>,
>;
type TemplateStructure;
fn template(&self) -> &Self::TemplateField;
fn template_init(&mut self, init: TemplateInit<Self>)
where
Self: Sized;
fn template_create_or_update<'b>(
&'b mut self,
backend_context: &'b BackendContext<B>,
backend_element: &'b mut ForestNodeMut<B::GeneralElement>,
slot_fn: &mut dyn FnMut(
SlotChange<&mut ForestNodeMut<B::GeneralElement>, &ForestToken, &Self::SlotData>,
) -> Result<(), Error>,
) -> Result<(), Error>
where
Self: Sized;
#[inline(never)]
fn template_update_store_slot_changes<'b>(
&'b mut self,
backend_context: &'b BackendContext<B>,
backend_element: &'b mut ForestNodeMut<B::GeneralElement>,
) -> Result<bool, Error>
where
Self: Sized,
{
let mut slot_changes: Vec<SlotChange<(), ForestToken, ()>> = Vec::with_capacity(0);
self.template_create_or_update(backend_context, backend_element, &mut |slot_change| {
match slot_change {
SlotChange::Unchanged(..) => {}
SlotChange::DataChanged(_, n, _) => {
slot_changes.push(SlotChange::DataChanged((), n.clone(), ()))
}
SlotChange::Added(_, n, _) => {
slot_changes.push(SlotChange::Added((), n.clone(), ()))
}
SlotChange::Removed(n) => slot_changes.push(SlotChange::Removed(n.clone())),
}
Ok(())
})?;
if slot_changes.len() > 0 {
if self
.template()
.extract_pending_slot_changes(slot_changes)
.len()
> 0
{
Err(Error::ListChangeWrong)?;
}
Ok(true)
} else {
Ok(false)
}
}
#[inline(never)]
fn for_each_slot_scope<'b>(
&'b mut self,
backend_element: &'b mut ForestNodeMut<B::GeneralElement>,
slot_fn: &mut dyn FnMut(
SlotChange<&mut ForestNodeMut<B::GeneralElement>, &ForestToken, &Self::SlotData>,
) -> Result<(), Error>,
) -> Result<(), Error> {
for (t, d) in self.template().slot_scopes().iter() {
let n = &mut backend_element
.borrow_mut_token(t)
.ok_or(Error::TreeNodeReleased)?;
slot_fn(SlotChange::Unchanged(n, t, d))?;
}
Ok(())
}
}