<img alt="github" src="https://img.shields.io/badge/github-udoprog/musli-8da0cb?style=for-the-badge&logo=github" height="20"> <img alt="crates.io" src="https://yellow-cdn.veclightyear.com/ab5030c0/22094f80-94b4-4283-abfa-d3188a824b1d.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20"> <img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-musli-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20"> <img alt="build status" src="https://img.shields.io/github/actions/workflow/status/udoprog/musli/ci.yml?branch=main&style=for-the-badge" height="20">
卓越的性能,没有任何妥协1!
Müsli 是一个灵活、快速且通用的 Rust 二进制序列化框架,与 [serde] 类似。
它提供了一系列格式,每种格式都有其明确记录的特性和权衡。包括 [musli::json] 在内的每种面向字节的序列化方法都完全支持 #[no_std],无论是否使用 alloc。还有一个特别出色的组件提供了简单明了的[零拷贝序列化][zerocopy]底层功能。
derives] 了解如何实现 [Encode] 和 [Decode]。data_model] 了解 Müsli 的抽象数据模型。tests] 了解该库的测试方法。musli::serde] 了解与 [serde] 的无缝兼容性。您可能还想了解 Müsli 与 serde 的区别。在 Cargo.toml 中添加以下内容,使用您想要的格式:
<br>[dependencies] musli = { version = "0.0.123", features = ["storage"] }
主要工作由 [Encode] 和 [Decode] 派生宏完成,这些宏在 [derives] 模块中有详细文档。
Müsli 基于实现这些特征的类型所表示的模式进行操作。
use musli::{Encode, Decode}; #[derive(Encode, Decode)] struct Person { /* .. 字段 .. */ }
注意 默认情况下,字段由其数字索引标识,如果重新排序字段,索引会发生变化。重命名字段和设置默认命名策略可以通过配置 [
derives] 来完成。
提供的二进制序列化格式旨在高效且准确地编码 Rust 中可用的每种类型和数据结构。每种格式都有详细记录的权衡,并旨在使用时完全内存安全。
在内部,我们使用"编码"、"编码"和"解码"这些术语,因为它们与 [serde] 使用的"序列化"、"序列化"和"反序列化"不同,从而使两个库之间的互操作性更加清晰。编码和解码也更具有"二进制序列化"的感觉,这更贴近本框架的重点。
Müsli 的设计原则与 [serde] 类似。依靠 Rust 强大的特征系统来生成可以在很大程度上被优化掉的代码。最终结果应该与手写的高度优化代码非常相似。
例如,以下两个函数都生成相同的汇编代码(使用 --release 构建):
const OPTIONS: Options = options::new() .with_integer(Integer::Fixed) .with_byte_order(ByteOrder::NATIVE) .build(); const ENCODING: Encoding<OPTIONS> = Encoding::new().with_options(); #[derive(Encode, Decode)] #[musli(packed)] pub struct Storage { left: u32, right: u32, } 使用musli的函数: ```rust fn with_musli(storage: &Storage) -> Result<[u8; 8]> { let mut array = [0; 8]; ENCODING.encode(&mut array[..], storage)?; Ok(array) }
不使用musli的函数:
fn without_musli(storage: &Storage) -> Result<[u8; 8]> { let mut array = [0; 8]; array[..4].copy_from_slice(&storage.left.to_ne_bytes()); array[4..].copy_from_slice(&storage.right.to_ne_bytes()); Ok(array) }
serde] 的不同之处Müsli 的数据模型不直接对应 Rust。没有提供被序列化类型元数据的 serialize_struct_variant 方法。[Encoder] 和 [Decoder] trait 对此是不可知的。与 Rust 类型的兼容性完全由 [Encode] 和 [Decode] 派生结合模式来处理。
我们使用 GATs 提供更易用的抽象。当 serde 设计时 GATs 还不可用。
所有东西都是 [Decoder] 或 [Encoder]。因此字段名不限于字符串或索引,而可以根据需要命名为[任意类型][musli-name-type]。
仅在需要时使用访问器。serde 在反序列化时[完全使用访问器],相应的方法被视为底层格式的"提示"。然后反序列化器可以根据底层格式实际包含的内容自由调用访问器上的任何方法。在 Müsli 中,我们颠倒了这一点。如果调用者想要解码任意类型,它会调用 [decode_any]。然后格式可以发出适当的底层类型信号,或调用 [Visitor::visit_unknown] 告诉实现者它无法访问类型信息。
我们发明了模式编码 允许同一个 Rust 类型以多种不同方式编码,对编码方式有更大的控制。默认情况下我们包含 [Binary] 和 [Text] 模式,为二进制和基于文本的格式提供合理的默认值。
Müsli 从底层完全支持 [no-std 和 no-alloc],使用安全高效的[作用域分配]而不影响功能。
我们支持[详细跟踪] 解码时可以大大改善出错位置的诊断。
当前格式通过支持不同程度的升级稳定性来区分。完全升级稳定的编码格式必须容忍一个模型可以添加旧版本模型应该能够忽略的字段。
部分升级稳定性仍然有用,就像下面的 [musli::storage] 格式,因为从存储读取只需要解码是升级稳定的。所以如果使用 #[musli(default)] 正确管理,这永远不会导致任何读取者看到未知字段。
可用格式及其功能如下:
reorder | missing | unknown | self | |
|---|---|---|---|---|
[musli::storage] #[musli(packed)] | ✗ | ✗ | ✗ | ✗ |
[musli::storage] | ✔ | ✔ | ✗ | ✗ |
[musli::wire] | ✔ | ✔ | ✔ | ✗ |
[musli::descriptive] | ✔ | ✔ | ✔ | ✔ |
[musli::json] 2 | ✔ | ✔ | ✔ | ✔ |
reorder 决定字段是否必须按照在类型中指定的确切顺序出现。在这种类型中重新排序字段会导致某种 未知但安全的行为。这只适用于每个客户端的数据模型严格同步的通信。
missing 决定读取是否可以通过类似 Option<T> 的方式处理缺失字段。这适用于磁盘存储,因为它意味着随着模式的演变可以添加新的可选字段。
unknown 决定格式是否可以跳过未知字段。这适用于网络通信。此时你已经达到了升级稳定性。这里可以进行一些级别的内省,因为序列化格式必须包含足够的字段信息来知道要跳过什么,这通常允许对基本类型进行推理。
self 决定格式是否是自描述的。允许从序列化状态完全重建数据结构。这些格式不需要模型来解码,可以与 [musli::value] 等动态容器相互转换以进行内省。这种格式还允许执行类型强制转换,因此如果符合目标类型,有符号数可以正确读取为无符号数。
每减少一个功能,格式就变得更紧凑高效。例如使用 #[musli(packed)] 的 [musli::storage] 大约与 [bincode] 一样紧凑,而 [musli::wire] 的大小与 [protobuf] 相当。所有格式主要面向字节,但如果好处明显,有些可能会执行[位压缩]。
以下是使用 [musli::wire] 实现完全升级稳定性的示例。Version1 可以从 Version2 的实例中解码,因为它知道如何跳过属于 Version2 的字段。我们还明确地为字段添加 #[musli(name = ..)],以确保它们在重新排序时不会改变。
use musli::{Encode, Decode}; #[derive(Debug, PartialEq, Encode, Decode)] struct Version1 { #[musli(mode = Binary, name = 0)] name: String, } #[derive(Debug, PartialEq, Encode, Decode)] struct Version2 { #[musli(mode = Binary, name = 0)] name: String, #[musli(mode = Binary, name = 1)] #[musli(default)] age: Option<u32>, } let version2 = musli::wire::to_vec(&Version2 { name: String::from("Aristotle"), age: Some(61), })?; let version1: Version1 = musli::wire::decode(version2.as_slice())?;
以下是使用 [musli::storage] 对相同数据模型实现部分升级稳定性的示例。注意 Version2 如何从 Version1 解码,但不能反过来,这使其适用于磁盘存储,其中模式可以从旧版本演变到新版本。
let version2 = musli::storage::to_vec(&Version2 { name: String::from("Aristotle"), age: Some(61), })?; assert!(musli::storage::decode::<_, Version1>(version2.as_slice()).is_err()); let version1 = musli::storage::to_vec(&Version1 { name: String::from("Aristotle"), })?; let version2: Version2 = musli::storage::decode(version1.as_slice())?;
与 [serde] 相比,在 Müsli 中同一个模型可以以不同的方式序列化。我们支持为单个模型实现不同的模式,而不是要求使用不同的模型。
模式是一种类型参数,它允许根据编码器配置的模式应用不同的属性。模式可以适用于任何musli属性,为您提供了很大的灵活性。
如果未指定模式,实现将应用于所有模式(M)。如果至少指定了一个模式,它将应用于模型中存在的所有模式和[Binary]。这样,使用默认模式Binary的编码应该始终有效。
有关如何配置模式的更多信息,请参阅[derives]。
以下是一个简单示例,展示如何使用两种模式为单个结构体提供两种完全不同的格式:
<br>use musli::{Decode, Encode}; use musli::json::Encoding; enum Alt {} #[derive(Decode, Encode)] #[musli(mode = Alt, packed)] #[musli(name_all = "name")] struct Word<'a> { text: &'a str, teineigo: bool, } const CONFIG: Encoding = Encoding::new(); const ALT_CONFIG: Encoding<Alt> = Encoding::new().with_mode(); let word = Word { text: "あります", teineigo: true, }; let out = CONFIG.to_string(&word)?; assert_eq!(out, r#"{"text":"あります","teineigo":true}"#); let out = ALT_CONFIG.to_string(&word)?; assert_eq!(out, r#"["あります",true]"#);
以下是本crate中使用不安全代码的非详尽列表及其原因:
Tag::kind中的mem::transmute。它确保转换为#[repr(u8)]的Kind枚举尽可能高效。
一个主要不安全的SliceReader,它提供比&[u8]的默认Reader实现更高效的读取。因为它可以直接在指针上执行大部分必要的比较。
musli::json中与UTF-8处理相关的一些不安全性,因为我们内部自己检查UTF-8有效性(类似serde_json)。
FixedBytes<N>是一个可以操作未初始化数据的基于栈的容器。它的实现大部分是不安全的。通过它可以执行基于栈的序列化,这在no-std环境中很有用。
在所有二进制格式中,一些unsafe用于拥有所有权的String解码,以支持通过[simdutf8]进行更快的字符串处理。禁用simdutf8功能(默认启用)会移除这些不安全使用。
为确保这个库在内存安全方面的正确实现,使用miri进行了广泛的测试和模糊测试。更多信息请参见[tests]。
[此处省略了原文中的链接引用部分]


