pub struct Tag {
pub name: String,
pub attributes: IndexMap<String, RenderableTreeNodes>,
pub children: Vec<RenderableTreeNode>,
}Expand description
An element in a renderable tree.
Mirrors upstream src/tag.ts. The name is what a renderer emits – p,
article, or whatever a schema’s render said – and it is a plain string
rather than an HTML element type, because this crate decides no HTML policy.
A host rendering to something that is not HTML puts its own names here.
§Why an attribute holds a whole subtree
Upstream types attributes as Record<string, any> and means it: an ordinary
attribute is a scalar, but a rendered slot is put in the attribute map as the
transformed nodes of that slot (transformer.ts, attributes). The
corpus fixes this – “Basic slot” expects attributes: {bar: [{tag: p, ...}]}
– so narrowing attributes to Scalar would fail cases that are otherwise
correct. RenderableTreeNodes is the honest type, and a scalar attribute
is One(Scalar(..)).
Fields§
§name: StringThe element name. Upstream defaults it to div.
attributes: IndexMap<String, RenderableTreeNodes>The attributes, in authored order.
children: Vec<RenderableTreeNode>The children, in document order.
Implementations§
Source§impl Tag
impl Tag
Sourcepub fn with(
name: impl Into<String>,
attributes: IndexMap<String, RenderableTreeNodes>,
children: Vec<RenderableTreeNode>,
) -> Tag
pub fn with( name: impl Into<String>, attributes: IndexMap<String, RenderableTreeNodes>, children: Vec<RenderableTreeNode>, ) -> Tag
A tag with attributes and children.
The argument order is upstream’s new Tag(name, attributes, children),
so a ported test reads next to the TypeScript it came from.
Sourcepub fn set(
&mut self,
name: impl Into<String>,
value: impl Into<RenderableTreeNodes>,
)
pub fn set( &mut self, name: impl Into<String>, value: impl Into<RenderableTreeNodes>, )
Set an attribute to a single value, in authored order.
Sourcepub fn push(&mut self, child: RenderableTreeNode)
pub fn push(&mut self, child: RenderableTreeNode)
Append a child.
Trait Implementations§
Source§impl Clone for Tag
impl Clone for Tag
RenderableTreeNode and RenderableTreeNodes keep their derives, and
that is safe because these exist: their recursion reaches a Tag or a
Scalar in one step, and both stop there. Nothing here may call those
derives on a nested tag, which is why the walks decompose them by hand.
Source§impl Drop for Tag
Dropping a renderable tree is iterative, for the reason dropping an AST is.
impl Drop for Tag
Dropping a renderable tree is iterative, for the reason dropping an AST is.
Node carries a manual Drop because nesting depth is
attacker-controlled and the derived recursive drop aborts the process on a
deep document. A renderable tree is built from that AST, one tag per
nested tag, so it inherits the same exposure and needs the same guard. An
abort cannot be caught, so the crate’s panic-freedom promise is not true
without it.
One Drop covers the whole tree. A RenderableTreeNode and a
RenderableTreeNodes are shallow wrappers whose derived drops recurse
exactly one level before reaching a Tag, and this implementation unlinks
every descendant onto the heap before any of them is dropped – so each tag
it drops is already empty and recurses no further. Putting a manual Drop
on the enums instead would forbid moving a tag out of one, which is what
a renderer does on every node.
Scalar carries its own guard, below, for a different reason: its nesting
is bounded for values this crate builds and unbounded for values a caller
builds.
The cost, stated because it is invisible until someone hits it: a type with a
manual Drop cannot have a field moved out of it, so taking ownership of
Tag::children needs std::mem::take rather than a partial move. That
is the same tax Node charges, paid for the same reason.