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

+167
View File
@@ -0,0 +1,167 @@
// 对比实际运行库、Axum Query 和其底层 serde_urlencoded;不包含网络或路由耗时。
// 默认库的错误输入行为另行检查,合法输入计时不能证明完整边界语义等价。
use axum::{extract::Query, http::Uri};
use dever_runtime::api::{self, Request};
use serde::{Deserialize, de::DeserializeOwned};
#[derive(Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct QueryArguments {
name: String,
count: i64,
enabled: bool,
ratio: f64,
tag: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct WideArguments {
field0: String,
field1: String,
field2: String,
field3: String,
field4: String,
field5: String,
field6: String,
field7: String,
field8: String,
field9: String,
field10: String,
field11: String,
field12: String,
field13: String,
field14: String,
field15: String,
field16: String,
field17: String,
field18: String,
field19: String,
field20: String,
field21: String,
field22: String,
field23: String,
field24: String,
field25: String,
field26: String,
field27: String,
field28: String,
field29: String,
field30: String,
field31: String,
}
struct QueryInput {
request: Request,
uri: Uri,
}
fn query_fault(_: impl std::fmt::Display) -> Fault {
&FaultInfo {
message: "invalid query",
source: "query-comparison",
line: 1,
column: 1,
}
}
fn runtime_query<Arguments: DeserializeOwned>(
values: &[QueryInput],
) -> Result<Option<Arguments>, Fault> {
let Some(input) = values.first() else {
return Ok(None);
};
api::input(&input.request)
.map_err(query_fault)?
.decode(dever_runtime::wire::decode)
.map(Some)
.map_err(query_fault)
}
fn axum_query<Arguments: DeserializeOwned>(
values: &[QueryInput],
) -> Result<Option<Arguments>, Fault> {
let Some(input) = values.first() else {
return Ok(None);
};
Query::<Arguments>::try_from_uri(&input.uri)
.map(|Query(arguments)| Some(arguments))
.map_err(query_fault)
}
fn serde_query<Arguments: DeserializeOwned>(
values: &[QueryInput],
) -> Result<Option<Arguments>, Fault> {
let Some(input) = values.first() else {
return Ok(None);
};
serde_urlencoded::from_str(input.uri.query().unwrap_or_default())
.map(Some)
.map_err(query_fault)
}
fn query_input(query: &str) -> QueryInput {
let target = format!("/test?{query}");
QueryInput {
uri: target.parse().unwrap(),
request: axum::http::Request::builder()
.uri(target)
.body(Default::default())
.unwrap(),
}
}
fn query_comparison<Arguments: DeserializeOwned + PartialEq + std::fmt::Debug>(
name: &str,
query: &str,
count: usize,
) {
let input = [query_input(query)];
for (label, decoder) in [
("axum", axum_query::<Arguments> as fn(&[QueryInput]) -> _),
(
"serde_urlencoded",
serde_query::<Arguments> as fn(&[QueryInput]) -> _,
),
] {
compare_named(
&format!("query_{name}_{label}"),
&input,
count,
runtime_query::<Arguments>,
decoder,
|output| u64::from(output.is_some()),
label,
);
}
}
fn main() {
if std::env::args().any(|argument| argument == "--check") {
query_checks();
return;
}
println!("case,sample,implementation,elapsed_ns,checksum");
for (name, value, count) in [
("plain", "Alice".to_owned(), 20_000),
("unicode", "%E9%9B%AA+test".to_owned(), 20_000),
("escaped", "%22%5C%00%26%3D%25".repeat(8), 10_000),
("long", "value%2B%E9%9B%AA".repeat(256), 1_000),
] {
query_comparison::<QueryArguments>(
name,
&format!("name={value}&count=-7&enabled=true&ratio=1.25&tag=demo"),
count,
);
}
for (name, value, count) in [
("wide_plain", "testvalue".to_owned(), 2_000),
("wide_escaped", "value%2B%E9%9B%AA".repeat(8), 500),
] {
let query = (0..32)
.map(|index| format!("field{index}={value}"))
.collect::<Vec<_>>()
.join("&");
query_comparison::<WideArguments>(name, &query, count);
}
}