Turn NodeData into an enum with variants for Element and Text

pub enum NodeData {
    Element(Element),
    Text(NodeChars),
}

The old NodeData is now Element.

This will let us box the Element, so that it takes as little space as
possible for the enum when it has a NodeData::Text value.

To make this easier for the rest of the code, now there is a
NodeBorrow trait, implemented for RsvgNode and imported pretty much
everywhere, with the following methods:

pub trait NodeBorrow {
    /// Returns `false` for NodeData::Text, `true` otherwise.
    fn is_element(&self) -> bool;

    /// Borrows a `NodeChars` reference.
    ///
    /// Panics: will panic if `&self` is not a `NodeData::Text` node
    fn borrow_chars(&self) -> Ref<NodeChars>;

    /// Borrows an `Element` reference
    ///
    /// Panics: will panic if `&self` is not a `NodeData::Element` node
    fn borrow_element(&self) -> Ref<Element>;

    /// Borrows an `Element` reference mutably
    ///
    /// Panics: will panic if `&self` is not a `NodeData::Element` node
    fn borrow_element_mut(&mut self) -> RefMut<Element>;
}

So, instead of doing node.borrow() -> Ref<NodeData>, we now can do
node.borrow_element() directly, for example.

The calling code is still supposed to first ensure that a node
is_element() or not, just like it was doing
`get_type() == NodeType::Foo` before doing get_impl::<Foo>().
parent 057d22fe
......@@ -92,7 +92,7 @@ use url::Url;
use crate::allowed_url::AllowedUrl;
use crate::error::*;
use crate::io::{self, BinaryData};
use crate::node::{NodeCascade, NodeType, RsvgNode};
use crate::node::{NodeBorrow, NodeCascade, NodeType, RsvgNode};
use crate::properties::{parse_property, ComputedValues, ParsedProperty};
/// A parsed CSS declaration
......@@ -450,17 +450,17 @@ impl selectors::Element for RsvgElement {
}
fn has_local_name(&self, local_name: &LocalName) -> bool {
self.0.borrow().element_name().local == *local_name
self.0.borrow_element().element_name().local == *local_name
}
/// Empty string for no namespace
fn has_namespace(&self, ns: &Namespace) -> bool {
self.0.borrow().element_name().ns == *ns
self.0.borrow_element().element_name().ns == *ns
}
/// Whether this element and the `other` element have the same local name and namespace.
fn is_same_type(&self, other: &Self) -> bool {
self.0.borrow().element_name() == other.0.borrow().element_name()
self.0.borrow_element().element_name() == other.0.borrow_element().element_name()
}
fn attr_matches(
......@@ -508,7 +508,7 @@ impl selectors::Element for RsvgElement {
fn has_id(&self, id: &LocalName, case_sensitivity: CaseSensitivity) -> bool {
self.0
.borrow()
.borrow_element()
.get_id()
.map(|self_id| case_sensitivity.eq(self_id.as_bytes(), id.as_ref().as_bytes()))
.unwrap_or(false)
......@@ -516,7 +516,7 @@ impl selectors::Element for RsvgElement {
fn has_class(&self, name: &LocalName, case_sensitivity: CaseSensitivity) -> bool {
self.0
.borrow()
.borrow_element()
.get_class()
.map(|classes| {
classes
......@@ -548,8 +548,7 @@ impl selectors::Element for RsvgElement {
fn is_empty(&self) -> bool {
!self.0.has_children()
|| self.0.children().all(|child| {
child.borrow().get_type() == NodeType::Chars
&& child.borrow().get_chars().is_empty()
child.borrow().get_type() == NodeType::Chars && child.borrow_chars().is_empty()
})
}
......@@ -736,7 +735,7 @@ impl Stylesheet {
/// Runs the CSS cascade on the specified tree from all the stylesheets
pub fn cascade(root: &mut RsvgNode, stylesheets: &[Stylesheet], extra: &[Stylesheet]) {
for mut node in root.descendants() {
for mut node in root.descendants().filter(|n| n.is_element()) {
let mut matches = Vec::new();
let mut match_ctx = MatchingContext::new(
......@@ -755,10 +754,11 @@ pub fn cascade(root: &mut RsvgNode, stylesheets: &[Stylesheet], extra: &[Stylesh
matches.as_mut_slice().sort();
for m in matches {
node.borrow_mut().apply_style_declaration(m.declaration);
node.borrow_element_mut()
.apply_style_declaration(m.declaration);
}
node.borrow_mut().set_style_attribute();
node.borrow_element_mut().set_style_attribute();
}
let values = ComputedValues::default();
......
......@@ -14,7 +14,7 @@ use crate::error::{AcquireError, LoadingError};
use crate::handle::LoadOptions;
use crate::io::{self, BinaryData};
use crate::limits;
use crate::node::{NodeData, NodeType, RsvgNode};
use crate::node::{NodeBorrow, NodeData, NodeType, RsvgNode};
use crate::property_bag::PropertyBag;
use crate::structure::{IntrinsicDimensions, Svg};
use crate::surface_utils::shared_surface::SharedImageSurface;
......@@ -95,10 +95,10 @@ impl Document {
/// Gets the dimension parameters of the toplevel `<svg>`.
pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
let root = self.root();
let node_data = root.borrow();
let elt = root.borrow_element();
assert!(node_data.get_type() == NodeType::Svg);
node_data.get_impl::<Svg>().get_intrinsic_dimensions()
assert!(elt.get_type() == NodeType::Svg);
elt.get_impl::<Svg>().get_intrinsic_dimensions()
}
/// Runs the CSS cascade on the document tree
......@@ -434,15 +434,18 @@ impl DocumentBuilder {
) -> RsvgNode {
let mut node = create_node(name, pbag);
if let Some(id) = node.borrow().get_id() {
if let Some(id) = node.borrow_element().get_id() {
// This is so we don't overwrite an existing id
self.ids
.entry(id.to_string())
.or_insert_with(|| node.clone());
}
node.borrow_mut()
.set_atts(parent.as_ref().clone(), pbag, self.load_options.locale());
node.borrow_element_mut().set_atts(
parent.as_ref().clone(),
pbag,
self.load_options.locale(),
);
if let Some(mut parent) = parent {
parent.append(node.clone());
......@@ -484,7 +487,7 @@ impl DocumentBuilder {
child
};
chars_node.borrow().get_chars().append(text);
chars_node.borrow_chars().append(text);
}
pub fn resolve_href(&self, href: &str) -> Result<AllowedUrl, AllowedUrlError> {
......
......@@ -18,7 +18,7 @@ use crate::error::{AcquireError, RenderingError};
use crate::filters;
use crate::gradient::{LinearGradient, RadialGradient};
use crate::marker;
use crate::node::{CascadedValues, NodeDraw, NodeType, RsvgNode};
use crate::node::{CascadedValues, NodeBorrow, NodeDraw, NodeType, RsvgNode};
use crate::paint_server::{PaintServer, PaintSource};
use crate::path_builder::*;
use crate::pattern::Pattern;
......@@ -318,7 +318,7 @@ impl DrawingCtx {
bbox: &BoundingBox,
) -> Result<(), RenderingError> {
if let Some(node) = clip_node {
let units = node.borrow().get_impl::<ClipPath>().get_units();
let units = node.borrow_element().get_impl::<ClipPath>().get_units();
if units == CoordUnits::ObjectBoundingBox && bbox.rect.is_none() {
// The node being clipped is empty / doesn't have a
......@@ -397,7 +397,7 @@ impl DrawingCtx {
};
let mask_transform = mask_node
.borrow()
.borrow_element()
.get_transform()
.post_transform(&transform);
......@@ -576,7 +576,7 @@ impl DrawingCtx {
res = res.and_then(|bbox| {
dc.generate_cairo_mask(
&mask_node.borrow().get_impl::<Mask>(),
&mask_node.borrow_element().get_impl::<Mask>(),
&mask_node,
affines.for_temporary_surface,
&bbox,
......@@ -742,7 +742,7 @@ impl DrawingCtx {
Ok(acquired) => {
let filter_node = acquired.get();
if !filter_node.borrow().is_in_error() {
if !filter_node.borrow_element().is_in_error() {
// FIXME: deal with out of memory here
filters::render(
&filter_node,
......@@ -816,7 +816,7 @@ impl DrawingCtx {
had_paint_server = match node.borrow().get_type() {
NodeType::LinearGradient => node
.borrow()
.borrow_element()
.get_impl::<LinearGradient>()
.resolve_fallbacks_and_set_pattern(
&node,
......@@ -826,7 +826,7 @@ impl DrawingCtx {
bbox,
)?,
NodeType::RadialGradient => node
.borrow()
.borrow_element()
.get_impl::<RadialGradient>()
.resolve_fallbacks_and_set_pattern(
&node,
......@@ -836,7 +836,7 @@ impl DrawingCtx {
bbox,
)?,
NodeType::Pattern => node
.borrow()
.borrow_element()
.get_impl::<Pattern>()
.resolve_fallbacks_and_set_pattern(
&node,
......@@ -1112,8 +1112,8 @@ impl DrawingCtx {
cascaded: &CascadedValues<'_>,
clipping: bool,
) -> Result<BoundingBox, RenderingError> {
let node_data = node.borrow();
let use_ = node_data.get_impl::<Use>();
let elt = node.borrow_element();
let use_ = elt.get_impl::<Use>();
// <use> is an element that is used directly, unlike
// <pattern>, which is used through a fill="url(#...)"
......@@ -1181,11 +1181,11 @@ impl DrawingCtx {
)
})
} else {
let node_data = child.borrow();
let symbol = node_data.get_impl::<Symbol>();
let elt = child.borrow_element();
let symbol = elt.get_impl::<Symbol>();
let clip_mode = if !values.is_overflow()
|| (values.overflow == Overflow::Visible && child.borrow().is_overflow())
|| (values.overflow == Overflow::Visible && child.borrow_element().is_overflow())
{
Some(ClipMode::ClipToVbox)
} else {
......@@ -1270,7 +1270,10 @@ fn get_clip_in_user_and_object_space(
.and_then(|acquired| {
let clip_node = acquired.get().clone();
let units = clip_node.borrow().get_impl::<ClipPath>().get_units();
let units = clip_node
.borrow_element()
.get_impl::<ClipPath>()
.get_units();
match units {
CoordUnits::UserSpaceOnUse => Some((Some(clip_node), None)),
......
......@@ -6,7 +6,7 @@ use markup5ever::{expanded_name, local_name, namespace_url, ns};
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::node::{NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::number_list::{NumberList, NumberListLength};
use crate::parsers::{Parse, ParseValue};
use crate::property_bag::PropertyBag;
......@@ -257,7 +257,7 @@ macro_rules! func_or_default {
($func_node:ident, $func_type:ty, $func_data:ident, $func_default:ident) => {
match $func_node {
Some(ref f) => {
$func_data = f.borrow();
$func_data = f.borrow_element();
$func_data.get_impl::<$func_type>()
}
_ => &$func_default,
......@@ -295,7 +295,7 @@ impl FilterEffect for FeComponentTransfer {
node.children()
.rev()
.filter(|c| c.borrow().get_type() == node_type)
.find(|c| c.borrow().get_impl::<F>().channel() == channel)
.find(|c| c.borrow_element().get_impl::<F>().channel() == channel)
};
let func_r_node = get_node::<FeFuncR>(node, NodeType::FeFuncR, Channel::R);
......@@ -307,7 +307,7 @@ impl FilterEffect for FeComponentTransfer {
.iter()
.filter_map(|x| x.as_ref())
{
if node.borrow().is_in_error() {
if node.borrow_element().is_in_error() {
return Err(FilterError::ChildNodeInError);
}
}
......@@ -319,15 +319,15 @@ impl FilterEffect for FeComponentTransfer {
let func_a_default = FeFuncA::default();
// We need to tell the borrow checker that these live long enough
let func_r_data;
let func_g_data;
let func_b_data;
let func_a_data;
let func_r = func_or_default!(func_r_node, FeFuncR, func_r_data, func_r_default);
let func_g = func_or_default!(func_g_node, FeFuncG, func_g_data, func_g_default);
let func_b = func_or_default!(func_b_node, FeFuncB, func_b_data, func_b_default);
let func_a = func_or_default!(func_a_node, FeFuncA, func_a_data, func_a_default);
let func_r_element;
let func_g_element;
let func_b_element;
let func_a_element;
let func_r = func_or_default!(func_r_node, FeFuncR, func_r_element, func_r_default);
let func_g = func_or_default!(func_g_node, FeFuncG, func_g_element, func_g_default);
let func_b = func_or_default!(func_b_node, FeFuncB, func_b_element, func_b_default);
let func_a = func_or_default!(func_a_node, FeFuncA, func_a_element, func_a_default);
#[inline]
fn compute_func<'a, F>(func: &'a F) -> impl Fn(u8, f64, f64) -> u8 + 'a
......
......@@ -7,7 +7,7 @@ use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::filter::Filter;
use crate::node::RsvgNode;
use crate::node::{NodeBorrow, RsvgNode};
use crate::paint_server::PaintServer;
use crate::properties::ComputedValues;
use crate::rect::IRect;
......@@ -111,8 +111,8 @@ impl FilterContext {
// However, with userSpaceOnUse it's still possible to create images with a filter.
let bbox_rect = node_bbox.rect.unwrap_or_default();
let node_data = filter_node.borrow();
let filter = node_data.get_impl::<Filter>();
let elt = filter_node.borrow_element();
let filter = elt.get_impl::<Filter>();
let affine = match filter.get_filter_units() {
CoordUnits::UserSpaceOnUse => draw_transform,
......@@ -256,8 +256,8 @@ impl FilterContext {
/// Pushes the viewport size based on the value of `primitiveUnits`.
pub fn get_view_params(&self, draw_ctx: &mut DrawingCtx) -> ViewParams {
let node_data = self.node.borrow();
let filter = node_data.get_impl::<Filter>();
let elt = self.node.borrow_element();
let filter = elt.get_impl::<Filter>();
// See comments in compute_effects_region() for how this works.
if filter.get_primitive_units() == CoordUnits::ObjectBoundingBox {
......
......@@ -18,7 +18,7 @@ use crate::filters::{
},
FilterEffect, FilterError, PrimitiveWithInput,
};
use crate::node::{CascadedValues, NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::node::{CascadedValues, NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::parsers::{NumberOptionalNumber, ParseValue};
use crate::property_bag::PropertyBag;
use crate::surface_utils::{
......@@ -504,14 +504,23 @@ fn find_light_source(node: &RsvgNode, ctx: &FilterContext) -> Result<LightSource
}
let node = node.unwrap();
if node.borrow().is_in_error() {
if node.borrow_element().is_in_error() {
return Err(FilterError::ChildNodeInError);
}
let light_source = match node.borrow().get_type() {
NodeType::FeDistantLight => node.borrow().get_impl::<FeDistantLight>().transform(ctx),
NodeType::FePointLight => node.borrow().get_impl::<FePointLight>().transform(ctx),
NodeType::FeSpotLight => node.borrow().get_impl::<FeSpotLight>().transform(ctx),
NodeType::FeDistantLight => node
.borrow_element()
.get_impl::<FeDistantLight>()
.transform(ctx),
NodeType::FePointLight => node
.borrow_element()
.get_impl::<FePointLight>()
.transform(ctx),
NodeType::FeSpotLight => node
.borrow_element()
.get_impl::<FeSpotLight>()
.transform(ctx),
_ => unreachable!(),
};
......
......@@ -2,7 +2,7 @@ use markup5ever::{expanded_name, local_name, namespace_url, ns};
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::node::{NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::node::{NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::parsers::ParseValue;
use crate::property_bag::PropertyBag;
use crate::rect::IRect;
......@@ -92,14 +92,16 @@ impl FilterEffect for FeMerge {
.children()
.filter(|c| c.borrow().get_type() == NodeType::FeMergeNode)
{
if child.borrow().is_in_error() {
let elt = child.borrow_element();
if elt.is_in_error() {
return Err(FilterError::ChildNodeInError);
}
let input = ctx.get_input(
acquired_nodes,
draw_ctx,
child.borrow().get_impl::<FeMergeNode>().in_.as_ref(),
elt.get_impl::<FeMergeNode>().in_.as_ref(),
)?;
bounds = bounds.add_input(&input);
}
......@@ -111,7 +113,7 @@ impl FilterEffect for FeMerge {
.children()
.filter(|c| c.borrow().get_type() == NodeType::FeMergeNode)
{
output_surface = Some(child.borrow().get_impl::<FeMergeNode>().render(
output_surface = Some(child.borrow_element().get_impl::<FeMergeNode>().render(
ctx,
acquired_nodes,
draw_ctx,
......
......@@ -12,7 +12,7 @@ use crate::drawing_ctx::DrawingCtx;
use crate::error::{RenderingError, ValueErrorKind};
use crate::filter::Filter;
use crate::length::*;
use crate::node::{CascadedValues, NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::node::{CascadedValues, NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::parsers::ParseValue;
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
......@@ -118,7 +118,12 @@ impl NodeTrait for Primitive {
let primitiveunits = parent
.and_then(|parent| {
if parent.borrow().get_type() == NodeType::Filter {
Some(parent.borrow().get_impl::<Filter>().get_primitive_units())
Some(
parent
.borrow_element()
.get_impl::<Filter>()
.get_primitive_units(),
)
} else {
None
}
......@@ -248,8 +253,8 @@ pub fn render(
node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
let filter_node = &*filter_node;
assert_eq!(filter_node.borrow().get_type(), NodeType::Filter);
assert!(!filter_node.borrow().is_in_error());
assert_eq!(filter_node.borrow_element().get_type(), NodeType::Filter);
assert!(!filter_node.borrow_element().is_in_error());
let mut filter_ctx = FilterContext::new(
filter_node,
......@@ -267,9 +272,10 @@ pub fn render(
let primitives = filter_node
.children()
.filter(|c| c.is_element())
// Skip nodes in error.
.filter(|c| {
let in_error = c.borrow().is_in_error();
let in_error = c.borrow_element().is_in_error();
if in_error {
rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
......@@ -278,7 +284,12 @@ pub fn render(
!in_error
})
// Keep only filter primitives (those that implement the Filter trait)
.filter(|c| c.borrow().get_node_trait().as_filter_effect().is_some())
.filter(|c| {
c.borrow_element()
.get_node_trait()
.as_filter_effect()
.is_some()
})
// Check if the node wants linear RGB.
.map(|c| {
let linear_rgb = {
......@@ -292,8 +303,8 @@ pub fn render(
});
for (c, linear_rgb) in primitives {
let node_data = c.borrow();
let filter = node_data.get_node_trait().as_filter_effect().unwrap();
let elt = c.borrow_element();
let filter = elt.get_node_trait().as_filter_effect().unwrap();
let mut render = |filter_ctx: &mut FilterContext| {
if let Err(err) = filter
......
......@@ -11,7 +11,7 @@ use crate::document::{AcquiredNode, AcquiredNodes, NodeStack};
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::error::*;
use crate::length::*;
use crate::node::{CascadedValues, NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::node::{CascadedValues, NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::paint_server::{AsPaintSource, PaintSource};
use crate::parsers::{Parse, ParseValue};
use crate::properties::ComputedValues;
......@@ -448,8 +448,8 @@ impl UnresolvedGradient {
assert!(node_type == NodeType::LinearGradient || node_type == NodeType::RadialGradient);
for child_node in node.children() {
let child = child_node.borrow();
for child_node in node.children().filter(|c| c.is_element()) {
let child = child_node.borrow_element();
if child.get_type() != NodeType::Stop {
continue;
......@@ -661,7 +661,7 @@ macro_rules! impl_paint_source {
return Err(AcquireError::CircularReference(acquired_node.clone()));
}
let borrowed_node = acquired_node.borrow();
let borrowed_node = acquired_node.borrow_element();
let unresolved = match borrowed_node.get_type() {
$node_type => {
let a_gradient = borrowed_node.get_impl::<$gradient>();
......@@ -851,7 +851,7 @@ mod tests {
Box::new(LinearGradient::default()),
));
let borrow = node.borrow();
let borrow = node.borrow_element();
let g = borrow.get_impl::<LinearGradient>();
let Unresolved { gradient, .. } = g.get_unresolved(&node);
let gradient = gradient.resolve_from_defaults();
......@@ -865,7 +865,7 @@ mod tests {
Box::new(RadialGradient::default()),
));
let borrow = node.borrow();
let borrow = node.borrow_element();
let g = borrow.get_impl::<RadialGradient>();
let Unresolved { gradient, .. } = g.get_unresolved(&node);
let gradient = gradient.resolve_from_defaults();
......
......@@ -14,7 +14,7 @@ use crate::document::{AcquiredNodes, Document};
use crate::dpi::Dpi;
use crate::drawing_ctx::DrawingCtx;
use crate::error::{DefsLookupErrorKind, LoadingError, RenderingError};
use crate::node::{CascadedValues, RsvgNode};
use crate::node::{CascadedValues, NodeBorrow, RsvgNode};
use crate::rect::{IRect, Rect};
use crate::structure::{IntrinsicDimensions, Svg};
use url::Url;
......@@ -334,8 +334,10 @@ impl Handle {
let cascaded = CascadedValues::new_from_node(&node);
let values = cascaded.get();
if let Some((root_width, root_height)) =
node.borrow().get_impl::<Svg>().get_size(&values, dpi)
if let Some((root_width, root_height)) = node
.borrow_element()
.get_impl::<Svg>()
.get_size(&values, dpi)
{
let rect = IRect::from_size(root_width, root_height);
......
......@@ -573,7 +573,7 @@ fn emit_marker_by_name(
if let Ok(acquired) = acquired_nodes.acquire(name, &[NodeType::Marker]) {
let node = acquired.get();
node.borrow().get_impl::<Marker>().render(
node.borrow_element().get_impl::<Marker>().render(
&node,
acquired_nodes,
draw_ctx,
......
......@@ -14,8 +14,8 @@
use downcast_rs::*;
use locale_config::Locale;
use markup5ever::{expanded_name, local_name, namespace_url, ns, LocalName, Namespace, QualName};
use std::cell::Ref;
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};
use std::cell::{Ref, RefMut};
use std::collections::HashSet;
use std::fmt;
......@@ -43,8 +43,13 @@ pub type RsvgNode = rctree::Node<NodeData>;
/// See the [module documentation](index.html) for more information.
pub type RsvgWeakNode = rctree::WeakNode<NodeData>;
/// Contents of a tree node
pub struct NodeData {
pub enum NodeData {
Element(Element),
Text(NodeChars),
}
/// Contents of an element node in the DOM
pub struct Element {
node_type: NodeType,
element_name: QualName,
id: Option<String>, // id attribute from XML element
......@@ -67,7 +72,7 @@ impl NodeData {
class: Option<&str>,
node_impl: Box<dyn NodeTrait>,
) -> NodeData {
NodeData {
NodeData::Element(Element {
node_type,
element_name: element_name.clone(),
id: id.map(str::to_string),
......@@ -80,21 +85,24 @@ impl NodeData {
cond: true,
style_attr: String::new(),
node_impl,
}
})
}
pub fn new_chars() -> NodeData {
Self::new_element(
NodeType::Chars,
&QualName::new(
None,
Namespace::from("https://wiki.gnome.org/Projects/LibRsvg"),
LocalName::from("rsvg-chars"),
),
None,
None,
Box::new(NodeChars::new()),
)
NodeData::Text(NodeChars::new())
}
pub fn get_type(&self) -> NodeType {
match *self {
NodeData::Element(ref e) => e.node_type,
NodeData::Text(_) => NodeType::Chars,
}
}
}
impl Element {
pub fn get_type(&self) -> NodeType {
self.node_type
}
pub fn get_node_trait(&self) -> &dyn NodeTrait {
......@@ -109,14 +117,6 @@ impl NodeData {
}
}
pub fn get_type(&self) -> NodeType {
self.node_type
}
pub fn get_chars(&self) -> &NodeChars {
self.get_impl::<NodeChars>()
}