1use crate::{cached_set::CacheId, RootRender, VdomWeak};
11 #[cfg(feature = "xxx-unstable-internal-use-only")]
13 pub kind: NodeKind<'a>,
15 #[cfg(not(feature = "xxx-unstable-internal-use-only"))]
16 pub(crate) kind: NodeKind<'a>,
19pub_unstable_internal! {
20 /// A node is either a text node or an element.
21 #[derive(Debug, Clone)]
22 pub(crate) enum NodeKind<'a> {
26 /// An element potentially with attributes and children.
27 Element(&'a ElementNode<'a>),
29 /// A node in the vdom's `CachedSet`. This allows us to avoid
30 /// re-rendering and re-diffing subtrees.
35pub_unstable_internal! {
36 /// Text nodes are just a string of text. They cannot have attributes or
38 #[derive(Debug, Clone)]
39 pub(crate) struct TextNode<'a> {
44pub_unstable_internal! {
45 /// Elements have a tag name, zero or more attributes, and zero or more
47 #[derive(Debug, Clone)]
48 pub(crate) struct ElementNode<'a> {
50 pub tag_name: &'a str,
51 pub listeners: &'a [Listener<'a>],
52 pub attributes: &'a [Attribute<'a>],
53 pub children: &'a [Node<'a>],
54 pub namespace: Option<&'a str>,
58pub_unstable_internal! {
59 /// A cached node exists in an arena that is internal to the `Vdom`. It
60 /// allows us to avoid both re-rendering a sub-tree and re-diffing
61 /// it. `CachedNode`s cannot contain cycles, since they can only contain
62 /// other `CachedNode`s that already exist when they are being constructed.
63 #[derive(Debug, Clone, Copy)]
64 pub(crate) struct CachedNode {
66 // Always a copy of the inner cached node's key.
71/// The key for keyed children.
73/// Keys must be unique among siblings.
75/// If any sibling is keyed, then they all must be keyed.
76#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
77pub struct NodeKey(pub(crate) u32);
79impl Default for NodeKey {
80 fn default() -> NodeKey {
86 /// The default, lack of a key.
87 pub const NONE: NodeKey = NodeKey(u32::MAX);
89 /// Is this key `NodeKey::NONE`?
91 pub fn is_none(&self) -> bool {
95 /// Is this key not `NodeKey::NONE`?
97 pub fn is_some(&self) -> bool {
101 /// Create a new `NodeKey`.
103 /// `key` must not be `u32::MAX`.
105 pub fn new(key: u32) -> Self {
106 debug_assert_ne!(key, u32::MAX);
111/// An event listener callback function.
113/// It takes three parameters:
115/// 1. The virtual DOM's root rendering component.
116/// 2. A capability to scheduler virtual DOM re-rendering.
117/// 3. The event that occurred.
118pub(crate) type ListenerCallback<'a> =
119 &'a (dyn Fn(&mut dyn RootRender, VdomWeak, web_sys::Event) + 'static);
121/// An event listener.
122pub struct Listener<'a> {
123 /// The type of event to listen for.
124 pub(crate) event: &'a str,
125 /// The callback to invoke when the event happens.
126 pub(crate) callback: ListenerCallback<'a>,
129/// An attribute on a DOM node, such as `id="my-thing"` or
130/// `href="https://example.com"`.
131#[derive(Clone, Debug)]
132pub struct Attribute<'a> {
133 pub(crate) name: &'a str,
134 pub(crate) value: &'a str,
137impl<'a> From<CachedNode> for Node<'a> {
139 fn from(c: CachedNode) -> Self {
141 kind: NodeKind::Cached(c),
146impl fmt::Debug for Listener<'_> {
147 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148 let (a, b) = self.get_callback_parts();
149 let a = a as *mut u32;
150 let b = b as *mut u32;
151 f.debug_struct("Listener")
152 .field("event", &self.event)
153 .field("callback", &(a, b))
158impl<'a> Attribute<'a> {
159 /// Get this attribute's name, such as `"id"` in `<div id="my-thing" />`.
161 pub fn name(&self) -> &'a str {
165 /// The attribute value, such as `"my-thing"` in `<div id="my-thing" />`.
167 pub fn value(&self) -> &'a str {
171 /// Certain attributes are considered "volatile" and can change via user
172 /// input that we can't see when diffing against the old virtual DOM. For
173 /// these attributes, we want to always re-set the attribute on the physical
174 /// DOM node, even if the old and new virtual DOM nodes have the same value.
176 pub(crate) fn is_volatile(&self) -> bool {
178 "value" | "checked" | "selected" => true,
185 /// Low-level constructor for making a new `Node` of type element with given
188 /// This is primarily intended for JSX and templating proc-macros to compile
189 /// down into. If you are building nodes by-hand, prefer using the
190 /// `dodrio::builder::*` APIs.
196 listeners: &'a [Listener<'a>],
197 attributes: &'a [Attribute<'a>],
198 children: &'a [Node<'a>],
199 namespace: Option<&'a str>,
201 let element = bump.alloc_with(|| ElementNode {
211 kind: NodeKind::Element(element),
215 /// Construct a new text node with the given text.
217 pub(crate) fn text(text: &'a str) -> Node<'a> {
219 kind: NodeKind::Text(TextNode { text }),
224 pub(crate) fn key(&self) -> NodeKey {
226 NodeKind::Text(_) => NodeKey::NONE,
227 NodeKind::Element(e) => e.key,
228 NodeKind::Cached(c) => c.key,
233/// A node can become an iterator that yields the node itself once.
235/// This implementation of `IntoIterator` mostly exists to improve the
236/// `typed-html` ergonomics, where the macro invokes `.into_iter()` on the child
237/// contents of a tag. By implementing `IntoIterator` here, we avoid having to
238/// do nasty shenanigans like `<p>vec![$contents]</p>` instead of plain old
239/// `<p>$contents</p>`.
240impl<'a> IntoIterator for Node<'a> {
241 type Item = Node<'a>;
242 type IntoIter = iter::Once<Self::Item>;
244 fn into_iter(self) -> Self::IntoIter {
249union CallbackFatPtr<'a> {
250 callback: ListenerCallback<'a>,
256 pub(crate) fn get_callback_parts(&self) -> (u32, u32) {
258 mem::size_of::<ListenerCallback>(),
259 mem::size_of::<CallbackFatPtr>()
263 let fat = CallbackFatPtr {
264 callback: self.callback,
266 let (a, b) = fat.parts;
267 debug_assert!(a != 0);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list