Files
core/test/rust/performance/json/document.rs
T
2026-11-03 03:32:07 +00:00

136 lines
7.9 KiB
Rust

use dever_runtime::wire::document;
fn document_fault(_: impl std::fmt::Display) -> Fault {
&FaultInfo { message: "JSON failure", source: "document-reference", line: 1, column: 1 }
}
fn generated_document(values: &[String]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |source| GENERATED_DOCUMENT(source).map_err(document_fault))
}
fn reference_document(values: &[String]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |source| {
let value = document::parse_with_depth(source, document::DOCUMENT_MAX_DEPTH).map_err(document_fault)?;
document::stringify_with_depth(&value, document::DOCUMENT_MAX_DEPTH).map_err(document_fault)
})
}
// 独立手写 Map 适配,解析/写出引擎仍共用;只衡量表示转换与生成层。
type ReferenceNode = reference_writer::Node<String, Vec<i64>, Map<String, i64>>;
fn reference_map_document(values: &[String]) -> Result<String, Fault> {
let Some(source) = values.first() else { return Ok(String::new()); };
let parsed = document::parse_with_depth(source, document::DOCUMENT_MAX_DEPTH).map_err(document_fault)?;
let mut nodes = indexmap::IndexMap::with_capacity(parsed.nodes.len());
for (index, value) in parsed.nodes.into_iter().enumerate() {
let value = match value {
document::Value::Null => ReferenceNode::Null,
document::Value::Boolean(value) => ReferenceNode::Boolean(value),
document::Value::Number(value) => ReferenceNode::Number(value),
document::Value::String(value) => ReferenceNode::String(value),
document::Value::Array(values) => ReferenceNode::Array(values),
document::Value::Object(values) => ReferenceNode::Object(values.map_or_else(|| Map::with_capacity(0), |values| *values)),
};
nodes.insert(index as i64, value);
}
reference_map_write(parsed.root as i64, &nodes)
}
fn reference_map_write(root: i64, nodes: &indexmap::IndexMap<i64, ReferenceNode>) -> Result<String, Fault> {
let root = usize::try_from(root).map_err(document_fault)?;
if nodes.len() > document::MAX_VALUES { return Err(document_fault("too many nodes")); }
let mut ordered = vec![None; nodes.len()];
for (id, value) in nodes {
if let Ok(index) = usize::try_from(*id) && let Some(slot) = ordered.get_mut(index) {
*slot = Some(value);
}
}
let ordered = ordered.into_iter().map(|value| value.ok_or_else(|| document_fault("missing node"))).collect::<Result<Vec<_>, _>>()?;
reference_writer::stringify_nodes(root, ordered.len(), |index| {
match ordered[index] {
ReferenceNode::Null => reference_writer::Node::Null,
ReferenceNode::Boolean(value) => reference_writer::Node::Boolean(*value),
ReferenceNode::Number(value) => reference_writer::Node::Number(value.as_str()),
ReferenceNode::String(value) => reference_writer::Node::String(value.as_str()),
ReferenceNode::Array(values) => reference_writer::Node::Array(values.iter().copied()),
ReferenceNode::Object(values) => reference_writer::Node::Object(values.iter().map(|(name, id)| (name.as_str(), *id))),
}
}, document::DOCUMENT_MAX_DEPTH).map_err(document_fault)
}
#[derive(Debug)]
enum ReferenceFailure {
Fault(Fault),
Parse(i64, String, Fault),
Write(i64, String, Fault),
}
impl std::fmt::Display for ReferenceFailure {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Fault(fault) | Self::Parse(_, _, fault) | Self::Write(_, _, fault) => fault.fmt(formatter),
}
}
}
fn reference_map_faults(values: &[String]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |source| reference_map_contract(source).map_err(document_fault))
}
// 原参照继续保留;这里独立保留解析/输出错误的载荷与静态源位置。
fn reference_map_contract(source: &str) -> Result<String, ReferenceFailure> {
let parse_fault = &FaultInfo { message: "ParseResult.Failed", source: "document-reference", line: 1, column: 1 };
let write_fault = &FaultInfo { message: "StringifyResult.Failed", source: "document-reference", line: 2, column: 1 };
let fail = |node, message: &str| ReferenceFailure::Write(node, message.into(), write_fault);
let parsed = document::parse_with_depth(source, document::DOCUMENT_MAX_DEPTH)
.map_err(|error| ReferenceFailure::Parse(error.position as i64, error.message, parse_fault))?;
let mut nodes = indexmap::IndexMap::with_capacity(parsed.nodes.len());
for (index, value) in parsed.nodes.into_iter().enumerate() {
let value = match value {
document::Value::Null => ReferenceNode::Null,
document::Value::Boolean(value) => ReferenceNode::Boolean(value),
document::Value::Number(value) => ReferenceNode::Number(value),
document::Value::String(value) => ReferenceNode::String(value),
document::Value::Array(values) => ReferenceNode::Array(values),
document::Value::Object(values) => ReferenceNode::Object(values.map_or_else(|| Map::with_capacity(0), |values| *values)),
};
nodes.insert(index as i64, value);
}
let root = parsed.root as i64;
let root_index = usize::try_from(root).map_err(|_| fail(root, "negative JSON root"))?;
if nodes.len() > document::MAX_VALUES { return Err(fail(root, "JSON node count exceeds 65536 values")); }
let mut ordered = vec![None; nodes.len()];
for (id, value) in &nodes {
if let Ok(index) = usize::try_from(*id) && let Some(slot) = ordered.get_mut(index) {
*slot = Some(value);
}
}
let ordered = ordered.into_iter().enumerate().map(|(index, value)| value.ok_or_else(|| fail(index as i64, "JSON node IDs must be consecutive"))).collect::<Result<Vec<_>, _>>()?;
reference_writer::stringify_nodes(root_index, ordered.len(), |index| {
match ordered[index] {
ReferenceNode::Null => reference_writer::Node::Null,
ReferenceNode::Boolean(value) => reference_writer::Node::Boolean(*value),
ReferenceNode::Number(value) => reference_writer::Node::Number(value.as_str()),
ReferenceNode::String(value) => reference_writer::Node::String(value.as_str()),
ReferenceNode::Array(values) => reference_writer::Node::Array(values.iter().copied()),
ReferenceNode::Object(values) => reference_writer::Node::Object(values.iter().map(|(name, id)| (name.as_str(), *id))),
}
}, document::DOCUMENT_MAX_DEPTH).map_err(|error| ReferenceFailure::Write(error.node as i64, error.message, write_fault))
}
fn main() {
println!("case,sample,implementation,elapsed_ns,checksum");
let text = "雪\\\"\n".repeat(256);
let strings = dever_runtime::wire::json::Json::encode(&vec![text; 32]).unwrap().as_str().to_owned();
let numbers = format!("[{}]", vec!["1234567890123456789012345678901234e-12"; 256].join(","));
let mut nested = "1e9999".to_owned();
for _ in 0..48 { nested = format!("{{\"value\":{nested}}}"); }
let empty_objects = format!("[{}]", vec!["{}"; 128].join(","));
let wide = format!("{{{}}}", (0..256).map(|index| format!("\"key{index}\":1e9999")).collect::<Vec<_>>().join(","));
for (name, source) in [("document_text", strings), ("document_numbers", numbers), ("document_nested", nested), ("document_empty", "{}".into()), ("document_empty_objects", empty_objects), ("document_wide", wide)] {
compare(name, std::slice::from_ref(&source), 100, generated_document, reference_document, |value| value.bytes().map(u64::from).sum());
compare(&format!("{name}_map"), std::slice::from_ref(&source), 100, generated_document, reference_map_document, |value| value.bytes().map(u64::from).sum());
compare(&format!("{name}_map_faults"), &[source], 100, generated_document, reference_map_faults, |value| value.bytes().map(u64::from).sum());
}
}