use crate::{cached_set::CacheId, RootRender, VdomWeak};
use bumpalo::Bump;
use std::fmt;
use std::iter;
use std::mem;
use std::u32;
#[derive(Debug, Clone)]
pub struct Node<'a> {
#[cfg(feature = "xxx-unstable-internal-use-only")]
#[doc(hidden)]
pub kind: NodeKind<'a>,
#[cfg(not(feature = "xxx-unstable-internal-use-only"))]
pub(crate) kind: NodeKind<'a>,
}
pub_unstable_internal! {
#[derive(Debug, Clone)]
pub(crate) enum NodeKind<'a> {
Text(TextNode<'a>),
Element(&'a ElementNode<'a>),
Cached(CachedNode),
}
}
pub_unstable_internal! {
#[derive(Debug, Clone)]
pub(crate) struct TextNode<'a> {
pub text: &'a str,
}
}
pub_unstable_internal! {
#[derive(Debug, Clone)]
pub(crate) struct ElementNode<'a> {
pub key: NodeKey,
pub tag_name: &'a str,
pub listeners: &'a [Listener<'a>],
pub attributes: &'a [Attribute<'a>],
pub children: &'a [Node<'a>],
pub namespace: Option<&'a str>,
}
}
pub_unstable_internal! {
#[derive(Debug, Clone, Copy)]
pub(crate) struct CachedNode {
pub id: CacheId,
pub key: NodeKey,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct NodeKey(pub(crate) u32);
impl Default for NodeKey {
fn default() -> NodeKey {
NodeKey::NONE
}
}
impl NodeKey {
pub const NONE: NodeKey = NodeKey(u32::MAX);
#[inline]
pub fn is_none(&self) -> bool {
*self == Self::NONE
}
#[inline]
pub fn is_some(&self) -> bool {
!self.is_none()
}
#[inline]
pub fn new(key: u32) -> Self {
debug_assert_ne!(key, u32::MAX);
NodeKey(key)
}
}
pub(crate) type ListenerCallback<'a> =
&'a (dyn Fn(&mut dyn RootRender, VdomWeak, web_sys::Event) + 'static);
pub struct Listener<'a> {
pub(crate) event: &'a str,
pub(crate) callback: ListenerCallback<'a>,
}
#[derive(Clone, Debug)]
pub struct Attribute<'a> {
pub(crate) name: &'a str,
pub(crate) value: &'a str,
}
impl<'a> From<CachedNode> for Node<'a> {
#[inline]
fn from(c: CachedNode) -> Self {
Node {
kind: NodeKind::Cached(c),
}
}
}
impl fmt::Debug for Listener<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (a, b) = self.get_callback_parts();
let a = a as *mut u32;
let b = b as *mut u32;
f.debug_struct("Listener")
.field("event", &self.event)
.field("callback", &(a, b))
.finish()
}
}
impl<'a> Attribute<'a> {
#[inline]
pub fn name(&self) -> &'a str {
self.name
}
#[inline]
pub fn value(&self) -> &'a str {
self.value
}
#[inline]
pub(crate) fn is_volatile(&self) -> bool {
match self.name {
"value" | "checked" | "selected" => true,
_ => false,
}
}
}
impl<'a> Node<'a> {
#[inline]
pub fn element(
bump: &'a Bump,
key: NodeKey,
tag_name: &'a str,
listeners: &'a [Listener<'a>],
attributes: &'a [Attribute<'a>],
children: &'a [Node<'a>],
namespace: Option<&'a str>,
) -> Node<'a> {
let element = bump.alloc_with(|| ElementNode {
key,
tag_name,
listeners,
attributes,
children,
namespace,
});
Node {
kind: NodeKind::Element(element),
}
}
#[inline]
pub(crate) fn text(text: &'a str) -> Node<'a> {
Node {
kind: NodeKind::Text(TextNode { text }),
}
}
#[inline]
pub(crate) fn key(&self) -> NodeKey {
match &self.kind {
NodeKind::Text(_) => NodeKey::NONE,
NodeKind::Element(e) => e.key,
NodeKind::Cached(c) => c.key,
}
}
}
impl<'a> IntoIterator for Node<'a> {
type Item = Node<'a>;
type IntoIter = iter::Once<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
iter::once(self)
}
}
union CallbackFatPtr<'a> {
callback: ListenerCallback<'a>,
parts: (u32, u32),
}
impl Listener<'_> {
#[inline]
pub(crate) fn get_callback_parts(&self) -> (u32, u32) {
assert_eq!(
mem::size_of::<ListenerCallback>(),
mem::size_of::<CallbackFatPtr>()
);
unsafe {
let fat = CallbackFatPtr {
callback: self.callback,
};
let (a, b) = fat.parts;
debug_assert!(a != 0);
(a, b)
}
}
}