use crate::ParserSettings;
use crate::binxml::ir::RecordContent;
use crate::binxml::render_ctx::{
Ovr, RNode, Scope, content_layout, count_expansion_copies, expansion_any, find_expansion,
for_each_expansion, has_non_empty_text_content, resolve_child_element,
};
use crate::binxml::value_render::ValueRenderer;
use crate::binxml::value_variant::BinXmlValue;
use crate::err::{EvtxError, Result};
#[cfg(feature = "bench")]
use crate::model::ir::IrArena;
use crate::model::ir::{Attr, Element, IrTree, Name, Node, Text, is_optional_empty};
use crate::utils::Utf16LeSlice;
use sonic_rs::format::{CompactFormatter, Formatter};
use sonic_rs::writer::WriteExt;
const INLINE_UNIQUE_NAMES: usize = 16;
pub(crate) fn render_json_record<W: WriteExt>(
tree: &IrTree<'_>,
settings: &ParserSettings,
writer: &mut W,
) -> Result<()> {
render_json_with_scope(
Scope::materialized(tree.arena()),
tree.root_element(),
settings,
writer,
)
}
pub(crate) fn render_json_record_content<W: WriteExt>(
content: &RecordContent<'_>,
settings: &ParserSettings,
writer: &mut W,
) -> Result<()> {
match content {
RecordContent::Tree(tree) => render_json_record(tree, settings, writer),
RecordContent::Template(tc) => {
let scope = tc.scope();
let root = scope
.arena
.get(tc.root.template.root())
.expect("invalid element id");
render_json_with_scope(scope, root, settings, writer)
}
}
}
fn render_json_with_scope<W: WriteExt>(
scope: Scope<'_, '_>,
root: &Element<'_>,
settings: &ParserSettings,
writer: &mut W,
) -> Result<()> {
let mut emitter = JsonEmitter::new(writer, settings.should_separate_json_attributes());
emitter.write_bytes(b"{")?;
if emitter.separate_json_attributes {
if !root.attrs.is_empty()
&& emitter.render_separate_attributes_for_element(scope, root, 0, None)?
{
emitter.write_byte(b',')?;
}
emitter.write_json_key_from_name_with_suffix(&root.name, 0)?;
emitter.write_element_value_no_attrs(scope, root, None, false)?;
} else {
emitter.write_byte(b'\"')?;
emitter.write_name(root.name.as_str())?;
emitter.write_bytes(b"\":")?;
emitter.write_element_value(scope, root, None, false)?;
}
emitter.write_bytes(b"}")?;
emitter.flush()?;
Ok(())
}
#[derive(Clone, Copy)]
struct NameKey<'a> {
bytes: &'a str,
}
impl<'a> NameKey<'a> {
fn from_name(name: &'a Name<'a>) -> Self {
NameKey {
bytes: name.as_str(),
}
}
fn eql(self, other: NameKey<'a>) -> bool {
if self.bytes.as_ptr() == other.bytes.as_ptr() && self.bytes.len() == other.bytes.len() {
return true;
}
self.bytes == other.bytes
}
}
struct NameCount<'a> {
key: NameKey<'a>,
emitted_count: u16,
}
struct NameCounts<'a> {
inline: [Option<NameCount<'a>>; INLINE_UNIQUE_NAMES],
num_inline: usize,
spill: Vec<NameCount<'a>>,
}
impl<'a> NameCounts<'a> {
fn next_suffix(&mut self, key: NameKey<'a>) -> u16 {
for nc_opt in self.inline.iter_mut().take(self.num_inline) {
let Some(nc) = nc_opt.as_mut() else {
continue;
};
if nc.key.eql(key) {
let suffix = nc.emitted_count;
nc.emitted_count = nc.emitted_count.saturating_add(1);
return suffix;
}
}
if !self.spill.is_empty() {
for nc in self.spill.iter_mut() {
if nc.key.eql(key) {
let suffix = nc.emitted_count;
nc.emitted_count = nc.emitted_count.saturating_add(1);
return suffix;
}
}
}
let entry = NameCount {
key,
emitted_count: 1,
};
if self.num_inline < INLINE_UNIQUE_NAMES {
self.inline[self.num_inline] = Some(entry);
self.num_inline += 1;
} else {
self.spill.push(entry);
}
0
}
}
fn attr_flags(scope: &Scope<'_, '_>, attrs: &[Attr<'_>], ovr: Option<&Ovr<'_>>) -> (bool, bool) {
if attrs.is_empty() {
return (false, false);
}
for attr in attrs {
if has_non_empty_text_content(scope, &attr.value, ovr) {
return (true, true);
}
}
(true, false)
}
fn get_name_attr_nodes<'b, 'a>(element: &'b Element<'a>) -> Option<&'b [Node<'a>]> {
for attr in &element.attrs {
if attr.name.as_str() == "Name" {
return Some(&attr.value);
}
}
None
}
struct JsonEmitter<'w, W: WriteExt> {
writer: &'w mut W,
values: ValueRenderer,
formatter: CompactFormatter,
separate_json_attributes: bool,
}
impl<'w, W: WriteExt> JsonEmitter<'w, W> {
fn new(writer: &'w mut W, separate_json_attributes: bool) -> Self {
JsonEmitter {
writer,
values: ValueRenderer::new(),
formatter: CompactFormatter,
separate_json_attributes,
}
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
self.writer.write_all(bytes).map_err(EvtxError::from)
}
fn write_byte(&mut self, byte: u8) -> Result<()> {
self.writer.write_all(&[byte]).map_err(EvtxError::from)
}
fn flush(&mut self) -> Result<()> {
self.writer.flush().map_err(EvtxError::from)
}
fn write_name(&mut self, name: &str) -> Result<()> {
self.write_bytes(name.as_bytes())
}
fn write_json_key_from_name_with_suffix(&mut self, name: &Name<'_>, suffix: u16) -> Result<()> {
self.write_byte(b'\"')?;
self.write_name(name.as_str())?;
if suffix > 0 {
self.write_byte(b'_')?;
self.formatter
.write_u64(self.writer, u64::from(suffix))
.map_err(EvtxError::from)?;
}
self.write_bytes(b"\":")
}
fn write_json_key_from_nodes(
&mut self,
scope: Scope<'_, '_>,
nodes: &[Node<'_>],
ovr: Option<&Ovr<'_>>,
) -> Result<()> {
self.write_byte(b'\"')?;
self.write_json_text_content(scope, nodes, false, ovr)?;
self.write_bytes(b"\":")
}
fn write_json_escaped_utf16(&mut self, value: Utf16LeSlice<'_>) -> Result<()> {
let bytes = value.as_bytes();
let units = bytes.len() / 2;
if units == 0 {
return Ok(());
}
utf16_simd::write_json_utf16le(self.writer, bytes, units, false)
.map_err(EvtxError::from)?;
Ok(())
}
fn write_json_text(&mut self, text: &Text<'_>) -> Result<()> {
if text.is_empty() {
return Ok(());
}
match text {
Text::Utf16(value) => self.write_json_escaped_utf16(*value),
Text::Utf8(value) => self
.formatter
.write_string_fast(self.writer, value.as_ref(), false)
.map_err(EvtxError::from),
}
}
fn write_json_text_content(
&mut self,
scope: Scope<'_, '_>,
nodes: &[Node<'_>],
skip_elements: bool,
ovr: Option<&Ovr<'_>>,
) -> Result<()> {
for node in nodes {
match scope.resolve(node, ovr)? {
RNode::Skip => {}
RNode::Text(text) => self.write_json_text(&text)?,
RNode::Value(value) => {
self.values.write_json_value_text(self.writer, value)?;
}
RNode::OwnValue(value) => {
self.values.write_json_value_text(self.writer, &value)?;
}
RNode::Frag(_) | RNode::Nested(_) => {
if skip_elements {
continue;
}
return Err(EvtxError::FailedToCreateRecordModel(
"unexpected element node in text context",
));
}
RNode::Plain(node) => match node {
Node::Text(text) | Node::CData(text) => self.write_json_text(text)?,
Node::Value(value) => {
self.values.write_json_value_text(self.writer, value)?;
}
Node::CharRef(ch) => {
if let Some(ch) = char::from_u32(u32::from(*ch)) {
let mut buf = [0_u8; 4];
let s = ch.encode_utf8(&mut buf);
self.formatter
.write_string_fast(self.writer, s, false)
.map_err(EvtxError::from)?;
} else {
self.write_bytes(b"&#")?;
self.formatter
.write_u64(self.writer, u64::from(*ch))
.map_err(EvtxError::from)?;
self.write_byte(b';')?;
}
}
Node::EntityRef(name) => {
let resolved = match name.as_str() {
"quot" => Some("\""),
"apos" => Some("'"),
"amp" => Some("&"),
"lt" => Some("<"),
"gt" => Some(">"),
_ => None,
};
match resolved {
Some(s) => {
self.formatter
.write_string_fast(self.writer, s, false)
.map_err(EvtxError::from)?;
}
None => {
self.write_byte(b'&')?;
self.write_bytes(name.as_str().as_bytes())?;
self.write_byte(b';')?;
}
}
}
Node::PITarget(_) | Node::PIData(_) => {}
Node::Placeholder(_) => {
return Err(EvtxError::FailedToCreateRecordModel(
"unresolved placeholder in tree",
));
}
Node::Element(_) => {
if skip_elements {
continue;
}
return Err(EvtxError::FailedToCreateRecordModel(
"unexpected element node in text context",
));
}
},
}
}
Ok(())
}
fn write_value_as_number(&mut self, value: &BinXmlValue<'_>) -> Result<bool> {
match value {
BinXmlValue::Int8Type(v) => self.write_signed_number(i64::from(*v)),
BinXmlValue::Int16Type(v) => self.write_signed_number(i64::from(*v)),
BinXmlValue::Int32Type(v) => self.write_signed_number(i64::from(*v)),
BinXmlValue::Int64Type(v) => self.write_signed_number(*v),
BinXmlValue::UInt8Type(v) => self.write_unsigned_number(u64::from(*v)),
BinXmlValue::UInt16Type(v) => self.write_unsigned_number(u64::from(*v)),
BinXmlValue::UInt32Type(v) => self.write_unsigned_number(u64::from(*v)),
BinXmlValue::UInt64Type(v) => self.write_unsigned_number(*v),
BinXmlValue::BoolType(v) => {
self.write_bytes(if *v { b"true" } else { b"false" })?;
Ok(true)
}
_ => Ok(false),
}
}
fn try_write_as_number(
&mut self,
scope: Scope<'_, '_>,
nodes: &[Node<'_>],
ovr: Option<&Ovr<'_>>,
) -> Result<bool> {
let single = if let [node] = nodes {
scope.resolve(node, ovr)?
} else {
let mut single: Option<RNode<'_, '_>> = None;
for node in nodes {
match scope.resolve(node, ovr)? {
RNode::Skip => {}
rnode => {
if single.is_some() {
return Ok(false);
}
single = Some(rnode);
}
}
}
match single {
Some(rnode) => rnode,
None => return Ok(false),
}
};
match single {
RNode::Value(value) => self.write_value_as_number(value),
RNode::OwnValue(value) => self.write_value_as_number(&value),
RNode::Plain(Node::Value(value)) => self.write_value_as_number(value),
_ => Ok(false),
}
}
fn try_write_as_number_skip_elements(
&mut self,
scope: Scope<'_, '_>,
nodes: &[Node<'_>],
ovr: Option<&Ovr<'_>>,
) -> Result<bool> {
let mut single: Option<RNode<'_, '_>> = None;
for node in nodes {
let rnode = scope.resolve(node, ovr)?;
match &rnode {
RNode::Skip | RNode::Frag(_) | RNode::Nested(_) => continue,
RNode::Text(text) => {
if !text.is_empty() {
return Ok(false);
}
}
RNode::Value(value) => {
if is_optional_empty(value) {
continue;
}
if single.is_some() {
return Ok(false);
}
single = Some(rnode);
}
RNode::OwnValue(value) => {
if is_optional_empty(value) {
continue;
}
if single.is_some() {
return Ok(false);
}
single = Some(rnode);
}
RNode::Plain(node) => match node {
Node::Element(_) => continue,
Node::Text(text) | Node::CData(text) => {
if !text.is_empty() {
return Ok(false);
}
}
Node::Value(value) => {
if is_optional_empty(value) {
continue;
}
if single.is_some() {
return Ok(false);
}
single = Some(rnode);
}
Node::CharRef(_) | Node::EntityRef(_) => return Ok(false),
Node::PITarget(_) | Node::PIData(_) => {}
Node::Placeholder(_) => {
return Err(EvtxError::FailedToCreateRecordModel(
"unresolved placeholder in tree",
));
}
},
}
}
match single {
Some(RNode::Value(value)) => self.write_value_as_number(value),
Some(RNode::OwnValue(value)) => self.write_value_as_number(&value),
Some(RNode::Plain(Node::Value(value))) => self.write_value_as_number(value),
_ => Ok(false),
}
}
fn write_signed_number(&mut self, value: i64) -> Result<bool> {
self.formatter
.write_i64(self.writer, value)
.map_err(EvtxError::from)?;
Ok(true)
}
fn write_unsigned_number(&mut self, value: u64) -> Result<bool> {
self.formatter
.write_u64(self.writer, value)
.map_err(EvtxError::from)?;
Ok(true)
}
fn render_text_to_json_string(
&mut self,
scope: Scope<'_, '_>,
nodes: &[Node<'_>],
skip_elements: bool,
ovr: Option<&Ovr<'_>>,
) -> Result<()> {
self.write_byte(b'\"')?;
self.write_json_text_content(scope, nodes, skip_elements, ovr)?;
self.write_byte(b'\"')
}
fn render_content_as_json_value(
&mut self,
scope: Scope<'_, '_>,
nodes: &[Node<'_>],
skip_elements: bool,
ovr: Option<&Ovr<'_>>,
) -> Result<()> {
let wrote_number = if skip_elements {
self.try_write_as_number_skip_elements(scope, nodes, ovr)?
} else {
self.try_write_as_number(scope, nodes, ovr)?
};
if wrote_number {
return Ok(());
}
self.render_text_to_json_string(scope, nodes, skip_elements, ovr)
}
fn render_attributes_object(
&mut self,
scope: Scope<'_, '_>,
attrs: &[Attr<'_>],
ovr: Option<&Ovr<'_>>,
) -> Result<bool> {
let (_has_any, has_text) = attr_flags(&scope, attrs, ovr);
if !has_text {
return Ok(false);
}
self.write_bytes(b"\"#attributes\":{")?;
let wrote_any = self.render_attributes_object_body(scope, attrs, ovr)?;
self.write_byte(b'}')?;
Ok(wrote_any)
}
fn render_attributes_object_body(
&mut self,
scope: Scope<'_, '_>,
attrs: &[Attr<'_>],
ovr: Option<&Ovr<'_>>,
) -> Result<bool> {
let mut wrote_any = false;
let mut first = true;
for attr in attrs {
if !has_non_empty_text_content(&scope, &attr.value, ovr) {
continue;
}
if !first {
self.write_byte(b',')?;
}
first = false;
wrote_any = true;
self.write_byte(b'\"')?;
self.write_name(attr.name.as_str())?;
self.write_bytes(b"\":")?;
if self.try_write_as_number(scope, &attr.value, ovr)? {
continue;
}
self.render_text_to_json_string(scope, &attr.value, false, ovr)?;
}
Ok(wrote_any)
}
fn render_separate_attributes_for_element(
&mut self,
scope: Scope<'_, '_>,
element: &Element<'_>,
suffix: u16,
ovr: Option<&Ovr<'_>>,
) -> Result<bool> {
if element.attrs.is_empty() {
return Ok(false);
}
let (_has_any, has_text) = attr_flags(&scope, &element.attrs, ovr);
if !has_text {
return Ok(false);
}
self.write_byte(b'\"')?;
self.write_name(element.name.as_str())?;
if suffix > 0 {
self.write_byte(b'_')?;
self.formatter
.write_u64(self.writer, u64::from(suffix))
.map_err(EvtxError::from)?;
}
self.write_bytes(b"_attributes\":{")?;
let wrote_any = self.render_attributes_object_body(scope, &element.attrs, ovr)?;
self.write_byte(b'}')?;
Ok(wrote_any)
}
fn render_data_element_value(
&mut self,
scope: Scope<'_, '_>,
element: &Element<'_>,
ovr: Option<&Ovr<'_>>,
) -> Result<()> {
if self.try_write_leaf_value(scope, element, ovr, true)? {
return Ok(());
}
let (has_text, has_element_child) = content_layout(&scope, element, ovr);
if !has_text && !has_element_child {
return self.write_bytes(b"\"\"");
}
if has_element_child {
self.write_element_body_json(scope, element, ovr, false, true, has_text)
} else {
self.render_content_as_json_value(scope, &element.children, false, ovr)
}
}
fn try_write_leaf_value(
&mut self,
scope: Scope<'_, '_>,
element: &Element<'_>,
ovr: Option<&Ovr<'_>>,
empty_as_string: bool,
) -> Result<bool> {
if element.has_element_child || element.children.len() != 1 {
return Ok(false);
}
let empty: &[u8] = if empty_as_string { b"\"\"" } else { b"null" };
match scope.resolve(&element.children[0], ovr)? {
RNode::Skip => {
self.write_bytes(empty)?;
Ok(true)
}
RNode::Text(text) => {
self.write_leaf_text(&text, empty)?;
Ok(true)
}
RNode::Value(value) => {
self.write_leaf_value(value, empty)?;
Ok(true)
}
RNode::OwnValue(value) => {
self.write_leaf_value(&value, empty)?;
Ok(true)
}
RNode::Plain(Node::Text(text)) => {
self.write_leaf_text(text, empty)?;
Ok(true)
}
RNode::Plain(Node::Value(value)) => {
self.write_leaf_value(value, empty)?;
Ok(true)
}
_ => Ok(false),
}
}
fn write_leaf_text(&mut self, text: &Text<'_>, empty: &[u8]) -> Result<()> {
if text.is_empty() {
return self.write_bytes(empty);
}
self.write_byte(b'\"')?;
self.write_json_text(text)?;
self.write_byte(b'\"')
}
fn write_leaf_value(&mut self, value: &BinXmlValue<'_>, empty: &[u8]) -> Result<()> {
if is_optional_empty(value) {
return self.write_bytes(empty);
}
if self.write_value_as_number(value)? {
return Ok(());
}
self.write_byte(b'\"')?;
self.values.write_json_value_text(self.writer, value)?;
self.write_byte(b'\"')
}
fn write_element_value_no_attrs(
&mut self,
scope: Scope<'_, '_>,
element: &Element<'_>,
ovr: Option<&Ovr<'_>>,
child_is_container: bool,
) -> Result<()> {
if self.try_write_leaf_value(scope, element, ovr, false)? {
return Ok(());
}
let (has_text, has_element_child) = content_layout(&scope, element, ovr);
if !has_element_child && !has_text {
self.write_bytes(b"null")
} else if !has_element_child {
self.render_content_as_json_value(scope, &element.children, false, ovr)
} else {
self.write_element_body_json(scope, element, ovr, child_is_container, true, has_text)
}
}
fn write_element_value(
&mut self,
scope: Scope<'_, '_>,
element: &Element<'_>,
ovr: Option<&Ovr<'_>>,
child_is_container: bool,
) -> Result<()> {
if element.attrs.is_empty() && self.try_write_leaf_value(scope, element, ovr, false)? {
return Ok(());
}
let (has_text, has_element_child) = content_layout(&scope, element, ovr);
let (_has_attrs_any, has_attrs_text) = attr_flags(&scope, &element.attrs, ovr);
if !has_element_child && !has_text && !has_attrs_text {
self.write_bytes(b"null")
} else if !has_element_child && !has_attrs_text {
self.render_content_as_json_value(scope, &element.children, false, ovr)
} else {
self.write_element_body_json(scope, element, ovr, child_is_container, false, has_text)
}
}
fn write_element_body_json<'t, 'a>(
&mut self,
scope: Scope<'t, 'a>,
element: &'t Element<'a>,
ovr: Option<&Ovr<'_>>,
in_data_container: bool,
omit_attributes: bool,
has_text: bool,
) -> Result<()> {
let mut should_flatten_named_data = false;
if in_data_container {
for node in &element.children {
let Some(ce) = resolve_child_element(scope, node, ovr)? else {
continue;
};
if !is_data_element(ce.element.name.as_str()) {
continue;
}
let Some(name_nodes) = get_name_attr_nodes(ce.element) else {
continue;
};
let child_scope = ce.scope;
let has_named =
if ce.expand && child_scope.ctx.as_ref().is_some_and(|ctx| ctx.may_expand) {
expansion_any(&child_scope, ce.element, ovr, &mut |copy_ovr| {
Ok(has_non_empty_text_content(
&child_scope,
name_nodes,
copy_ovr,
))
})?
} else {
let copy_ovr = if ce.expand { ovr } else { None };
has_non_empty_text_content(&child_scope, name_nodes, copy_ovr)
};
if has_named {
should_flatten_named_data = true;
break;
}
}
}
let mut name_counts = NameCounts {
inline: std::array::from_fn(|_| None),
num_inline: 0,
spill: Vec::new(),
};
self.write_byte(b'{')?;
let mut wrote_any = false;
if !omit_attributes
&& !element.attrs.is_empty()
&& self.render_attributes_object(scope, &element.attrs, ovr)?
{
wrote_any = true;
}
if has_text {
if wrote_any {
self.write_byte(b',')?;
}
wrote_any = true;
self.write_bytes(b"\"#text\":")?;
self.render_content_as_json_value(scope, &element.children, true, ovr)?;
}
let positional_data_count = if in_data_container && !should_flatten_named_data {
let mut count = 0usize;
for node in &element.children {
let Some(ce) = resolve_child_element(scope, node, ovr)? else {
continue;
};
if !is_data_element(ce.element.name.as_str()) {
continue;
}
count += if ce.expand {
count_expansion_copies(&ce.scope, ce.element, ovr)
} else {
1
};
}
count
} else {
0
};
let mut positional_data_emitted = false;
for node in &element.children {
let Some(ce) = resolve_child_element(scope, node, ovr)? else {
continue;
};
let child = ce.element;
let child_scope = ce.scope;
let expansion = if ce.expand {
child_scope
.ctx
.as_ref()
.and_then(|ctx| find_expansion(child, ctx, ovr))
} else {
None
};
let direct_ovr = if ce.expand { ovr } else { None };
if in_data_container && is_data_element(child.name.as_str()) {
if should_flatten_named_data {
let Some(name_nodes) = get_name_attr_nodes(child) else {
continue;
};
if expansion.is_none() {
self.emit_named_data_copy(
child_scope,
child,
name_nodes,
direct_ovr,
&mut wrote_any,
)?;
} else {
let emitter = &mut *self;
let wrote_any_ref = &mut wrote_any;
for_each_expansion(&child_scope, child, ovr, &mut |copy_ovr| {
emitter.emit_named_data_copy(
child_scope,
child,
name_nodes,
copy_ovr,
wrote_any_ref,
)
})?;
}
} else if !positional_data_emitted && positional_data_count > 0 {
if wrote_any {
self.write_byte(b',')?;
}
wrote_any = true;
positional_data_emitted = true;
self.write_bytes(b"\"Data\":{")?;
self.write_bytes(b"\"#text\":")?;
if positional_data_count == 1 {
self.render_data_element_value(child_scope, child, direct_ovr)?;
} else {
self.write_byte(b'[')?;
let mut first = true;
for node2 in &element.children {
let Some(ce2) = resolve_child_element(scope, node2, ovr)? else {
continue;
};
if !is_data_element(ce2.element.name.as_str()) {
continue;
}
let candidate = ce2.element;
let candidate_scope = ce2.scope;
let item_ovr = if ce2.expand { ovr } else { None };
let emitter = &mut *self;
let mut emit_item = |copy_ovr: Option<&Ovr<'_>>| -> Result<()> {
if !first {
emitter.write_byte(b',')?;
}
first = false;
emitter.render_data_element_value(
candidate_scope,
candidate,
copy_ovr,
)
};
if ce2.expand {
for_each_expansion(
&candidate_scope,
candidate,
ovr,
&mut emit_item,
)?;
} else {
emit_item(item_ovr)?;
}
}
self.write_byte(b']')?;
}
self.write_byte(b'}')?;
}
continue;
}
if expansion.is_none() {
self.emit_normal_child(child_scope, child, direct_ovr, &mut name_counts, &mut wrote_any)?;
} else {
let emitter = &mut *self;
let name_counts_ref = &mut name_counts;
let wrote_any_ref = &mut wrote_any;
for_each_expansion(&child_scope, child, ovr, &mut |copy_ovr| {
emitter.emit_normal_child(
child_scope,
child,
copy_ovr,
name_counts_ref,
wrote_any_ref,
)
})?;
}
}
self.write_byte(b'}')?;
Ok(())
}
fn emit_named_data_copy(
&mut self,
scope: Scope<'_, '_>,
child: &Element<'_>,
name_nodes: &[Node<'_>],
copy_ovr: Option<&Ovr<'_>>,
wrote_any: &mut bool,
) -> Result<()> {
if !has_non_empty_text_content(&scope, name_nodes, copy_ovr) {
return Ok(());
}
if *wrote_any {
self.write_byte(b',')?;
}
*wrote_any = true;
self.write_json_key_from_nodes(scope, name_nodes, copy_ovr)?;
self.render_data_element_value(scope, child, copy_ovr)
}
fn emit_normal_child<'t, 'a>(
&mut self,
scope: Scope<'t, 'a>,
child: &'t Element<'a>,
copy_ovr: Option<&Ovr<'_>>,
name_counts: &mut NameCounts<'t>,
wrote_any: &mut bool,
) -> Result<()> {
let suffix = name_counts.next_suffix(NameKey::from_name(&child.name));
if *wrote_any {
self.write_byte(b',')?;
}
*wrote_any = true;
let child_is_container = is_data_container(child.name.as_str());
if self.separate_json_attributes {
let wrote_attrs =
self.render_separate_attributes_for_element(scope, child, suffix, copy_ovr)?;
let (has_text, has_element_child) = content_layout(&scope, child, copy_ovr);
let child_has_value = has_element_child || has_text;
let write_value = child_has_value || !wrote_attrs;
if wrote_attrs && write_value {
self.write_byte(b',')?;
}
if write_value {
self.write_json_key_from_name_with_suffix(&child.name, suffix)?;
self.write_element_value_no_attrs(scope, child, copy_ovr, child_is_container)?;
}
} else {
self.write_json_key_from_name_with_suffix(&child.name, suffix)?;
self.write_element_value(scope, child, copy_ovr, child_is_container)?;
}
Ok(())
}
}
#[cfg(feature = "bench")]
pub(crate) fn bench_write_json_text_content<'a, W: WriteExt>(
writer: &mut W,
arena: &'a IrArena<'a>,
nodes: &[Node<'a>],
) -> Result<()> {
let mut emitter = JsonEmitter::new(writer, false);
emitter.write_json_text_content(Scope::materialized(arena), nodes, false, None)?;
emitter.flush()
}
fn is_data_container(name: &str) -> bool {
name == "EventData" || name == "UserData"
}
fn is_data_element(name: &str) -> bool {
name == "Data"
}