nodes.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. //! Virtual Node Support
  2. //! VNodes represent lazily-constructed VDom trees that support diffing and event handlers.
  3. //!
  4. //! These VNodes should be *very* cheap and *very* fast to construct - building a full tree should be insanely quick.
  5. use std::marker::PhantomData;
  6. use bumpalo::Bump;
  7. pub use vcomponent::VComponent;
  8. pub use velement::VElement;
  9. pub use velement::{Attribute, Listener, NodeKey};
  10. pub use vnode::VNode;
  11. pub use vtext::VText;
  12. /// Tools for the base unit of the virtual dom - the VNode
  13. /// VNodes are intended to be quickly-allocated, lightweight enum values.
  14. ///
  15. /// Components will be generating a lot of these very quickly, so we want to
  16. /// limit the amount of heap allocations / overly large enum sizes.
  17. mod vnode {
  18. use super::*;
  19. pub enum VNode<'src> {
  20. /// An element node (node type `ELEMENT_NODE`).
  21. Element(VElement<'src>),
  22. /// A text node (node type `TEXT_NODE`).
  23. ///
  24. /// Note: This wraps a `VText` instead of a plain `String` in
  25. /// order to enable custom methods like `create_text_node()` on the
  26. /// wrapped type.
  27. Text(VText<'src>),
  28. /// A "suspended component"
  29. /// This is a masqeurade over an underlying future that needs to complete
  30. /// When the future is completed, the VNode will then trigger a render
  31. Suspended,
  32. /// A User-defined componen node (node type COMPONENT_NODE)
  33. Component(VComponent),
  34. }
  35. impl<'src> VNode<'src> {
  36. /// Create a new virtual element node with a given tag.
  37. ///
  38. /// These get patched into the DOM using `document.createElement`
  39. ///
  40. /// ```ignore
  41. /// let div = VNode::element("div");
  42. /// ```
  43. pub fn element(tag: &'static str) -> Self {
  44. VNode::Element(VElement::new(tag))
  45. }
  46. /// Construct a new text node with the given text.
  47. #[inline]
  48. pub(crate) fn text(text: &'src str) -> VNode<'src> {
  49. VNode::Text(VText { text })
  50. }
  51. // /// Create a new virtual text node with the given text.
  52. // ///
  53. // /// These get patched into the DOM using `document.createTextNode`
  54. // ///
  55. // /// ```ignore
  56. // /// let div = VNode::text("div");
  57. // /// ```
  58. // pub fn text<S>(text: S) -> Self
  59. // where
  60. // S: Into<String>,
  61. // {
  62. // /*
  63. // TODO
  64. // This is an opportunity to be extremely efficient when allocating/creating strings
  65. // To assemble a formatted string, we can, using the macro, borrow all the contents without allocating.
  66. // String contents are therefore bump allocated automatically
  67. // html!{
  68. // <>"Hello {world}"</>
  69. // }
  70. // Should be
  71. // ```
  72. // let mut root = VNode::text(["Hello", world]);
  73. // ```
  74. // */
  75. // VNode::Text(VText::new(text.into()))
  76. // }
  77. // /// Return a [`VElement`] reference, if this is an [`Element`] variant.
  78. // ///
  79. // /// [`VElement`]: struct.VElement.html
  80. // /// [`Element`]: enum.VNode.html#variant.Element
  81. // pub fn as_velement_ref(&self) -> Option<&VElement> {
  82. // match self {
  83. // VNode::Element(ref element_node) => Some(element_node),
  84. // _ => None,
  85. // }
  86. // }
  87. // /// Return a mutable [`VElement`] reference, if this is an [`Element`] variant.
  88. // ///
  89. // /// [`VElement`]: struct.VElement.html
  90. // /// [`Element`]: enum.VNode.html#variant.Element
  91. // pub fn as_velement_mut(&mut self) -> Option<&mut VElement> {
  92. // match self {
  93. // VNode::Element(ref mut element_node) => Some(element_node),
  94. // _ => None,
  95. // }
  96. // }
  97. // /// Return a [`VText`] reference, if this is an [`Text`] variant.
  98. // ///
  99. // /// [`VText`]: struct.VText.html
  100. // /// [`Text`]: enum.VNode.html#variant.Text
  101. // pub fn as_vtext_ref(&self) -> Option<&VText> {
  102. // match self {
  103. // VNode::Text(ref text_node) => Some(text_node),
  104. // _ => None,
  105. // }
  106. // }
  107. // /// Return a mutable [`VText`] reference, if this is an [`Text`] variant.
  108. // ///
  109. // /// [`VText`]: struct.VText.html
  110. // /// [`Text`]: enum.VNode.html#variant.Text
  111. // pub fn as_vtext_mut(&mut self) -> Option<&mut VText> {
  112. // match self {
  113. // VNode::Text(ref mut text_node) => Some(text_node),
  114. // _ => None,
  115. // }
  116. // }
  117. // /// Used by html-macro to insert space before text that is inside of a block that came after
  118. // /// an open tag.
  119. // ///
  120. // /// html! { <div> {world}</div> }
  121. // ///
  122. // /// So that we end up with <div> world</div> when we're finished parsing.
  123. // pub fn insert_space_before_text(&mut self) {
  124. // match self {
  125. // VNode::Text(text_node) => {
  126. // text_node.text = " ".to_string() + &text_node.text;
  127. // }
  128. // _ => {}
  129. // }
  130. // }
  131. // /// Used by html-macro to insert space after braced text if we know that the next block is
  132. // /// another block or a closing tag.
  133. // ///
  134. // /// html! { <div>{Hello} {world}</div> } -> <div>Hello world</div>
  135. // /// html! { <div>{Hello} </div> } -> <div>Hello </div>
  136. // ///
  137. // /// So that we end up with <div>Hello world</div> when we're finished parsing.
  138. // pub fn insert_space_after_text(&mut self) {
  139. // match self {
  140. // VNode::Text(text_node) => {
  141. // text_node.text += " ";
  142. // }
  143. // _ => {}
  144. // }
  145. // }
  146. }
  147. // -----------------------------------------------
  148. // Convert from DOM elements to the primary enum
  149. // -----------------------------------------------
  150. // impl From<VText> for VNode {
  151. // fn from(other: VText) -> Self {
  152. // VNode::Text(other)
  153. // }
  154. // }
  155. // impl From<VElement> for VNode {
  156. // fn from(other: VElement) -> Self {
  157. // VNode::Element(other)
  158. // }
  159. // }
  160. }
  161. mod velement {
  162. use super::*;
  163. use std::collections::HashMap;
  164. pub struct VElement<'a> {
  165. /// The HTML tag, such as "div"
  166. pub tag: &'a str,
  167. pub tag_name: &'a str,
  168. pub attributes: &'a [Attribute<'a>],
  169. // todo: hook up listeners
  170. // pub listeners: &'a [Listener<'a>],
  171. // / HTML attributes such as id, class, style, etc
  172. // pub attrs: HashMap<String, String>,
  173. // TODO: @JON Get this to not heap allocate, but rather borrow
  174. // pub attrs: HashMap<&'static str, &'static str>,
  175. // TODO @Jon, re-enable "events"
  176. //
  177. // /// Events that will get added to your real DOM element via `.addEventListener`
  178. // pub events: Events,
  179. // pub events: HashMap<String, ()>,
  180. // /// The children of this `VNode`. So a <div> <em></em> </div> structure would
  181. // /// have a parent div and one child, em.
  182. // pub children: Vec<VNode>,
  183. }
  184. impl<'a> VElement<'a> {
  185. // The tag of a component MUST be known at compile time
  186. pub fn new(tag: &'a str) -> Self {
  187. todo!()
  188. // VElement {
  189. // tag,
  190. // attrs: HashMap::new(),
  191. // events: HashMap::new(),
  192. // // events: Events(HashMap::new()),
  193. // children: vec![],
  194. // }
  195. }
  196. }
  197. /// An attribute on a DOM node, such as `id="my-thing"` or
  198. /// `href="https://example.com"`.
  199. #[derive(Clone, Debug)]
  200. pub struct Attribute<'a> {
  201. pub(crate) name: &'a str,
  202. pub(crate) value: &'a str,
  203. }
  204. impl<'a> Attribute<'a> {
  205. /// Get this attribute's name, such as `"id"` in `<div id="my-thing" />`.
  206. #[inline]
  207. pub fn name(&self) -> &'a str {
  208. self.name
  209. }
  210. /// The attribute value, such as `"my-thing"` in `<div id="my-thing" />`.
  211. #[inline]
  212. pub fn value(&self) -> &'a str {
  213. self.value
  214. }
  215. /// Certain attributes are considered "volatile" and can change via user
  216. /// input that we can't see when diffing against the old virtual DOM. For
  217. /// these attributes, we want to always re-set the attribute on the physical
  218. /// DOM node, even if the old and new virtual DOM nodes have the same value.
  219. #[inline]
  220. pub(crate) fn is_volatile(&self) -> bool {
  221. match self.name {
  222. "value" | "checked" | "selected" => true,
  223. _ => false,
  224. }
  225. }
  226. }
  227. /// An event listener.
  228. pub struct Listener<'a> {
  229. /// The type of event to listen for.
  230. pub(crate) event: &'a str,
  231. /// The callback to invoke when the event happens.
  232. pub(crate) callback: &'a (dyn Fn()),
  233. }
  234. /// The key for keyed children.
  235. ///
  236. /// Keys must be unique among siblings.
  237. ///
  238. /// If any sibling is keyed, then they all must be keyed.
  239. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
  240. pub struct NodeKey(pub(crate) u32);
  241. impl Default for NodeKey {
  242. fn default() -> NodeKey {
  243. NodeKey::NONE
  244. }
  245. }
  246. impl NodeKey {
  247. /// The default, lack of a key.
  248. pub const NONE: NodeKey = NodeKey(u32::MAX);
  249. /// Is this key `NodeKey::NONE`?
  250. #[inline]
  251. pub fn is_none(&self) -> bool {
  252. *self == Self::NONE
  253. }
  254. /// Is this key not `NodeKey::NONE`?
  255. #[inline]
  256. pub fn is_some(&self) -> bool {
  257. !self.is_none()
  258. }
  259. /// Create a new `NodeKey`.
  260. ///
  261. /// `key` must not be `u32::MAX`.
  262. #[inline]
  263. pub fn new(key: u32) -> Self {
  264. debug_assert_ne!(key, u32::MAX);
  265. NodeKey(key)
  266. }
  267. }
  268. // todo
  269. // use zst enum for element type. Something like ValidElements::div
  270. }
  271. mod vtext {
  272. #[derive(PartialEq)]
  273. pub struct VText<'a> {
  274. pub text: &'a str,
  275. }
  276. impl<'a> VText<'a> {
  277. // / Create an new `VText` instance with the specified text.
  278. // pub fn new<S>(text: S) -> Self
  279. // where
  280. // S: Into<String>,
  281. // {
  282. // VText { text: text.into() }
  283. // }
  284. }
  285. }
  286. /// Virtual Components for custom user-defined components
  287. /// Only supports the functional syntax
  288. mod vcomponent {
  289. use crate::virtual_dom::Properties;
  290. use std::{any::TypeId, fmt, future::Future};
  291. use super::VNode;
  292. #[derive(PartialEq)]
  293. pub struct VComponent {
  294. // props_id: TypeId,
  295. // callerIDs are unsafely coerced to function pointers
  296. // This is okay because #1, we store the props_id and verify and 2# the html! macro rejects components not made this way
  297. //
  298. // Manually constructing the VComponent is not possible from 3rd party crates
  299. }
  300. impl VComponent {
  301. // /// Construct a VComponent directly from a function component
  302. // /// This should be *very* fast - we store the function pointer and props type ID. It should also be small on the stack
  303. // pub fn from_fn<P: Properties>(f: FC<P>, props: P) -> Self {
  304. // // // Props needs to be static
  305. // // let props_id = std::any::TypeId::of::<P>();
  306. // // // Cast the caller down
  307. // // Self { props_id }
  308. // Self {}
  309. // }
  310. }
  311. }