4 个版本
0.1.3 | 2023年10月2日 |
---|---|
0.1.2 | 2023年10月2日 |
0.1.1 | 2023年9月26日 |
0.1.0 | 2023年9月26日 |
#1319 在 编码
14KB
187 代码行
serde-split
serde-split
是一个围绕 serde
's 派生宏的封装,用于序列化和反序列化。
使用 serde-split
的 Deserialize
和 Serialize
派生宏将允许派生器为支持跳过字段(如 serde_json
)和不支持跳过字段(如 bincode
)的序列化器派生两个独立的 trait 实现。
示例
假设你正在使用 bevy
开发一个游戏,并且有一个动画格式。在开发过程中,你可能希望这种动画格式是易于修改的 JSON 数据,但在正式发布时,你希望将其打包为二进制数据。
对于 JSON 开发资源,你将从 JSON 文件的相对路径加载每个关键帧,而对于发布资源,你将从二进制文件反序列化精灵图作为 PNG 数据。
在这个启发了这个 crate 的真实用例中,你可以这样实现
use serde_split::{Deserialize, Serialize};
use image::RgbaImage;
mod rgba_image {
/* PNG serde impl */
}
fn default_image() -> RgbaImage {
RgbaImage::new(1, 1)
}
#[derive(Deserialize, Serialize)]
pub struct SpriteAnimation {
#[json(skip, default = "default_image")]
#[bin(with = "rgba_image")]
pub sprite_sheet: RgbaImage,
pub keyframes: Vec<KeyFrame>,
}
bincode
也不支持相邻的枚举标记,这可以帮助简化人类维护的 JSON 数据,但会破坏二进制格式。
你可以想象,对于同一款游戏,你可能有一些可以具有静态位置或基于路径的位置的碰撞对象
use bevy::prelude::Vec2;
use serde::{Deserialize, Serialize};
// This is the only way to declare this while allowing it to work with bincode
#[derive(Deserialize, Serialize)]
pub enum ObjectPosition {
Static(Vec2),
Path {
start: Vec2,
points: Vec<Vec2>
}
}
不幸的是,这会使我们的 JSON 数据看起来像这样
{
"object": {
"position": {
"Static": [0.0, 0.0]
}
},
"object2": {
"position": {
"Path": {
"start": [0.0, 0.0],
"points": [
[10.0, 10.0],
[-10.0, 10.0],
[0.0, 0.0]
]
}
}
}
}
使用 serde-split
的宏,你可以这样声明你的结构体
use bevy::prelude::Vec2;
use serde_split::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
#[json(untagged)]
pub enum ObjectPosition {
Static(Vec2),
Path {
start: Vec2,
points: Vec<Vec2>
}
}
现在你的 JSON 表示形式得到了简化
{
"object": {
"position": [0.0, 0.0]
},
"object2": {
"position": {
"start": [0.0, 0.0],
"points": [
[10.0, 10.0],
[-10.0, 10.0],
[0.0, 0.0]
]
}
}
}
而二进制表示形式对于 bincode
的(反)序列化器来说定义良好!
它会展开成什么样子?
如果我们使用上面提到的精灵动画示例,以下结构体
#[derive(Deserialize)]
pub struct SpriteAnimation {
#[json(skip, default = "default_image")]
#[bin(with = "rgba_image")]
pub sprite_sheet: RgbaImage,
pub keyframes: Vec<KeyFrame>,
}
将大致展开为
const _: () = {
#[derive(serde::Deserialize)]
#[serde(remote = "SpriteAnimation")]
pub struct SpriteAnimationJsonImpl {
#[serde(skip, default = "default_image")]
pub sprite_sheet: RgbaImage,
pub keyframes: Vec<KeyFrame>
}
#[derive(serde::Deserialize)]
#[serde(remote = "SpriteAnimation")]
pub struct SpriteAnimationBinaryImpl {
#[serde(with = "rgba_image")]
pub sprite_sheet: RgbaImage,
pub keyframes: Vec<KeyFrame>
}
impl<'de> serde::Deserialize<'de> for SpriteAnimation {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>
{
if deserializer.is_human_readable() {
SpriteAnimationJsonImpl::deserialize(deserializer)
} else {
SpriteAnimationBinaryImpl::deserialize(deserializer)
}
}
}
};
对于 Serialize
也会有类似的展开。
依赖项
~3MB
~57K SLoC