# Serde fast flatten
This crate provides a drop-in replacement for `serde` auto-derive macros with a
faster `flatten` implementation that, incidentally, is also compatible with
non-self-describing formats.
## Summary
The `Deserialize` implementation generated by `serde`'s auto-derive macro for
flattened struct fields, is quite slow compared to the unflattened version,
because it needs to store the unrecognized fields in the parent structure for
subsequent deserilization by the child structure.
This crate provides traits that allow a more performant implementation of struct
flattening, along with auto-derive macros to help implementing them. It also
includes some tests and a benchmark (see below).
## Usage
In `Cargo.toml`, add the following dependency:
```toml
serde_fast_flatten = { version = "0.1.3", features = ["derive"] }
```
In your code, replace the auto-derive macros `serde::Serialize` and
`serde::Deserialize` with `serde::SerializeFields` and
`serde::DeserializeFields`, respectively. This is needed for all structs
containing a `#[serde(flatten)]` annotation and all structs referenced by such
annotation.
```rust
// use serde::{Serialize, Deserialize};
use serde_fast_flatten::{SerializeFields, DeserializeFields};
// #[derive(Serialize, Deserialize)]
#[derive(SerializeFields, DeserializeFields)]
struct Paged<T> {
#[serde(flatten)]
params: PageParams,
items: Vec<T>,
}
// #[derive(Serialize, Deserialize)]
#[derive(SerializeFields, DeserializeFields)]
struct PageParams {
page: u32,
limit: u32,
}
```
That's it! The auto-derive macros will generate implementations for
`SerializeFields` and `DeserializeFields`, as well as `Serialize` and
`Deserialize` implementations based on them.
## Compatibility
The test suite currently includes roundtrip tests for `serde_json`,
`serde_yaml`, `serde_cbor` (normal and packed repr), `bincode` and
`bitcode`.
For `serde_json` and `serde_yaml`, the serialized output is the same
as the standard `serde` implementation. Using `serde_cbor`, the output
differs. `bincode` and `bitcode` both fail on `serde`'s auto-derived
flatten implementation, and work correctly using the
`serde_fast_flatten`-based implementation.
The auto-derive macros currently only work on `structs`, not on `enums`, and are
only tested with `#[serde(flatten)]` attributes.
## Benchmarks
A simple benchmark can be run using `cargo bench`. It serializes and
deserializes a simple structure with `serde_json`. On my machine (Intel Ultra 9
185H) this gives the following results:
| serialize/serde_flatten | 53.415 µs | 53.522 µs | 53.634 µs |
| serialize/serde_unflattened | 76.089 µs | 76.279 µs | 76.483 µs |
| serialize/fast_flatten | 54.318 µs | 54.467 µs | 54.647 µs |
| | | | |
| deserialize/serde_flatten | 279.46 µs | 279.89 µs | 280.32 µs |
| deserialize/serde_unflattened | 122.75 µs | 123.06 µs | 123.43 µs |
| deserialize/fast_flatten | 124.03 µs | 124.20 µs | 124.38 µs |
When _serializing_, there is little difference between the implementation
auto-derived by `serde` and the one written using `serde_fast_flatten`. The
unflattened representation serializes slower, probably due to the increased
output size.
For _deserialization_, however, there is a big difference between the
performance of `serde`'s implementation and the one by `serde_fast_flatten`.
While `serde`'s implementation takes about twice as long to deserialize the test
values from the flattened representation as deserializing from an unflattened
representation, `serde_fast_flatten`'s performance approaches that of the
unflattened representation.
## Roadmap
- Add support for internally-tagged and adjacently-tagged enums (with fast path
if the tag is the first field encountered, and fallback to content
deserializer otherwise)
- Add support for all serde attributes
- Add more example types and formats to test suite
## Stability
This project is in alpha stage. Even though there are currently no guarantees,
the intention is to progressively enhance the crate for its primary goal of
providing drop-in replacements for the `serde` auto-derive macros.
This means that if the auto-derive macros provided by this cratecurrently work
for your structures (i.e. the code compiles and the `Serialize` and
`Deserialize` implementations generated by `SerializeFields` and
`DeserializeFields` work as expected), we intend to keep them working in the
future. The best way to ensure stability for your use-case is to contribute
tests.
The traits added by this crate (`SerializeFields`, `DeserializeFields`,
`FieldDeserializer`) are subject to change in function of features to be added
to the auto-derive macros.
## License
Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT
license](LICENSE-MIT) 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.