10个稳定版本
2.4.0 | 2024年8月16日 |
---|---|
2.3.1 | 2024年8月16日 |
2.1.2 | 2024年7月31日 |
1.0.1 | 2024年7月29日 |
124 in 编码
910 monthly downloads
Used in merde_json_types
61KB
1.5K SLoC
merde_json
Logo by Misiasart
merde_json
通过特质、声明性宏和一些纪律,涵盖了“90%的使用场景”的JSON操作。
它优化了编译时间短和避免复制(但不是所有分配),如果愿意放弃一些proc宏的便利,非常适合用于Web服务器。
底层的JSON解析器是jiter,它提供了一个基于事件的用户界面,当merde_json的性能不足以满足需求时,可以选择使用。
约定 + 从 serde_json
迁移
serde 允许您使用proc宏推导 Serialize
和 Deserialize
特质
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct MyStruct {
name: String,
age: u8,
}
相比之下,merde_json提供声明性宏
use merde_json::Fantome;
use std::borrow::Cow;
#[derive(Debug, PartialEq)]
struct MyStruct<'src, 'val> {
_boo: Fantome<'src, 'val>,
name: Cow<'val, str>,
age: u8,
}
merde_json::derive! {
impl(JsonSerialize, JsonDeserialize) for MyStruct {
name,
age
}
}
声明性宏 = 在编译时要做的工作更少,只要遵循几条规则
- 所有结构体恰好有两个生命周期参数:'src和'val
- 所有结构体都有一个
_boo
字段,用于不使用生命周期参数的结构体 - 字段名称在结构体和宏中都列出了两次(声明性宏的限制)
- 对于所有字符串,使用
Cow<'val, str>
,而不是根据情况在&str
和String
之间选择
阅读 《Cows的神秘生活》 了解Rust的“写时复制”类型的简介。
反序列化
[from_str][] 是jiter API的薄包装,底层的JSON解析器。它为您提供 JsonValue
,然后您可以通过 [JsonDeserialize] 特质将其解构为Rust值
# use merde_json::{Fantome, JsonDeserialize, JsonSerialize, ToRustValue};
# use std::borrow::Cow;
#
# #[derive(Debug, PartialEq)]
# struct MyStruct<'src, 'val> {
# _boo: Fantome<'src, 'val>,
#
# name: Cow<'val, str>,
# age: u8,
# }
#
# merde_json::derive! {
# impl(JsonSerialize, JsonDeserialize) for MyStruct { name, age }
# }
#
# fn main() -> Result<(), merde_json::MerdeJsonError> {
let input = String::from(r#"{"name": "John Doe", "age": 30}"#);
let value = merde_json::from_str(&input)?;
let my_struct = MyStruct::json_deserialize(Some(&value));
println!("{:?}", my_struct);
# Ok(())
# }
为了方便起见,您可以使用ToRustValue::to_rust_value
# use merde_json::{Fantome, JsonDeserialize, JsonSerialize, ToRustValue};
# use std::borrow::Cow;
#
# #[derive(Debug, PartialEq)]
# struct MyStruct<'src, 'val> {
# _boo: Fantome<'src, 'val>,
# name: Cow<'val, str>,
# age: u8,
# }
#
# merde_json::derive! {
# impl(JsonSerialize, JsonDeserialize) for MyStruct { name, age }
# }
#
# fn main() -> Result<(), merde_json::MerdeJsonError> {
let input = String::from(r#"{"name": "John Doe", "age": 30}"#);
let value = merde_json::from_str(&input)?;
// Note: you have to specify the binding's type here.
// We can't use a turbofish anymore than we can with `Into::into`.
let my_struct: MyStruct = value.to_rust_value()?;
println!("{:?}", my_struct);
# Ok(())
# }
然而,不要忽视这样一个事实,my_struct
从value
借用,而value
又从input
借用。
我们需要三个显式绑定,尽管尝试内联其中之一很诱人。这将导致编译错误“临时值在借用时已丢弃”
# use merde_json::{Fantome, JsonDeserialize, JsonSerialize, ToRustValue};
# use std::borrow::Cow;
#
# #[derive(Debug, PartialEq)]
# struct MyStruct<'src, 'val> {
# _boo: Fantome<'src, 'val>,
# name: Cow<'val, str>,
# age: u8,
# }
#
# merde_json::derive! {
# impl(JsonSerialize, JsonDeserialize) for MyStruct { name, age }
# }
#
# fn main() -> Result<(), merde_json::MerdeJsonError> {
let input = String::from(r#"{"name": "John Doe", "age": 30}"#);
let value = merde_json::from_str(&input).unwrap();
let my_struct = MyStruct::json_deserialize(Some(&merde_json::from_str(&input).unwrap()));
println!("{:?}", my_struct);
# Ok(())
# }
移动反序列化的值
如何返回一个新反序列化的值,同时处理那两个令人烦恼的生命周期?
将它们都设置为'static
!然而,这失败了,因为反序列化的值不是T<'static, 'static>
—— 它仍然从源代码('src
)和被反序列化的JsonValue
('val
)借用。
此代码无法编译
# use merde_json::{Fantome, JsonDeserialize, JsonSerialize, ToRustValue};
# use std::borrow::Cow;
#
# #[derive(Debug, PartialEq)]
# struct MyStruct<'src, 'val> {
# _boo: Fantome<'src, 'val>,
# name: Cow<'val, str>,
# age: u8,
# }
#
# merde_json::derive! {
# impl(JsonSerialize, JsonDeserialize) for MyStruct { name, age }
# }
#
fn return_my_struct() -> MyStruct<'static, 'static> {
let input = String::from(r#"{"name": "John Doe", "age": 30}"#);
let value = merde_json::from_str(&input).unwrap();
let my_struct: MyStruct = value.to_rust_value().unwrap();
my_struct
}
# fn main() -> Result<(), merde_json::MerdeJsonError> {
let my_struct = return_my_struct();
println!("{:?}", my_struct);
# Ok(())
# }
...
---- src/lib.rs - (line 157) stdout ----
error[E0515]: cannot return value referencing local variable `value`
--> src/lib.rs:177:5
|
21 | let my_struct: MyStruct = value.to_rust_value().unwrap();
| ----- `value` is borrowed here
22 | my_struct
| ^^^^^^^^^ returns a value referencing data owned by the current function
通过派生[ToStatic]特质,您可以将从MyStruct<'src, 'val>
转换为MyStruct<'static, 'static>
# use merde_json::{Fantome, JsonDeserialize, JsonSerialize, ToRustValue, ToStatic};
# use std::borrow::Cow;
#
# #[derive(Debug, PartialEq)]
# struct MyStruct<'src, 'val> {
# _boo: Fantome<'src, 'val>,
# name: Cow<'val, str>,
# age: u8,
# }
#
merde_json::derive! {
// 👇
impl(JsonSerialize, JsonDeserialize, ToStatic) for MyStruct { name, age }
}
fn return_my_struct() -> MyStruct<'static, 'static> {
let input = String::from(r#"{"name": "John Doe", "age": 30}"#);
let value = merde_json::from_str(&input).unwrap();
let my_struct: MyStruct = value.to_rust_value().unwrap();
my_struct.to_static()
}
# fn main() -> Result<(), merde_json::MerdeJsonError> {
let my_struct = return_my_struct();
println!("{:?}", my_struct);
# Ok(())
# }
当然,ToStatic::to_static通常涉及堆分配。如果您只是暂时处理一些JSON有效负载,可以考虑接受一个回调并传递对您值的共享引用——这比您想象的更常见!
反序列化混合类型的数组
现实世界的JSON有效负载可以有混合类型的数组。您可以将它们保持为[Vec]的[JsonValue],直到您知道如何处理它们
use merde_json::{Fantome, JsonDeserialize, JsonSerialize, ToRustValue, JsonValue, MerdeJsonError};
#[derive(Debug, PartialEq)]
struct MixedArray<'src, 'val> {
_boo: Fantome<'src, 'val>,
items: Vec<&'val JsonValue<'src>>,
}
merde_json::derive! { impl(JsonDeserialize) for MixedArray { items } }
fn main() -> Result<(), merde_json::MerdeJsonError> {
let input = r#"{
"items": [42, "two", true]
}"#;
let value = merde_json::from_str(input)?;
let mixed_array: MixedArray = value.to_rust_value()?;
println!("Mixed array: {:?}", mixed_array);
// You can then process each item based on its type
for (index, item) in mixed_array.items.iter().enumerate() {
match item {
JsonValue::Int(i) => println!("Item {} is an integer: {}", index, i),
JsonValue::Str(s) => println!("Item {} is a string: {}", index, s),
JsonValue::Bool(b) => println!("Item {} is a boolean: {}", index, b),
_ => println!("Item {} is of another type", index),
}
}
Ok(())
}
注意:这就是为什么我们需要两个生命周期:JsonValue<'s>
相对于's
是不变的。JsonValue<'val>
不是JsonValue<'src>
的子类型,即使当'src: 'val
。
这里的其他选项是将items
保持为[JsonArray],甚至[JsonValue]。或者,items
可以是类型为Items
的,它有一个手动实现的[JsonDeserialize]。查看mixed
示例以获得灵感。
从其他crate反序列化类型
您将需要使用新类型包装器:您无法在time::OffsetDateTime
(一个外部crate的类型)上实现JsonSerializer
(一个外部crate的类型),这是根据孤儿规则的。
但是您可以在YourType<time::OffsetDateTime>
上实现它——这对于日期时间类型特别有效,因为我喜欢RFC3339,但您可能想要做其他事情。
merde_json_types crate的目标是收集这样的包装器类型:它应该无条件地拉取,并且有一个merde_json
功能,它有条件地实现包装器类型的相关特质,这使得在没有使用merde_json
的情况下使用您的crate成为一种低成本的选择。
序列化
序列化通常看起来像
# use merde_json::{Fantome, JsonSerialize, JsonDeserialize, ToRustValue};
# use std::borrow::Cow;
#
# #[derive(Debug, PartialEq)]
# struct MyStruct<'src, 'val> {
# _boo: Fantome<'src, 'val>,
# name: Cow<'val, str>,
# age: u8,
# }
#
# merde_json::derive! {
# impl(JsonSerialize, JsonDeserialize) for MyStruct { name, age }
# }
#
# fn main() -> Result<(), merde_json::MerdeJsonError> {
let original = MyStruct {
_boo: Default::default(),
name: "John Doe".into(),
age: 30,
};
let serialized = original.to_json_string();
println!("{}", serialized);
let ms = merde_json::from_str(&serialized)?;
let ms: MyStruct = ms.to_rust_value()?;
assert_eq!(original, ms);
# Ok(())
# }
在序列化时减少分配
如果您想更精细地控制缓冲区,例如您想为多次序列化重用相同的 Vec<u8>
,可以使用 JsonSerializer::from_vec
# use merde_json::{Fantome, JsonSerialize, JsonDeserialize, ToRustValue};
# use std::borrow::Cow;
#
# #[derive(Debug, PartialEq)]
# struct MyStruct<'src, 'val> {
# _boo: Fantome<'src, 'val>,
# name: Cow<'val, str>,
# age: u8,
# }
#
# merde_json::derive! {
# impl(JsonSerialize, JsonDeserialize) for MyStruct { name, age }
# }
#
# fn main() -> Result<(), merde_json::MerdeJsonError> {
let original = MyStruct {
_boo: Default::default(),
name: "John Doe".into(),
age: 30,
};
let mut buffer = Vec::new();
for _ in 0..3 {
buffer.clear();
let mut serializer = merde_json::JsonSerializer::from_vec(buffer);
original.json_serialize(&mut serializer);
buffer = serializer.into_inner();
let ms = merde_json::from_slice(&buffer)?;
let ms = ms.to_rust_value()?;
assert_eq!(original, ms);
}
# Ok(())
# }
请注意,序列化是不可失败的,因为它针对的是内存缓冲区而不是写入器,并且我们假设分配不会失败(像大多数当前的Rust代码一样)。
记住,如果 Vec
增长,除非您显式地通过 Vec::shrink_to_fit 或 Vec::shrink_to 等方式请求,否则它不会归还其内存。
注意事项与限制
这个crate的大部分内容都非常简单,这是故意的。
例如,由于反序列化是递归的,深层数据结构 确实 会耗尽堆栈。
反序列化会通过 jiter::JsonValue 进行,它包含诸如 std::sync::Arc、小型向量、懒哈希表等类型。简单地构建它们以从它们解构是浪费CPU周期,如果它在您的配置文件中出现了,那么是时候转向jiter的事件解析器 jiter::Jiter 了。
如果您期望一个 u32
,但JSON负载是一个浮点数,它将被四舍五入。
如果您期望一个 u32
,但JSON负载大于 u32::MAX
,您将得到一个 MerdeJsonError::OutOfRange 错误。
对于JSON数字中的无穷大/NaN没有控制:您可以自己调用 jiter::JsonValue::parse 来解决这个问题。
序列化不能是可读的:它永远不会产生不必要的空格、换行符等。如果您的性能特性允许,您可以查看 formatjson
序列化可能会产生其他解析器会拒绝或错误解析的JSON负载,特别是对于大于2^53或小于-2^53的数字。
没有内置的功能来序列化和反序列化从数字到字符串。
如果 merde_json
对您不起作用,那么您的用例很可能不受支持,您应该查看 serde。
常见问题解答
《JsonDeserialize》接口中的 Option
是怎么回事?
这允许 Option<T>
忽略缺失的值。所有其他实现应返回 MerdeJsonError::MissingValue
,如果选项是 None
,然后将其转换为 MerdeJsonError::MissingProperty
并带有字段名。
关于 #[serde(rename_all = "camelCase")]
我该怎么办?
将你的实际结构体字段改为 camelCase
,并在你的结构体上添加 #[allow(non_snake_case)]
。抱歉!
关于 #[serde(borrow)]
我该怎么办?
这是默认且唯一模式——对于所有字符串使用 Cow<'a, str>
,如果你需要移动结构体,则使用 .to_static()
。
依赖项
~3.5MB
~70K SLoC