Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,274 @@
|
||||
use dever_runtime::wire::{
|
||||
self,
|
||||
serde::{self, Deserialize, Serialize},
|
||||
};
|
||||
|
||||
struct Object<Value>(Value);
|
||||
|
||||
impl<'input, Value: Deserialize<'input>> Deserialize<'input> for Object<Value> {
|
||||
fn deserialize<Decoder: serde::Deserializer<'input>>(
|
||||
decoder: Decoder,
|
||||
) -> Result<Self, Decoder::Error> {
|
||||
wire::object(decoder).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(crate = "dever_runtime::wire::serde", deny_unknown_fields)]
|
||||
struct Greeting {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(crate = "dever_runtime::wire::serde", deny_unknown_fields)]
|
||||
struct Integer {
|
||||
value: i64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "dever_runtime::wire::serde", deny_unknown_fields)]
|
||||
struct Profile {
|
||||
id: Id,
|
||||
name: String,
|
||||
scores: Vec<i64>,
|
||||
ratio: Option<f64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(crate = "dever_runtime::wire::serde", deny_unknown_fields)]
|
||||
struct Echo {
|
||||
value: Object<Profile>,
|
||||
}
|
||||
|
||||
fn fault(_: String) -> Fault {
|
||||
&FaultInfo {
|
||||
message: "command failure",
|
||||
source: "reference.dever",
|
||||
line: 1,
|
||||
column: 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn greeting_generated(values: &[&str]) -> Result<String, Fault> {
|
||||
GENERATED_GREETING(values.first().copied().unwrap_or(r#"{"name":""}"#)).map_err(fault)
|
||||
}
|
||||
|
||||
fn greeting_reference(values: &[&str]) -> Result<String, Fault> {
|
||||
let input: Object<Greeting> =
|
||||
wire::decode(values.first().copied().unwrap_or(r#"{"name":""}"#)).map_err(fault)?;
|
||||
let mut result = String::with_capacity(input.0.name.len() + 9);
|
||||
result.push_str("[Hello, ");
|
||||
result.push_str(&input.0.name);
|
||||
result.push(']');
|
||||
wire::response(&result).map_err(fault)
|
||||
}
|
||||
|
||||
fn echo_generated(values: &[&str]) -> Result<String, Fault> {
|
||||
GENERATED_ECHO(
|
||||
values
|
||||
.first()
|
||||
.copied()
|
||||
.unwrap_or(r#"{"value":{"id":"","name":"","scores":[]}}"#),
|
||||
)
|
||||
.map_err(fault)
|
||||
}
|
||||
|
||||
fn echo_reference(values: &[&str]) -> Result<String, Fault> {
|
||||
let input: Object<Echo> = wire::decode(
|
||||
values
|
||||
.first()
|
||||
.copied()
|
||||
.unwrap_or(r#"{"value":{"id":"","name":"","scores":[]}}"#),
|
||||
)
|
||||
.map_err(fault)?;
|
||||
let result = input.0.value.0;
|
||||
if result.ratio.is_some_and(|value| !value.is_finite()) {
|
||||
return Err(fault("non-finite Float".into()));
|
||||
}
|
||||
wire::response(&result).map_err(fault)
|
||||
}
|
||||
|
||||
fn double_generated(values: &[&str]) -> Result<String, Fault> {
|
||||
GENERATED_DOUBLE(values.first().copied().unwrap_or(r#"{"value":0}"#)).map_err(fault)
|
||||
}
|
||||
|
||||
fn double_reference(values: &[&str]) -> Result<String, Fault> {
|
||||
let input: Object<Integer> =
|
||||
wire::decode(values.first().copied().unwrap_or(r#"{"value":0}"#)).map_err(fault)?;
|
||||
let result = input
|
||||
.0
|
||||
.value
|
||||
.checked_mul(2)
|
||||
.ok_or_else(|| fault("overflow".into()))?;
|
||||
wire::response(&result).map_err(fault)
|
||||
}
|
||||
|
||||
// 独立对照只处理这里的固定标量 record;结构预算由这两个协议本身保证。
|
||||
// 不调用 Dever 的 object/decode/response,也不替换原来的共享运行库对照。
|
||||
fn rust_input<Value: serde::de::DeserializeOwned>(input: &str) -> Result<Value, Fault> {
|
||||
if input.len() > 16 * 1024 * 1024 {
|
||||
return Err(fault("input limit".into()));
|
||||
}
|
||||
struct Record<Value>(std::marker::PhantomData<Value>);
|
||||
impl<'input, Value: Deserialize<'input>> serde::de::Visitor<'input> for Record<Value> {
|
||||
type Value = Value;
|
||||
fn expecting(&self, output: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
output.write_str("an object")
|
||||
}
|
||||
fn visit_map<Access: serde::de::MapAccess<'input>>(
|
||||
self,
|
||||
access: Access,
|
||||
) -> Result<Value, Access::Error> {
|
||||
Value::deserialize(serde::de::value::MapAccessDeserializer::new(access))
|
||||
}
|
||||
}
|
||||
let mut decoder = serde_json::Deserializer::from_str(input);
|
||||
let value =
|
||||
serde::Deserializer::deserialize_map(&mut decoder, Record(std::marker::PhantomData))
|
||||
.map_err(|error| fault(error.to_string()))?;
|
||||
decoder.end().map_err(|error| fault(error.to_string()))?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn rust_response<Value: Serialize>(data: Value) -> Result<String, Fault> {
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "dever_runtime::wire::serde")]
|
||||
struct Response<Value> {
|
||||
code: u16,
|
||||
message: &'static str,
|
||||
data: Value,
|
||||
}
|
||||
struct Buffer(Vec<u8>);
|
||||
impl std::io::Write for Buffer {
|
||||
fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
|
||||
if bytes.len() > 16 * 1024 * 1024 - self.0.len() {
|
||||
return Err(std::io::Error::other("output limit"));
|
||||
}
|
||||
self.0.extend_from_slice(bytes);
|
||||
Ok(bytes.len())
|
||||
}
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
// 与 serde_json::to_vec 相同;独立 Rust 参照也避免短输出反复扩容。
|
||||
let mut output = Buffer(Vec::with_capacity(128));
|
||||
serde_json::to_writer(
|
||||
&mut output,
|
||||
&Response {
|
||||
code: 0,
|
||||
message: "ok",
|
||||
data,
|
||||
},
|
||||
)
|
||||
.map_err(|error| fault(error.to_string()))?;
|
||||
Ok(String::from_utf8(output.0).unwrap())
|
||||
}
|
||||
|
||||
fn greeting_rust(values: &[&str]) -> Result<String, Fault> {
|
||||
let input: Greeting = rust_input(values.first().copied().unwrap_or(r#"{"name":""}"#))?;
|
||||
let mut result = String::with_capacity(input.name.len() + 9);
|
||||
result.push_str("[Hello, ");
|
||||
result.push_str(&input.name);
|
||||
result.push(']');
|
||||
rust_response(result)
|
||||
}
|
||||
|
||||
fn double_rust(values: &[&str]) -> Result<String, Fault> {
|
||||
let input: Integer = rust_input(values.first().copied().unwrap_or(r#"{"value":0}"#))?;
|
||||
rust_response(
|
||||
input
|
||||
.value
|
||||
.checked_mul(2)
|
||||
.ok_or_else(|| fault("overflow".into()))?,
|
||||
)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
for input in [
|
||||
r#"{"value":9223372036854775807}"#,
|
||||
r#"{"value":1,"value":2}"#,
|
||||
"[1]",
|
||||
"{}",
|
||||
] {
|
||||
assert_eq!(
|
||||
double_generated(&[input]).is_err(),
|
||||
double_reference(&[input]).is_err()
|
||||
);
|
||||
assert_eq!(
|
||||
double_generated(&[input]).is_err(),
|
||||
double_rust(&[input]).is_err()
|
||||
);
|
||||
}
|
||||
for input in [
|
||||
r#"{"value":["a","b",[],null]}"#,
|
||||
r#"{"value":{"id":"a","name":"b","scores":[],"extra":1}}"#,
|
||||
] {
|
||||
assert_eq!(
|
||||
echo_generated(&[input]).is_err(),
|
||||
echo_reference(&[input]).is_err()
|
||||
);
|
||||
}
|
||||
let long_name = "雪".repeat(2048);
|
||||
let long_greeting = format!("{{\"name\":\"{long_name}\"}}");
|
||||
let echo = format!(
|
||||
"{{\"value\":{{\"id\":\"a\",\"name\":\"{long_name}\",\"scores\":[1,2,3],\"ratio\":0.5}}}}"
|
||||
);
|
||||
println!("case,sample,implementation,elapsed_ns,checksum");
|
||||
compare(
|
||||
"command_greet_short",
|
||||
&[r#"{"name":"Dever"}"#],
|
||||
50000,
|
||||
greeting_generated,
|
||||
greeting_reference,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
compare(
|
||||
"command_greet_long",
|
||||
&[long_greeting.as_str()],
|
||||
3000,
|
||||
greeting_generated,
|
||||
greeting_reference,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
compare(
|
||||
"command_echo",
|
||||
&[echo.as_str()],
|
||||
3000,
|
||||
echo_generated,
|
||||
echo_reference,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
compare(
|
||||
"command_double",
|
||||
&[r#"{"value":21}"#],
|
||||
50000,
|
||||
double_generated,
|
||||
double_reference,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
compare(
|
||||
"command_greet_short_independent",
|
||||
&[r#"{"name":"Dever"}"#],
|
||||
50000,
|
||||
greeting_generated,
|
||||
greeting_rust,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
compare(
|
||||
"command_greet_long_independent",
|
||||
&[long_greeting.as_str()],
|
||||
3000,
|
||||
greeting_generated,
|
||||
greeting_rust,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
compare(
|
||||
"command_double_independent",
|
||||
&[r#"{"value":21}"#],
|
||||
50000,
|
||||
double_generated,
|
||||
double_rust,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user