#traits #serde #serializer-deserializer #erasure #erased #generic #type

no-std bevy_save-erased-serde

类型擦除的 Serialize 和 Serializer 特性

2 个不稳定版本

0.4.0 2023年4月25日
0.3.25 2023年4月24日

#989 in 编码

每月 50 次下载

MIT/Apache

140KB
3K SLoC

擦除 Serde

github crates.io docs.rs build status

这个crate提供了Serde的SerializeSerializerDeserializer特性的类型擦除版本,可以用作特性对象

由于Rust的"对象安全"规则,通常的Serde SerializeSerializerDeserializer特性不能用作特性对象,如&dyn Serialize或装箱特性对象如Box<dyn Serialize>,因为这三个特性都包含泛型方法,无法构成特性对象。

这个库应被视为以对象安全的方式与Serde API交互的低级构建块。大多数用例将需要更高级的功能,如由typetag提供的功能,该功能内部使用此crate。

这个crate中的特性与任何现有的Serde SerializeDeserialize类型以及任何现有的Serde SerializerDeserializer格式无缝协作。

[dependencies]
serde = "1.0"
erased-serde = "0.3"

序列化

use erased_serde::{Serialize, Serializer};
use std::collections::BTreeMap as Map;
use std::io;

fn main() {
    // Construct some serializers.
    let json = &mut serde_json::Serializer::new(io::stdout());
    let cbor = &mut serde_cbor::Serializer::new(serde_cbor::ser::IoWrite::new(io::stdout()));

    // The values in this map are boxed trait objects. Ordinarily this would not
    // be possible with serde::Serializer because of object safety, but type
    // erasure makes it possible with erased_serde::Serializer.
    let mut formats: Map<&str, Box<dyn Serializer>> = Map::new();
    formats.insert("json", Box::new(<dyn Serializer>::erase(json)));
    formats.insert("cbor", Box::new(<dyn Serializer>::erase(cbor)));

    // These are boxed trait objects as well. Same thing here - type erasure
    // makes this possible.
    let mut values: Map<&str, Box<dyn Serialize>> = Map::new();
    values.insert("vec", Box::new(vec!["a", "b"]));
    values.insert("int", Box::new(65536));

    // Pick a Serializer out of the formats map.
    let format = formats.get_mut("json").unwrap();

    // Pick a Serialize out of the values map.
    let value = values.get("vec").unwrap();

    // This line prints `["a","b"]` to stdout.
    value.erased_serialize(format).unwrap();
}

反序列化

use erased_serde::Deserializer;
use std::collections::BTreeMap as Map;

fn main() {
    static JSON: &[u8] = br#"{"A": 65, "B": 66}"#;
    static CBOR: &[u8] = &[162, 97, 65, 24, 65, 97, 66, 24, 66];

    // Construct some deserializers.
    let json = &mut serde_json::Deserializer::from_slice(JSON);
    let cbor = &mut serde_cbor::Deserializer::from_slice(CBOR);

    // The values in this map are boxed trait objects, which is not possible
    // with the normal serde::Deserializer because of object safety.
    let mut formats: Map<&str, Box<dyn Deserializer>> = Map::new();
    formats.insert("json", Box::new(<dyn Deserializer>::erase(json)));
    formats.insert("cbor", Box::new(<dyn Deserializer>::erase(cbor)));

    // Pick a Deserializer out of the formats map.
    let format = formats.get_mut("json").unwrap();

    let data: Map<String, usize> = erased_serde::deserialize(format).unwrap();

    println!("{}", data["A"] + data["B"]);
}

工作原理

这个crate基于构建具有泛型方法的特性(如所有Serde特性)的特性对象的一般技术。以下示例代码展示了应用于单个泛型方法的简化情况的这种技术。这是一个示例代码。在游乐场中尝试它。

在擦除-serde的情况下,事情比示例中的要复杂一些,但理念是相同的。

  • 我们需要处理接受值类型 self 的特形方法 -- 实际上是通过实现 Option<T> 的对象安全特形,其中 T 实现了真正的特形。
  • 我们需要处理具有关联类型如 Serializer::OkVisitor::Value 的特形 -- 通过仔细地将事物短期存储在指针后面。
  • 我们需要支持具有泛型类型在返回类型中但没有任何参数类型的特形方法,如 SeqAccess::next_element -- 这可以被转换成回调风格,其中返回值被传递给泛型参数。

未来,也许Rust编译器能够自动将此技术应用于当前规则下尚未对象安全的任何特形。


许可证

根据您的选择,在以下许可证下获得许可:Apache License,版本 2.0MIT许可证
除非您明确表示,否则根据Apache-2.0许可证定义的,您提交的任何有意包含在此软件包中的贡献,应按照上述方式双重许可,不附加任何额外条款或条件。

依赖关系

~110–355KB