Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -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");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user