// 两侧从已验证的原始值开始,独立参照直接序列化 Serde RawValue。 // 此组只比较原文输出;构造与更新成本由现有 json 组同时检查。 struct RawOutputCase { dever: Json, rust: Box, values: usize, depth: usize, } fn runtime_raw_output(values: &[RawOutputCase]) -> Result { values.first().map_or(Ok(String::new()), |value| { Ok(value.dever.as_str().trim_ascii().to_owned()) }) } fn native_raw_output(values: &[RawOutputCase]) -> Result { 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 { 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 { 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 { 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 { 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 { values.first().map_or(Ok(String::new()), |value| { serde_json::from_str::>(value) .map(|raw| Box::::from(raw).into()).map_err(json_fault) }) } fn runtime_from_text_nested(values: &[String]) -> Result { 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 { values.first().map_or(Ok(String::new()), |value| { let raw: Box = 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, rust: Vec, } struct NativeArrayValue { raw: Box, values: usize, depth: usize, } struct NativeArray<'value>(&'value [NativeArrayValue]); impl Serialize for NativeArray<'_> { fn serialize(&self, encoder: Encoder) -> Result { 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 { 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 { 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 { 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, values: usize, depth: usize, } fn runtime_nested_record(values: &[NestedCase]) -> Result { values.first().map_or(Ok(String::new()), |value| GENERATED_NESTED(&value.dever).map_err(json_fault)) } fn native_nested_record(values: &[NestedCase]) -> Result { #[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::(), 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"); } }