136 lines
7.9 KiB
Rust
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());
|
|
}
|
|
}
|