AI一键生成PPT,就用博思AIPPT!
博思AIPPT,新一代的AI生成PPT平台,支持智能生成PPT、AI美化PPT、文本&链接生成PPT、导入Word/PDF/Markdown文档生成PPT等,内置海量精美PPT模板,涵盖商务、教育、科技等不同风格,同时针对每个页面提供多种版式,一键自适应切换,完美适配各种办公场景。


AI赋能电商视觉革命,一站式智能商拍平台
潮际好麦深耕服装行业,是国内AI试衣效果最好的软件。使用先进AIGC能力为电商卖家批量提供优质的、低成本的商拍图。合作品牌有Shein、Lazada、安踏、百丽等65个国内外头部品牌,以及国内10万+淘宝、天猫、京东等主流平台的品牌商家,为卖家节省将近85%的出图成本,提升约3倍出图效率,让品牌能够快速上架。


企业专属的AI法律顾问
iTerms是法大大集团旗下法律子品牌,基于最先进的大语言模型(LLM)、专业的法律知识库和强大的智能体架构,帮助企业扫清合规障碍,筑牢风控防线,成为您企业专属的AI法律顾问。


稳定高效的流量提升解决方案,助力品牌曝光
稳定高效的流量提升解决方案,助力品牌曝光


最新版Sora2模型免费使用,一键生成无水印视频
最新版Sora2模型免费使用,一键生成无水印视频


实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。


选题、配图、成文,一站式创作,让内容运营更高效
讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。


AI辅助编程,代码自动修复
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。


最强AI数据分析助手
小浣熊家族Raccoon,您的AI智能助手,致力于通过先进的人工智能技术,为用户提供高效、便捷的智能服务。无论是日常咨询还是专业问题解答,小浣熊都能以快速、准确的响应满足您的需求,让您的生活更加智能便捷。


像人一样思考的AI智能体
imini 是一款超级AI智能体,能根据人类指令,自主思考、自主完成、并且交付结果的AI智能体。
最新AI工具、AI资讯
独家AI资源、AI项目落地

微信扫一扫关注公众号