use crate::*;
impl PartialEq for TextNode {
fn eq(&self, other: &Self) -> bool {
self.get_content() == other.get_content()
}
}
impl<T: Clone> Clone for VirtualNode<T> {
fn clone(&self) -> Self {
match self {
Self::Element {
tag,
attributes,
children,
key,
props,
} => Self::Element {
tag: tag.clone(),
attributes: attributes.clone(),
children: children.clone(),
key: key.clone(),
props: props.clone(),
},
Self::Text(text_node) => Self::Text(text_node.clone()),
Self::Fragment(children) => Self::Fragment(children.clone()),
Self::Dynamic(dynamic_node) => Self::Dynamic(dynamic_node.clone()),
Self::Empty => Self::Empty,
}
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for VirtualNode<T> {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Element {
tag,
attributes,
children,
key,
props,
} => formatter
.debug_struct("Element")
.field("tag", tag)
.field("attributes", attributes)
.field("children", children)
.field("key", key)
.field("props", props)
.finish(),
Self::Text(text_node) => formatter.debug_tuple("Text").field(text_node).finish(),
Self::Fragment(children) => formatter.debug_tuple("Fragment").field(children).finish(),
Self::Dynamic(_) => formatter.debug_tuple("Dynamic").finish(),
Self::Empty => formatter.debug_tuple("Empty").finish(),
}
}
}
impl<T> Default for VirtualNode<T> {
fn default() -> Self {
Self::Empty
}
}
impl<T: PartialEq> PartialEq for VirtualNode<T> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(VirtualNode::Text(old_text), VirtualNode::Text(new_text)) => old_text == new_text,
(
VirtualNode::Element {
tag: old_tag,
attributes: old_attrs,
children: old_children,
props: old_props,
..
},
VirtualNode::Element {
tag: new_tag,
attributes: new_attrs,
children: new_children,
props: new_props,
..
},
) => {
old_tag == new_tag
&& old_attrs.len() == new_attrs.len()
&& old_attrs.iter().zip(new_attrs.iter()).all(
|(old_attr, new_attr): (&AttributeEntry, &AttributeEntry)| {
old_attr == new_attr
},
)
&& old_children.len() == new_children.len()
&& old_children.iter().zip(new_children.iter()).all(
|(old_child, new_child): (&VirtualNode, &VirtualNode)| {
old_child == new_child
},
)
&& old_props == new_props
}
(VirtualNode::Fragment(old_children), VirtualNode::Fragment(new_children)) => {
old_children.len() == new_children.len()
&& old_children.iter().zip(new_children.iter()).all(
|(old_child, new_child): (&VirtualNode, &VirtualNode)| {
old_child == new_child
},
)
}
(VirtualNode::Dynamic(_), VirtualNode::Dynamic(_)) => false,
(VirtualNode::Empty, VirtualNode::Empty) => true,
_ => false,
}
}
}
impl Default for DynamicNode {
fn default() -> Self {
let render_fn_inner: Rc<RefCell<RenderFnInner>> =
Rc::new(RefCell::new(RenderFnInner::new(Box::new(|| {
VirtualNode::Empty
}))));
Self::new(render_fn_inner, HookContext::default())
}
}
impl Clone for DynamicNode {
fn clone(&self) -> Self {
let cloned: Self = Self::new(
self.get_render_fn().clone(),
self.get_hook_context().clone(),
);
cloned
}
}
impl DynamicNode {
pub(crate) fn get_hook_context_value(&self) -> HookContext {
self.get_hook_context().clone()
}
pub fn render(&self) -> VirtualNode {
let mut inner: RefMut<RenderFnInner> = self.get_render_fn().borrow_mut();
(inner.get_mut_render_fn())()
}
}
impl<T> VirtualNode<T> {
pub fn try_get_tag_name(&self) -> Option<String> {
match self {
Self::Element { tag, .. } => match tag {
Tag::Element(name) => Some(name.clone()),
Tag::Component(name) => Some(name.clone()),
},
_ => None,
}
}
pub fn try_get_children(&self) -> Option<&Vec<VirtualNode>> {
match self {
Self::Element { children, .. } => Some(children),
Self::Fragment(children) => Some(children),
_ => None,
}
}
pub fn has_children(&self) -> bool {
self.try_get_children()
.is_some_and(|children: &Vec<VirtualNode>| !children.is_empty())
}
pub fn try_get_props(&self) -> Option<&T> {
match self {
Self::Element { props, .. } => props.as_deref(),
_ => None,
}
}
pub fn try_take_props(&mut self) -> Option<T> {
match self {
Self::Element { props, .. } => props.take().map(|boxed: Box<T>| *boxed),
_ => None,
}
}
pub fn take_children(&mut self) -> VirtualNode {
match self {
Self::Element { children, .. } => {
let taken: Vec<VirtualNode> = take(children);
match taken.len() {
0 => VirtualNode::Empty,
1 => taken.into_iter().next().unwrap_or(VirtualNode::Empty),
_ => VirtualNode::Fragment(taken),
}
}
Self::Fragment(children) => {
let taken: Vec<VirtualNode> = take(children);
match taken.len() {
0 => VirtualNode::Empty,
1 => taken.into_iter().next().unwrap_or(VirtualNode::Empty),
_ => VirtualNode::Fragment(taken),
}
}
_ => VirtualNode::Empty,
}
}
}
impl VirtualNode<()> {
pub fn create_dynamic<F>(mut render_fn: F) -> Self
where
F: FnMut() -> Self + 'static,
{
let hook_context: HookContext = create_hook_context();
let mut hook_context_for_closure: HookContext = hook_context.clone();
let inner: Rc<RefCell<RenderFnInner>> =
Rc::new(RefCell::new(RenderFnInner::new(Box::new(move || {
hook_context_for_closure.reset_hook_index();
render_fn()
}))));
let dynamic_node: DynamicNode = DynamicNode::new(inner, hook_context);
Self::Dynamic(dynamic_node)
}
pub fn create_dynamic_with_context<F>(mut render_fn: F) -> Self
where
F: FnMut(&mut HookContext) -> Self + 'static,
{
let hook_context: HookContext = create_hook_context();
let mut hook_context_for_closure: HookContext = hook_context.clone();
let inner: Rc<RefCell<RenderFnInner>> =
Rc::new(RefCell::new(RenderFnInner::new(Box::new(move || {
hook_context_for_closure.reset_hook_index();
render_fn(&mut hook_context_for_closure)
}))));
let dynamic_node: DynamicNode = DynamicNode::new(inner, hook_context);
Self::Dynamic(dynamic_node)
}
}