pub enum Html {
Text {
text: String,
hash: u64,
},
Element {
tag: String,
attrs: Vec<(String, String)>,
key: Option<String>,
children: Vec<Arc<Html>>,
tag_key_h: u64,
attrs_h: u64,
children_h: u64,
},
}Variants§
Text
Element
Fields
children: Vec<Arc<Html>>Shared handles rather than owned subtrees, because a page is reassembled on every event and a child that did not change must cost a refcount rather than a copy.
With Vec<Html> here, child deep-copied the whole subtree it was given, at every
level — so one event rebuilding a page of n nodes copied every one of them, and the
cost compounded with nesting depth because each enclosing element copied what its
children had just copied (docs/23 §23.8, which described this as “n handles”).
tag_key_h: u64Three accumulators rather than one hash, so that the hash is a function of the node’s structure and not of the order the builder methods happened to be called in. Getting this wrong makes two identical subtrees hash differently, and a differ that trusts a hash it cannot reproduce is worse than one with no hash at all.
Implementations§
Source§impl Html
impl Html
pub fn text(s: impl Into<String>) -> Html
Sourcepub fn el(tag: impl Into<String>) -> Html
pub fn el(tag: impl Into<String>) -> Html
Start an element. Attributes and children are added with the builder methods below; each step costs one multiply per byte added, and nothing is ever rehashed.
pub fn attr(self, name: impl Into<String>, value: impl Into<String>) -> Html
Sourcepub fn attr_if(
self,
cond: bool,
name: impl Into<String>,
value: impl Into<String>,
) -> Html
pub fn attr_if( self, cond: bool, name: impl Into<String>, value: impl Into<String>, ) -> Html
Conditional attribute — the (if t.done "done" "") shape from the sketch, without emitting
an empty attribute the differ would then have to churn on.
Sourcepub fn on(self, event: &str, command: Value) -> Html
pub fn on(self, event: &str, command: Value) -> Html
A handler in view compiles to a declarative attribute — no user JavaScript exists in Mode
A (§5.1 “Input capture”), so script-src can stay near-empty. command is the serialised
command constructor the thin client posts back up the socket.
pub fn key(self, k: impl Into<String>) -> Html
pub fn child(self, c: Html) -> Html
Add a child that is already behind an Arc, which is what every page assembled from
a view has: the engine holds each child as a Value::Html and hands the same allocation to
this element. Cloning the handle is what makes reassembling a page cost its changed
nodes rather than all of them.
The hash is the child’s own, already computed when it was built, so sharing costs nothing at the differ either — an unchanged subtree still compares equal by hash without being walked.
pub fn children(self, cs: impl IntoIterator<Item = Html>) -> Html
Html::children for children that are already shared — the counterpart of
Html::child_shared, used where an element is rebuilt from the children it already had.
Sourcepub fn rehash(&self) -> Html
pub fn rehash(&self) -> Html
Rebuild the tree, recomputing every structural hash bottom-up.
Needed after in-place surgery on a node: an edit deep in a tree invalidates the hash of every ancestor, and a stale hash is worse than no hash — the differ would skip a subtree that did change.
pub fn hash(&self) -> u64
pub fn key_of(&self) -> Option<&str>
Sourcepub fn to_wire(&self) -> Value
pub fn to_wire(&self) -> Value
The wire encoding: a text node is a JSON string, an element is [tag, attrs, children].
Positional and terse because it rides in every patch. §4.4 specifies a field-tagged binary
encoding for Beck↔Beck traffic; the thin client is a browser, and JSON costs it zero bytes
of decoder — see crate::patch::Codec for the measured comparison.
Sourcepub fn render(&self) -> String
pub fn render(&self) -> String
Server-side render. “First paint is free SSR: evaluate pure view against the current
accumulator, ship HTML.”
Emitted without any inter-element whitespace, deliberately: patch paths are child indices, and a pretty-printer would insert text nodes that the server’s tree does not have, so the first patch after hydration would address the wrong node.