All Projects → dtolnay → Erased Serde

dtolnay / Erased Serde

Licence: other
Type-erased Serialize, Serializer and Deserializer traits

Programming Languages

rust
11053 projects

Labels

Projects that are alternatives of or similar to Erased Serde

Hyperjson
A hyper-fast Python module for reading/writing JSON data using Rust's serde-json.
Stars: ✭ 374 (+86.07%)
Mutual labels:  serde
Xml
No longer maintained
Stars: ✭ 36 (-82.09%)
Mutual labels:  serde
Serde Xml Rs
xml-rs based deserializer for Serde (compatible with 1.0+)
Stars: ✭ 141 (-29.85%)
Mutual labels:  serde
Envy
deserialize env vars into typesafe structs with rust
Stars: ✭ 468 (+132.84%)
Mutual labels:  serde
Bert Rs
BERT (Binary ERlang Term) serializer for Rust
Stars: ✭ 8 (-96.02%)
Mutual labels:  serde
Json Benchmark
nativejson-benchmark in Rust
Stars: ✭ 93 (-53.73%)
Mutual labels:  serde
Rustlang Cn
Rust中文
Stars: ✭ 283 (+40.8%)
Mutual labels:  serde
Json
Strongly typed JSON library for Rust
Stars: ✭ 2,544 (+1165.67%)
Mutual labels:  serde
Serde Aux
Auxiliary serde library
Stars: ✭ 33 (-83.58%)
Mutual labels:  serde
Recap
deserialize typed structures from regex captures
Stars: ✭ 135 (-32.84%)
Mutual labels:  serde
Msgpack Rust
MessagePack implementation for Rust / msgpack.org[Rust]
Stars: ✭ 561 (+179.1%)
Mutual labels:  serde
Calamine
A pure Rust Excel/OpenDocument SpeadSheets file reader: rust on metal sheets
Stars: ✭ 644 (+220.4%)
Mutual labels:  serde
Typical
Typical: Fast, simple, & correct data-validation using Python 3 typing.
Stars: ✭ 111 (-44.78%)
Mutual labels:  serde
Serde
Serialization framework for Rust
Stars: ✭ 4,901 (+2338.31%)
Mutual labels:  serde
Weld
Full fake REST API generator written with Rust
Stars: ✭ 146 (-27.36%)
Mutual labels:  serde
Serde Yaml
Strongly typed YAML library for Rust
Stars: ✭ 364 (+81.09%)
Mutual labels:  serde
Accord
Data validation library for Rust
Stars: ✭ 72 (-64.18%)
Mutual labels:  serde
Schemars
Generate JSON Schema documents from Rust code
Stars: ✭ 181 (-9.95%)
Mutual labels:  serde
Serde Wasm Bindgen
Native integration of Serde with wasm-bindgen
Stars: ✭ 176 (-12.44%)
Mutual labels:  serde
Serde urlencoded
x-www-form-urlencoded meets Serde
Stars: ✭ 120 (-40.3%)
Mutual labels:  serde

Erased Serde

github crates.io docs.rs build status

This crate provides type-erased versions of Serde's Serialize, Serializer and Deserializer traits that can be used as trait objects.

The usual Serde Serialize, Serializer and Deserializer traits cannot be used as trait objects like &dyn Serialize or boxed trait objects like Box<dyn Serialize> because of Rust's "object safety" rules. In particular, all three traits contain generic methods which cannot be made into a trait object.

This library should be considered a low-level building block for interacting with Serde APIs in an object-safe way. Most use cases will require higher level functionality such as provided by typetag which uses this crate internally.

The traits in this crate work seamlessly with any existing Serde Serialize and Deserialize type and any existing Serde Serializer and Deserializer format.

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

Serialization

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(Serializer::erase(json)));
    formats.insert("cbor", Box::new(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();
}

Deserialization

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(Deserializer::erase(json)));
    formats.insert("cbor", Box::new(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"]);
}

How it works

This crate is based on a general technique for building trait objects of traits that have generic methods (like all of Serde's traits). This example code demonstrates the technique applied to a simplified case of a single generic method. Try it in the playground.

In erased-serde things are a bit more complicated than in the example for three reasons but the idea is the same.

  • We need to deal with trait methods that take self by value -- effectively by implementing the object-safe trait for Option<T> where T implements the real trait.
  • We need to deal with traits that have associated types like Serializer::Ok and Visitor::Value -- by carefully short-term stashing things behind a pointer.
  • We need to support trait methods that have a generic type in the return type but none of the argument types, like SeqAccess::next_element -- this can be flipped around into a callback style where the return value is instead passed on to a generic argument.

In the future maybe the Rust compiler will be able to apply this technique automatically to any trait that is not already object safe by the current rules.


License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].