Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+135
View File
@@ -0,0 +1,135 @@
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());
}
}
+131
View File
@@ -0,0 +1,131 @@
// 阶段诊断复用正式入口;shared 标签只测运行库,不是独立 Rust 引擎参照。
// map 场景名保留历史编号,Rust 参照仍构造 Map;当前 Dever 直接拥有节点 List。
struct PreparedDocument {
generated: DOCUMENT_TYPE,
reference: (i64, indexmap::IndexMap<i64, ReferenceNode>),
raw: document::Document,
}
fn reference_nodes(parsed: document::Document) -> (i64, indexmap::IndexMap<i64, ReferenceNode>) {
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);
}
(parsed.root as i64, nodes)
}
fn phase_raw_parse(values: &[String]) -> Result<usize, Fault> {
values.first().map_or(Ok(0), |source| {
document::parse_with_depth(source, document::DOCUMENT_MAX_DEPTH)
.map(|parsed| black_box(parsed).nodes.len()).map_err(document_fault)
})
}
fn phase_generated_parse(values: &[String]) -> Result<usize, Fault> {
values.first().map_or(Ok(0), |source| {
GENERATED_PARSE(source).map(|parsed| black_box(parsed).field1.len()).map_err(document_fault)
})
}
fn phase_reference_parse(values: &[String]) -> Result<usize, Fault> {
values.first().map_or(Ok(0), |source| {
document::parse_with_depth(source, document::DOCUMENT_MAX_DEPTH)
.map(|parsed| black_box(reference_nodes(parsed)).1.len()).map_err(document_fault)
})
}
fn phase_generated_write(values: &[PreparedDocument]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| GENERATED_WRITE(&value.generated).map_err(document_fault))
}
fn phase_reference_write(values: &[PreparedDocument]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| reference_map_write(value.reference.0, &value.reference.1))
}
fn phase_raw_write(values: &[PreparedDocument]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
document::stringify_with_depth(&value.raw, document::DOCUMENT_MAX_DEPTH).map_err(document_fault)
})
}
#[derive(Debug)]
enum PhaseWriteFailure {
Fault(Fault),
Write(i64, String, Fault),
}
impl std::fmt::Display for PhaseWriteFailure {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Fault(fault) | Self::Write(_, _, fault) => fault.fmt(formatter),
}
}
}
fn phase_contract_write(values: &[PreparedDocument]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| reference_contract_write(&value.generated).map_err(document_fault))
}
fn phase_adapter_write(values: &[PreparedDocument]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| runtime_contract_write(&value.generated).map_err(document_fault))
}
// 同一份节点直接调用当前运行库,只衡量生成适配,不作为独立 JSON 引擎参照。
fn runtime_contract_write(value: &DOCUMENT_TYPE) -> Result<String, PhaseWriteFailure> {
let origin = &FaultInfo { message: "StringifyResult.Failed", source: "document-reference", line: 1, column: 1 };
let root = usize::try_from(value.field0).map_err(|_| {
PhaseWriteFailure::Write(value.field0, "negative JSON root".into(), origin)
})?;
document::stringify_slice(root, &value.field1, document::DOCUMENT_MAX_DEPTH)
.map_err(|error| PhaseWriteFailure::Write(error.node as i64, error.message, origin))
}
// 同一实参及错误布局,只隔离生成层;解析和输出引擎仍共享。
fn reference_contract_write(value: &DOCUMENT_TYPE) -> Result<String, PhaseWriteFailure> {
let origin = &FaultInfo { message: "StringifyResult.Failed", source: "document-reference", line: 1, column: 1 };
let fail = |node, message: &str| PhaseWriteFailure::Write(node, message.into(), origin);
let root = usize::try_from(value.field0).map_err(|_| fail(value.field0, "negative JSON root"))?;
reference_writer::stringify_nodes(root, value.field1.len(), |index| {
match &value.field1[index] {
document::Value::Null => reference_writer::Node::Null,
document::Value::Boolean(value) => reference_writer::Node::Boolean(*value),
document::Value::Number(value) => reference_writer::Node::Number(value.as_str()),
document::Value::String(value) => reference_writer::Node::String(value.as_str()),
document::Value::Array(values) => reference_writer::Node::Array(values.iter().copied()),
document::Value::Object(values) => reference_writer::Node::Object(values.iter().flat_map(|values| values.iter()).map(|(name, id)| (name.as_str(), *id))),
}
}, document::DOCUMENT_MAX_DEPTH).map_err(|error| PhaseWriteFailure::Write(error.node as i64, error.message, origin))
}
fn main() {
println!("case,sample,implementation,elapsed_ns,checksum");
let numbers = format!("[{}]", vec!["1234567890123456789012345678901234e-12"; 256].join(","));
let mut nested = "1e9999".to_owned();
for _ in 0..48 { nested = format!("{{\"value\":{nested}}}"); }
let text = dever_runtime::wire::json::Json::encode(&vec!["雪\\\"\n".repeat(256); 32]).unwrap().as_str().to_owned();
let ascii = dever_runtime::wire::serde_json::to_string(&vec!["abcdef".repeat(256); 32]).unwrap();
let unicode = dever_runtime::wire::serde_json::to_string(&vec!["雪🙂".repeat(256); 32]).unwrap();
for (name, source) in [("numbers", numbers), ("nested", nested), ("text", text), ("ascii", ascii), ("unicode", unicode)] {
let prepared = PreparedDocument {
generated: GENERATED_PARSE(&source).unwrap(),
reference: reference_nodes(document::parse_with_depth(&source, document::DOCUMENT_MAX_DEPTH).unwrap()),
raw: document::parse_with_depth(&source, document::DOCUMENT_MAX_DEPTH).unwrap(),
};
let inputs = std::slice::from_ref(&source);
compare_named(&format!("{name}_parse_shared"), inputs, 100, phase_raw_parse, phase_raw_parse, |count| *count as u64, "shared");
compare(&format!("{name}_parse_map"), inputs, 100, phase_generated_parse, phase_reference_parse, |count| *count as u64);
let values = &[prepared];
compare_named(&format!("{name}_write_shared"), values, 100, phase_raw_write, phase_raw_write, |value| value.bytes().map(u64::from).sum(), "shared");
compare(&format!("{name}_write_map"), values, 100, phase_generated_write, phase_reference_write, |value| value.bytes().map(u64::from).sum());
compare(&format!("{name}_write_map_contract"), values, 100, phase_generated_write, phase_contract_write, |value| value.bytes().map(u64::from).sum());
compare_named(&format!("{name}_write_adapter"), values, 100, phase_generated_write, phase_adapter_write, |value| value.bytes().map(u64::from).sum(), "shared_engine");
}
}
+130
View File
@@ -0,0 +1,130 @@
// 两侧都接收已验证的 JSON,返回独立拥有的原始子树;不在计时内重复验证输入。
// 独立参照只使用 Serde,不调用 Dever 的键比较或字段读取实现。
use dever_runtime::wire::serde::{
Deserializer,
de::{DeserializeSeed, IgnoredAny, MapAccess, Visitor},
};
use dever_runtime::wire::serde_json::{self, value::RawValue};
struct PropertyCase {
source: Json,
name: String,
}
struct MatchingKey<'name>(&'name str);
impl<'input> DeserializeSeed<'input> for MatchingKey<'_> {
type Value = bool;
fn deserialize<Decoder: Deserializer<'input>>(
self,
decoder: Decoder,
) -> Result<bool, Decoder::Error> {
decoder.deserialize_str(self)
}
}
impl<'input> Visitor<'input> for MatchingKey<'_> {
type Value = bool;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("an object key")
}
fn visit_str<Failure: dever_runtime::wire::serde::de::Error>(
self,
value: &str,
) -> Result<bool, Failure> {
Ok(value == self.0)
}
}
struct MatchingProperty<'name>(&'name str);
impl<'input> Visitor<'input> for MatchingProperty<'_> {
type Value = Option<&'input RawValue>;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("an object")
}
fn visit_map<Access: MapAccess<'input>>(
self,
mut fields: Access,
) -> Result<Self::Value, Access::Error> {
let mut result = None;
while let Some(matches) = fields.next_key_seed(MatchingKey(self.0))? {
if matches {
result = Some(fields.next_value()?);
} else {
fields.next_value::<IgnoredAny>()?;
}
}
Ok(result)
}
}
fn runtime_property(values: &[PropertyCase]) -> Result<Option<String>, Fault> {
let Some(value) = values.first() else {
return Ok(None);
};
value
.source
.property(&value.name)
.map(|found| found.map(Json::into_text))
.map_err(json_fault)
}
fn native_property(values: &[PropertyCase]) -> Result<Option<String>, Fault> {
let Some(value) = values.first() else {
return Ok(None);
};
let mut decoder =
dever_runtime::wire::serde_json::Deserializer::from_str(value.source.as_str());
decoder
.deserialize_map(MatchingProperty(&value.name))
.map(|found| found.map(|raw| raw.get().to_owned()))
.map_err(json_fault)
}
fn property_costs() {
for (kind, suffix) in [("plain", ""), ("escaped", "雪\\\"\n")] {
let names = (0..256)
.map(|index| format!("key_{index:03}_{suffix}"))
.collect::<Vec<_>>();
let fields = names
.iter()
.map(|name| {
format!(
"{}: [ 1e9999, -0, \"\\u96ea\" ]",
serde_json::to_string(name).unwrap()
)
})
.collect::<Vec<_>>();
let source = format!("{{{}}}", fields.join(","));
for (position, name) in [
("first", names[0].as_str()),
("middle", names[128].as_str()),
("last", names[255].as_str()),
("missing", "absent"),
] {
let values = [PropertyCase {
source: Json::parse(&source).unwrap(),
name: name.into(),
}];
let expected =
(position != "missing").then(|| r#"[ 1e9999, -0, "\u96ea" ]"#.to_owned());
assert_eq!(runtime_property(&values).unwrap(), expected);
assert_eq!(native_property(&values).unwrap(), expected);
compare_named(
&format!("json_property_{kind}_{position}"),
&values,
1000,
runtime_property,
native_property,
|value| value.as_ref().map_or(0, |text| text.len() as u64),
"rust_serde",
);
}
}
}
+264
View File
@@ -0,0 +1,264 @@
// 两侧从已验证的原始值开始,独立参照直接序列化 Serde RawValue。
// 此组只比较原文输出;构造与更新成本由现有 json 组同时检查。
struct RawOutputCase {
dever: Json,
rust: Box<RawValue>,
values: usize,
depth: usize,
}
fn runtime_raw_output(values: &[RawOutputCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
Ok(value.dever.as_str().trim_ascii().to_owned())
})
}
fn native_raw_output(values: &[RawOutputCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
serde_json::to_string(&value.rust).map_err(json_fault)
})
}
fn runtime_nested_output(values: &[RawOutputCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
Json::array(std::slice::from_ref(&value.dever)).map(Json::into_text).map_err(json_fault)
})
}
fn native_nested_output(values: &[RawOutputCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
if value.values + 1 > 65_536 || value.depth + 1 > 64 || value.rust.get().len() + 2 > 16 * 1024 * 1024 {
return Err(json_fault("JSON budget"));
}
serde_json::to_string(&[&value.rust]).map_err(json_fault)
})
}
fn generated_nested_array_output(values: &[RawOutputCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
GENERATED_ARRAY(std::slice::from_ref(&value.dever)).map_err(json_fault)
})
}
fn runtime_from_text(values: &[String]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
Json::parse(value).map(Json::into_text).map_err(json_fault)
})
}
fn native_from_text(values: &[String]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
serde_json::from_str::<Box<RawValue>>(value)
.map(|raw| Box::<str>::from(raw).into()).map_err(json_fault)
})
}
fn runtime_from_text_nested(values: &[String]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
let raw = Json::parse(value).map_err(json_fault)?;
Json::array(&[raw]).map(Json::into_text).map_err(json_fault)
})
}
fn native_from_text_nested(values: &[String]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
let raw: Box<RawValue> = serde_json::from_str(value).map_err(json_fault)?;
serde_json::to_string(&[raw]).map_err(json_fault)
})
}
fn from_text_costs(name: &str, source: &str, values: &[RawOutputCase]) {
let count = if name == "short" { 100_000 } else { 1000 };
compare_named(
&format!("json_nested_output_{name}"), values, count,
runtime_nested_output, native_nested_output,
|value| value.len() as u64, "rust_serde",
);
compare_named(
&format!("json_dever_array_output_{name}"), values, count,
generated_nested_array_output, native_nested_output,
|value| value.len() as u64, "rust_serde",
);
// 原生参照仅检查 JSON 语法,不包含 Dever 的去重和预算,不能据此宣称合同追平。
let sources = [source.to_owned()];
compare_named(
&format!("json_from_text_{name}"), &sources, count,
runtime_from_text, native_from_text,
|value| value.len() as u64, "rust_syntax_only",
);
compare_named(
&format!("json_from_text_nested_{name}"), &sources, count,
runtime_from_text_nested, native_from_text_nested,
|value| value.len() as u64, "rust_syntax_only",
);
}
fn raw_output_costs() {
nested_output_costs();
array_output_costs();
for (name, text) in [
("short", "a".repeat(64)),
("plain_4096", "a".repeat(4096)),
("plain_65536", "a".repeat(65536)),
("escaped", "雪\"\\\n".repeat(1024)),
] {
let source = format!(
"{{\"text\":{},\"number\":1e9999}}",
serde_json::to_string(&text).unwrap()
);
let values = [RawOutputCase {
dever: Json::parse(&source).unwrap(),
rust: serde_json::from_str(&source).unwrap(),
// 上面构造的对象恰好包含 text、number 两个标量字段。
values: 3,
depth: 1,
}];
assert_eq!(runtime_raw_output(&values).unwrap(), source);
assert_eq!(native_raw_output(&values).unwrap(), source);
from_text_costs(name, &source, &values);
compare_named(
&format!("json_raw_output_{name}"),
&values,
1000,
runtime_raw_output,
native_raw_output,
|value| value.len() as u64,
"rust_serde",
);
// 输入解码已经取得 RawValue;输出不应丢掉它后再从 String 解析。
let decoded = [RawOutputCase {
dever: serde_json::from_str(&source).unwrap(),
rust: serde_json::from_str(&source).unwrap(),
values: 3,
depth: 1,
}];
compare_named(
&format!("json_decoded_output_{name}"),
&decoded,
1000,
runtime_raw_output,
native_raw_output,
|value| value.len() as u64,
"rust_serde",
);
}
}
struct ArrayOutputCase {
dever: Vec<Json>,
rust: Vec<NativeArrayValue>,
}
struct NativeArrayValue {
raw: Box<RawValue>,
values: usize,
depth: usize,
}
struct NativeArray<'value>(&'value [NativeArrayValue]);
impl Serialize for NativeArray<'_> {
fn serialize<Encoder: Serializer>(&self, encoder: Encoder) -> Result<Encoder::Ok, Encoder::Error> {
use dever_runtime::wire::serde::ser::{Error, SerializeSeq};
let mut sequence = encoder.serialize_seq(Some(self.0.len()))?;
let mut count = 1;
let mut bytes = 2;
for (index, value) in self.0.iter().enumerate() {
count += value.values;
bytes += value.raw.get().len() + usize::from(index != 0);
if count > 65_536 || value.depth + 1 > 64 || bytes > 16 * 1024 * 1024 {
return Err(Encoder::Error::custom("JSON budget"));
}
sequence.serialize_element(&value.raw)?;
}
sequence.end()
}
}
fn runtime_array_output(values: &[ArrayOutputCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
Json::array(&value.dever).map(Json::into_text).map_err(json_fault)
})
}
fn native_array_output(values: &[ArrayOutputCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
serde_json::to_string(&NativeArray(&value.rust)).map_err(json_fault)
})
}
fn generated_array_output(values: &[ArrayOutputCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| {
GENERATED_ARRAY(&value.dever).map_err(json_fault)
})
}
fn array_output_costs() {
for count in [0, 1, 4, 16] {
let sources: Vec<_> = [" null ", " [1,-0] ", r#" {"雪":"\u96ea"} "#, " [] "]
.into_iter().cycle().take(count).collect();
// 两侧每个子值都已验证且保留结构统计;计时包含合并预算和完整写出。
let values = [ArrayOutputCase {
dever: sources.iter().map(|source| Json::parse(source).unwrap()).collect(),
rust: sources.iter().map(|source| {
let (values, depth) = reference_shape(&serde_json::from_str(source).unwrap());
NativeArrayValue { raw: serde_json::from_str(source).unwrap(), values, depth }
}).collect(),
}];
compare_named(&format!("json_array_mixed_{count}"), &values, 100_000,
runtime_array_output, native_array_output, |value| value.len() as u64, "rust_bounded");
compare_named(&format!("json_dever_array_mixed_{count}"), &values, 100_000,
generated_array_output, native_array_output, |value| value.len() as u64, "rust_bounded");
}
}
struct NestedCase {
dever: Json,
rust: Box<RawValue>,
values: usize,
depth: usize,
}
fn runtime_nested_record(values: &[NestedCase]) -> Result<String, Fault> {
values.first().map_or(Ok(String::new()), |value| GENERATED_NESTED(&value.dever).map_err(json_fault))
}
fn native_nested_record(values: &[NestedCase]) -> Result<String, Fault> {
#[derive(Serialize)]
#[serde(crate = "dever_runtime::wire::serde")]
struct Nested<'value> { value: &'value RawValue }
let Some(value) = values.first() else { return Ok(String::new()); };
if value.values + 1 > 65_536 || value.depth + 1 > 64 || value.rust.get().len() + 10 > 16 * 1024 * 1024 {
return Err(json_fault("JSON budget"));
}
serde_json::to_string(&Nested { value: &value.rust }).map_err(json_fault)
}
fn reference_shape(value: &serde_json::Value) -> (usize, usize) {
let children: Vec<_> = match value {
serde_json::Value::Array(values) => values.iter().map(reference_shape).collect(),
serde_json::Value::Object(values) => values.values().map(reference_shape).collect(),
_ => return (1, 0),
};
(1 + children.iter().map(|child| child.0).sum::<usize>(), 1 + children.iter().map(|child| child.1).max().unwrap_or(0))
}
fn nested_output_costs() {
for (name, text) in [
("short", "a".repeat(64)),
("plain_4096", "a".repeat(4096)),
("plain_65536", "a".repeat(65536)),
("escaped", "雪\"\\\n".repeat(1024)),
] {
let source = format!("{{\"text\":{},\"number\":-0}}", serde_json::to_string(&text).unwrap());
// 两侧都从已验证原文及结构信息开始;独立 Rust 不调用 Dever 的验证或输出。
let (count, depth) = reference_shape(&serde_json::from_str(&source).unwrap());
let values = [NestedCase {
dever: Json::parse(&source).unwrap(),
rust: serde_json::from_str(&source).unwrap(), values: count, depth,
}];
compare_named(&format!("json_dever_nested_{name}"), &values,
if name == "short" { 100_000 } else { 1000 },
runtime_nested_record, native_nested_record, |value| value.len() as u64, "rust_bounded");
}
}
+208
View File
@@ -0,0 +1,208 @@
//! 冻结原写出算法供前后对照;生产运行库不依赖此通用节点适配。
use dever_runtime::wire::document::{MAX_BYTES, MAX_VALUES, WriteError};
use dever_runtime::wire::serde_json;
pub enum Node<Text, Children, Members> {
Null,
Boolean(bool),
Number(Text),
String(Text),
Array(Children),
Object(Members),
}
#[derive(Clone, Copy)]
struct Size {
bytes: usize,
values: usize,
depth: usize,
}
/// 节点直接按下标借用,编号和文档结构在 measure 中检查;不再给取节点包装错误通道。
pub fn stringify_nodes<'node, Children, Members>(
root: usize,
count: usize,
node: impl Fn(usize) -> Node<&'node str, Children, Members>,
max_depth: usize,
) -> Result<String, WriteError>
where
Children: Iterator<Item = i64>,
Members: Iterator<Item = (&'node str, i64)>,
{
let bytes = measure(root, count, &node, max_depth)?;
let mut output = String::with_capacity(bytes);
write_node(&node, root, &mut output);
Ok(output)
}
fn measure<'node, Children, Members>(
root: usize,
count: usize,
node: &impl Fn(usize) -> Node<&'node str, Children, Members>,
max_depth: usize,
) -> Result<usize, WriteError>
where
Children: Iterator<Item = i64>,
Members: Iterator<Item = (&'node str, i64)>,
{
let fail = |node, message: &str| WriteError {
node,
message: message.into(),
};
if count > MAX_VALUES {
return Err(fail(root, "JSON node count exceeds 65536 values"));
}
if root >= count {
return Err(fail(root, "JSON root does not refer to a document node"));
}
let mut sizes = Vec::<Size>::with_capacity(count);
for index in 0..count {
let mut size = Size {
bytes: 0,
values: 1,
depth: 0,
};
match node(index) {
Node::Null => size.bytes = 4,
Node::Boolean(value) => size.bytes = if value { 4 } else { 5 },
Node::Number(raw) => {
if !matches!(raw.as_bytes().first(), Some(b'-' | b'0'..=b'9'))
|| !serde_json::from_str::<&serde_json::value::RawValue>(raw)
.is_ok_and(|value| value.get() == raw)
{
return Err(fail(index, "invalid JSON number"));
}
size.bytes = raw.len();
}
Node::String(text) => size.bytes = string_size(text),
Node::Array(children) => {
size.bytes = 2;
size.depth = 1;
for (position, child) in children.enumerate() {
size.bytes += usize::from(position != 0);
add_child(&mut size, child, &sizes, index, max_depth)?;
}
}
Node::Object(fields) => {
size.bytes = 2;
size.depth = 1;
for (position, (name, child)) in fields.enumerate() {
size.bytes += string_size(name) + 1 + usize::from(position != 0);
add_child(&mut size, child, &sizes, index, max_depth)?;
}
}
}
check(size, index, max_depth)?;
sizes.push(size);
}
Ok(sizes[root].bytes)
}
fn add_child(
size: &mut Size,
child: i64,
sizes: &[Size],
node: usize,
max_depth: usize,
) -> Result<(), WriteError> {
let child = usize::try_from(child).map_err(|_| WriteError {
node,
message: "negative JSON node ID".into(),
})?;
let child = sizes.get(child).ok_or_else(|| WriteError {
node,
message: "JSON child must precede parent".into(),
})?;
size.bytes += child.bytes;
size.values += child.values;
size.depth = size.depth.max(child.depth + 1);
check(*size, node, max_depth)
}
fn check(size: Size, node: usize, max_depth: usize) -> Result<(), WriteError> {
let message = if size.bytes > MAX_BYTES {
"JSON exceeds 16 MiB"
} else if size.values > MAX_VALUES {
"JSON contains more than 65536 values"
} else if size.depth > max_depth {
"JSON nesting exceeds configured limit"
} else {
return Ok(());
};
Err(WriteError {
node,
message: message.into(),
})
}
fn string_size(text: &str) -> usize {
text.len()
+ 2
+ text
.bytes()
.map(|byte| match byte {
b'"' | b'\\' | 8 | 12 | b'\n' | b'\r' | b'\t' => 1,
0..=31 => 5,
_ => 0,
})
.sum::<usize>()
}
fn write_node<'node, Children, Members>(
node: &impl Fn(usize) -> Node<&'node str, Children, Members>,
index: usize,
output: &mut String,
) where
Children: Iterator<Item = i64>,
Members: Iterator<Item = (&'node str, i64)>,
{
match node(index) {
Node::Null => output.push_str("null"),
Node::Boolean(value) => output.push_str(if value { "true" } else { "false" }),
Node::Number(raw) => output.push_str(raw),
Node::String(text) => write_string(text, output),
Node::Array(children) => {
output.push('[');
for (position, child) in children.enumerate() {
if position != 0 {
output.push(',');
}
write_node(node, child as usize, output);
}
output.push(']');
}
Node::Object(fields) => {
output.push('{');
for (position, (name, child)) in fields.enumerate() {
if position != 0 {
output.push(',');
}
write_string(name, output);
output.push(':');
write_node(node, child as usize, output);
}
output.push('}');
}
}
}
fn write_string(text: &str, output: &mut String) {
output.push('"');
for character in text.chars() {
match character {
'"' => output.push_str("\\\""),
'\\' => output.push_str("\\\\"),
'\u{08}' => output.push_str("\\b"),
'\u{0c}' => output.push_str("\\f"),
'\n' => output.push_str("\\n"),
'\r' => output.push_str("\\r"),
'\t' => output.push_str("\\t"),
character if character < '\u{20}' => {
use std::fmt::Write;
write!(output, "\\u{:04x}", character as u32).unwrap();
}
character => output.push(character),
}
}
output.push('"');
}