5个版本
0.1.1 | 2023年11月10日 |
---|---|
0.1.0 | 2023年11月7日 |
#328 in 编码
每月 29 次下载
44KB
855 行
Typed JSON —
Typed JSON提供了一个json!
宏,用于构建具有非常自然JSON语法的impl serde::Serialize
类型。
use typed_json::json;
// The type of `john` is `impl serde::Serialize`
let john = json!({
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
});
// Convert to a string of JSON and print it out
println!("{}", serde_json::to_string(&john).unwrap());
关于json!
宏的一个巧妙之处是,您可以直接将变量和表达式插入到正在构建的JSON值中。Serde将在编译时检查您插入的值是否能够表示为JSON。
let full_name = "John Doe";
let age_last_year = 42;
fn random_phone() -> String {
"0".to_owned()
}
// The type of `john` is `impl serde::Serialize`
let john = typed_json::json!({
"name": full_name,
"age": age_last_year + 1,
"phones": [
format!("+44 {}", random_phone())
]
});
与serde_json
的比较
此crate提供了一个serde_json::json!()
的泛型版本。这意味着它执行0次分配,并为您表示的JSON对象创建一个自定义类型。对于一次性JSON文档,这最终使得编码速度快得多。这与serde_json::json!()
语法100%兼容,自serde_json = "1.0.108"
以来。
基准测试
以下基准测试表明将一个复杂的深层嵌套JSON文档序列化为String
。
注意:
typed_json_core
基准测试使用serde-json-core
将数据编码为heapless::String
。
Timer precision: 41 ns
serialize_string fastest │ slowest │ median │ mean │ samples │ iters
├─ serde_json 765.3 ns │ 15.1 µs │ 807 ns │ 824.9 ns │ 100000 │ 800000
├─ typed_json 148.1 ns │ 1.606 µs │ 153.3 ns │ 156 ns │ 100000 │ 3200000
╰─ typed_json_core 217.1 ns │ 2.991 µs │ 228.8 ns │ 240.4 ns │ 100000 │ 3200000
注意:基准测试使用
serde_json::to_string
,因为它比ToString
/Display
实现快得多,适用于serde_json::json
和typed_json::json
。
无std支持
您可以使用仅含core
的typed_json
。禁用默认的"std"功能。
[dependencies]
typed_json = { version = "0.1", default-features = false }
将 Serialize
类型编码为 JSON
您可能需要 serde_json
并启用 alloc
功能
[dependencies]
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
或者 serde-json-core
,无需依赖 alloc
[dependencies]
serde-json-core = "0.5.1"
工作原理
注意:这些都是实现细节,都不是稳定的 API
let data = json!({
"codes": [400, value1, value2],
"message": value3,
"contact": "contact support at [email protected]"
});
扩展成类似
let data = typed_json::__private::Map(hlist![
typed_json::__private::KV::Pair(
typed_json::__private::Expr("codes"),
typed_json::__private::Array(hlist![
typed_json::__private::Expr(400),
typed_json::__private::Expr(value1),
typed_json::__private::Expr(value2),
]),
),
typed_json::__private::KV::Pair(
typed_json::__private::Expr("message"),
typed_json::__private::Expr(value3)
),
typed_json::__private::KV::Pair(
typed_json::__private::Expr("contact"),
typed_json::__private::Expr("contact support at [email protected]")
),
]);
的形式,其中 hlist![a, b, c, d, e]
将扩展成
(a, ((b, c), (d, e)))
编译时基准测试
没有真正的零成本抽象。然而,有时似乎 typed-json
编译速度比 serde_json
快,有时则相反。
我使用了来自 https://kubernetesjsonschema.dev/ 的大型服务 JSON 进行编译时间测量。
基准测试细节
许多小文档
在这个测试中,我已经将上述 JSON 文件分割成 31 个合理大小的文档
调试
$ hyperfine \
--command-name "typed_json" \
"pushd tests/crates/stress3 && touch src/main.rs && cargo build" \
--command-name "serde_json" \
"pushd tests/crates/stress4 && touch src/main.rs && cargo build"
Benchmark 1: typed_json
Time (mean ± σ): 148.6 ms ± 3.7 ms [User: 141.2 ms, System: 82.0 ms]
Range (min … max): 143.3 ms … 157.0 ms 20 runs
Benchmark 2: serde_json
Time (mean ± σ): 151.7 ms ± 4.8 ms [User: 134.9 ms, System: 98.5 ms]
Range (min … max): 143.2 ms … 163.0 ms 20 runs
Summary
typed_json ran
1.02 ± 0.04 times faster than serde_json
发布
$ hyperfine \
--command-name "typed_json" \
"pushd tests/crates/stress3 && touch src/main.rs && cargo build --release" \
--command-name "serde_json" \
"pushd tests/crates/stress4 && touch src/main.rs && cargo build --release"
Benchmark 1: typed_json
Time (mean ± σ): 538.3 ms ± 7.1 ms [User: 877.5 ms, System: 65.7 ms]
Range (min … max): 527.4 ms … 550.9 ms 10 runs
Benchmark 2: serde_json
Time (mean ± σ): 1.003 s ± 0.013 s [User: 1.194 s, System: 0.075 s]
Range (min … max): 0.972 s … 1.020 s 10 runs
Summary
typed_json ran
1.86 ± 0.04 times faster than serde_json
一次性大文档
在这个测试中,我已经将单个 JSON 文件原样包含在内。我认为这不是一个现实的应用场景,但仍很有趣
调试
$ hyperfine \
--command-name "typed_json" \
"pushd tests/crates/stress1 && touch src/main.rs && cargo build" \
--command-name "serde_json" \
"pushd tests/crates/stress2 && touch src/main.rs && cargo build"
Benchmark 1: typed_json
Time (mean ± σ): 157.5 ms ± 6.1 ms [User: 147.9 ms, System: 83.5 ms]
Range (min … max): 152.1 ms … 178.4 ms 18 runs
Benchmark 2: serde_json
Time (mean ± σ): 151.7 ms ± 4.5 ms [User: 133.6 ms, System: 97.9 ms]
Range (min … max): 145.1 ms … 162.4 ms 18 runs
Summary
serde_json ran
1.04 ± 0.05 times faster than typed_json
发布
$ hyperfine \
--command-name "typed_json" \
"pushd tests/crates/stress1 && touch src/main.rs && cargo build --release" \
--command-name "serde_json" \
"pushd tests/crates/stress2 && touch src/main.rs && cargo build --release"
Benchmark 1: typed_json
Time (mean ± σ): 1.501 s ± 0.012 s [User: 2.324 s, System: 0.090 s]
Range (min … max): 1.480 s … 1.520 s 10 runs
Benchmark 2: serde_json
Time (mean ± σ): 947.3 ms ± 20.4 ms [User: 1142.0 ms, System: 71.2 ms]
Range (min … max): 918.7 ms … 989.0 ms 10 runs
Summary
serde_json ran
1.58 ± 0.04 times faster than typed_json
结论
我认为我无法断言 typed-json 在标准使用中引入了编译时退步。在极端情况下,它可能需要编译更多类型,但在标准使用中,它可以重用大量的先前编译
依赖关系
~110–440KB