use bumpalo::Bump;
pub use vcomponent::VComponent;
pub use velement::VElement;
pub use velement::{Attribute, Listener, NodeKey};
pub use vnode::VNode;
pub use vtext::VText;
pub struct DomTree;
mod vnode {
use super::*;
#[derive(Debug)]
pub enum VNode<'src> {
Element(&'src VElement<'src>),
Text(VText<'src>),
Suspended,
Component(VComponent<'src>),
}
impl<'a> VNode<'a> {
#[inline]
pub fn element(
bump: &'a Bump,
key: NodeKey,
tag_name: &'a str,
listeners: &'a [Listener<'a>],
attributes: &'a [Attribute<'a>],
children: &'a [VNode<'a>],
namespace: Option<&'a str>,
) -> VNode<'a> {
let element = bump.alloc_with(|| VElement {
key,
tag_name,
listeners,
attributes,
children,
namespace,
});
VNode::Element(element)
}
#[inline]
pub fn text(text: &'a str) -> VNode<'a> {
VNode::Text(VText { text })
}
#[inline]
pub(crate) fn key(&self) -> NodeKey {
match &self {
VNode::Text(_) => NodeKey::NONE,
VNode::Element(e) => e.key,
VNode::Suspended => {
todo!()
}
VNode::Component(_) => {
todo!()
}
}
}
}
}
mod velement {
use crate::events::VirtualEvent;
use super::*;
use std::fmt::Debug;
#[derive(Debug)]
pub struct VElement<'a> {
pub key: NodeKey,
pub tag_name: &'a str,
pub listeners: &'a [Listener<'a>],
pub attributes: &'a [Attribute<'a>],
pub children: &'a [VNode<'a>],
pub namespace: Option<&'a str>,
}
impl<'a> VElement<'a> {
pub fn new(_tag: &'a str) -> Self {
todo!()
}
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct Attribute<'a> {
pub name: &'static str,
pub value: &'a str,
}
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,
}
}
}
pub struct Listener<'bump> {
pub(crate) event: &'static str,
pub(crate) callback: &'bump (dyn Fn(VirtualEvent)),
}
impl Debug for Listener<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Listener")
.field("event", &self.event)
.finish()
}
}
pub(crate) type ListenerCallback<'a> = &'a (dyn Fn(VirtualEvent));
union CallbackFatPtr<'a> {
callback: ListenerCallback<'a>,
parts: (u32, u32),
}
impl Listener<'_> {
#[inline]
pub(crate) fn get_callback_parts(&self) -> (u32, u32) {
assert_eq!(
std::mem::size_of::<ListenerCallback>(),
std::mem::size_of::<CallbackFatPtr>()
);
unsafe {
let fat = CallbackFatPtr {
callback: self.callback,
};
let (a, b) = fat.parts;
debug_assert!(a != 0);
(a, b)
}
}
}
#[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)
}
}
}
mod vtext {
#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct VText<'bump> {
pub text: &'bump str,
}
impl<'a> VText<'a> {
pub fn new(text: &'a str) -> Self
{
VText { text: text.into() }
}
}
}
mod vcomponent {
use crate::innerlude::FC;
use std::marker::PhantomData;
#[derive(Debug)]
pub struct VComponent<'src> {
_p: PhantomData<&'src ()>,
props: Box<dyn std::any::Any>,
caller: *const (),
}
impl<'a> VComponent<'a> {
pub fn new<P>(caller: FC<P>, props: P) -> Self {
let _caller = caller as *const ();
let _props = Box::new(props);
todo!()
}
}
}