Crate lignin[−][src]
Expand description
lignin
, named after the structural polymer found in plants, is a lightweight but comprehensive VDOM data type library for use in a wider web context.
About the Documentation
DOM API terms are bold italic and linked to the MDN Web Docs. (Please file an issue if this isn’t the case somewhere.)
Implementation Contract
This is not a soundness contract. Code using this crate must not rely on it for soundness. However, it is free to panic when encountering an incorrect implementation.
Security
See also the implementation contracts on Node::Text::text
, Node::Comment::comment
and Attribute::name
.
When rendering the VDOM as HTML text, extra care must be taken to syntactically validate everything according to the specification!
HTML renderers should error rather than panic when encountering a VDOM that they can’t guarantee will be parsed as intended (assuming any syntax errors potentially cause undefined behavior somewhere).
However, renderers are free to be lenient in this regard by adjusting their output to be syntactically valid in a way that’s unlikely to cause a changed user experience. (That is: Feel free to substitute illegal character sequences in comments and such.)
Correctness
The DOM may contain extra siblings past the nodes mentioned in the VDOM. Renderers must ignore them.
Similarly, the DOM may contain extra attributes and event bindings. Renderers must ignore them unless attributes collide.
Components must clean up extra attributes and event listeners they have previous added to the DOM via the DOM API on teardown.
This simplifies renderers and allows reuse of DOM nodes between components, which in turn reduces the amount of DOM API calls necessary.
See also the implementation contracts on DomRef
and Node::Keyed
.
Performance
While the order of attributes reported by the DOM API in browsers isn’t specified and event listeners can’t be examined this way, components should stick to a relatively consistent order here and place conditional attributes and event bindings past always present ones in the respective slices.
When adding or removing Node
s dynamically between updates, components should wrap lists in Node::Multi
and otherwise insert an empty Node::Multi([&[])
as placeholder for an absent element.
Each of these suggestions allows better and easier diff optimization in renderers, but otherwise mustn’t be a strict requirement for compatibility.
Deep Comparisons
All core
comparison traits (PartialEq
, Eq
, PartialOrd
and Ord
) are implemented recursively where applicable.
Note that CallbackRef
s derived from separate instances of CallbackRegistration
are still considered distinct,
regardless of the receiver
and handler
used to make them.
However, without the "callbacks"
feature, all CallbackRef
instances are inactive and indistinct.
For shallow comparisons, access and compare fields directly or memoize parts of the GUI.
Features
"callbacks"
Enables DOM callback support. Requires std
.
Without this feature, most of the callback API is still available but stand-in types in web
are vacant and will materialize into any type.
Always test VDOM generators with the "callbacks"
feature enabled if they make use of them at all, but only depend on it in order to invoke callbacks.
Notes on Performance
Clone
Clone
is always implemented via Copy
in this crate, since none of the instances provide heap storage.
Comparisons and Hashing
As shallow hashes would easily collide for most applications where VDOM hashing comes up,
Hash
is implemented recursively in this crate and is potentially expensive.
The same applies to PartialEq
, Eq
, PartialOrd
and Ord
.
As an exception, Node::Memoized
instances are compared only by their state_key
.
Their content
is ignored for comparisons and does not factor into their hash.
lignin
does not implement hash caching by itself, so users of HashMap
or similar containers should wrap node graphs in a “HashCached<T>
” type first.
Limitations
As lignin
targets HTML and DOM rather than XML, it does not support processing instructions or CDATA sections.
For the same reason, there is formally no information about VDOM identity, which could be used to render self-referential XML documents.
In practice, it may be possible to determine identity by comparing pointers, but this would require some workarounds regarding
lignin
’s slices-of-values to be general.The implementation itself would be quite error-prone on types that are
Copy
due to implicit by-value copies there. Proceed with caution if you must!
Element and attribute names are always plain &str
s, which isn’t ideal for software that renders its GUI more directly than through a web browser.
I’m open to maintaining a generic fork if there’s interest in this regard.
with "callbacks"
feature
While the limit is relatively high at u32::MAX
, the total number of CallbackRegistration
s that can be created over the program’s lifetime is still limited¹.
For this reason, you should hold onto CallbackRegistration
instances as long a possible and avoid recreating them for each VDOM update.
However, you must not make assumptions about when the respective
callback
is invoked in relation to a component being rendered, asCallbackRef
s can legally be kept over multiple VDOM updates.
See CallbackRegistration
for storage hints.
¹ APIs exist in callback_registry
to partially or completely reset this limit, but they have additional safety requirements to the application as a whole.
without "callbacks"
feature
While the "callbacks"
feature is disabled, all callback management is erased.
This makes lignin
faster and removes all instantiation limits on CallbackRegistration
, but removes unique identities from CallbackRegistration
and CallbackRef
, which affects comparisons and hashing.
MathML support is rudimentary due lack of direct support in web-sys.
Usage Notes
Optional Tags
This is only a suggestion. Renderers should normally not depend on certain tags to be present or absent.
While HTML allows certain elements, like <body>
to be partially or entirely implied, lignin
is not granular enough to model this accurately.
Implied elements are also still present in the browser DOM, even if both their start and end tag have been omitted.
As such, these elements should normally be explicit in the VDOM. HTML renderers may omit tags from the serialised document or fragment according to the HTML specification.
Re-exports
pub use callback_registry::CallbackRef; | |
pub use callback_registry::CallbackRegistration; | |
pub use web::DomRef; | |
pub use web::Materialize; |
Modules
auto_safety | Transitive (across function boundaries) |
callback_registry | Callback registry plumbing, for renderers and app runners that support them and need to run indefinitely. |
web | Erasable web type stand-ins used as callback parameters. |
Macros
AutoSafe_alias | Mainly for use by frameworks. Canonically located at |
if_callbacks | Canonically located at |
if_not_callbacks | Canonically located at |
Structs
Attribute | |
Element |
|
ElementCreationOptions |
|
EventBinding |
|
EventBindingOptions |
|
ReorderableFragment |
|
ThreadBound |
|
ThreadSafe |
|
Enums
Node |
|
Traits
ThreadSafety | Marker trait for thread-safety tokens. |
Vdom | Marker trait for VDOM data types, which (almost) all vary by |