Commit 4ec3bb3
committed
refactor: JSON message with less allocations
This was found during experimenting `-Zbuild-analysis` with ndjson.
From me tracing the code with `cargo expand`, basically there shouldn't
have any significant performance difference between `serde(flatten)`
and inlining all the fields. Here the differences between them
* flatten one calls `Serialize::serialize_map` without fields size
hint so cannot pre-allocate Vec with `Vec::with_capacity`,
whereas inline case calls `Serialize::serialize_struct` with a
known length of fields.
* flatten would end up calling `Serializer::serialize_map`
and line calls `Serializer::serialize_struct`. And in serde_json
serializer `serialize_struct` actually call `serailze_map`.
So no difference on serializer side.
* There might be some function calls not inlined I like
`FlatMapSerializer` but I doubt it is costly than allocation.
Here is the `cargo-expand`'d result:
```rust
#[derive(Serialize)]
pub struct Foo<D: Serialize> {
id: u8,
#[serde(flatten)]
data: D,
}
#[derive(Serialize)]
struct Bar {
a: bool,
}
// Expand to
extern crate serde as _serde;
impl<D: Serialize> _serde::Serialize for Foo<D>
where
D: _serde::Serialize,
{
fn serialize<__S>(
&self,
__serializer: __S,
) -> _serde::__private228::Result<__S::Ok, __S::Error>
where
__S: _serde::Serializer,
{
let mut __serde_state = _serde::Serializer::serialize_map(
__serializer,
_serde::__private228::None,
)?;
_serde::ser::SerializeMap::serialize_entry(
&mut __serde_state,
"id",
&self.id,
)?;
_serde::Serialize::serialize(
&&self.data,
_serde::__private228::ser::FlatMapSerializer(&mut __serde_state),
)?;
_serde::ser::SerializeMap::end(__serde_state)
}
}
impl _serde::Serialize for Bar {
fn serialize<__S>(
&self,
__serializer: __S,
) -> _serde::__private228::Result<__S::Ok, __S::Error>
where
__S: _serde::Serializer,
{
let mut __serde_state = _serde::Serializer::serialize_struct(
__serializer,
"Bar",
false as usize + 1,
)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __serde_state,
"a",
&self.a,
)?;
_serde::ser::SerializeStruct::end(__serde_state)
}
}
```
```rust
#[derive(Serialize)]
pub struct Foo<D: Serialize> {
id: u8,
a: bool,
}
// Expand to
impl<D: Serialize> _serde::Serialize for Foo<D> {
fn serialize<__S>(
&self,
__serializer: __S,
) -> _serde::__private228::Result<__S::Ok, __S::Error>
where
__S: _serde::Serializer,
{
let mut __serde_state = _serde::Serializer::serialize_struct(
__serializer,
"Foo",
false as usize + 1 + 1,
)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __serde_state,
"id",
&self.id,
)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __serde_state,
"a",
&self.a,
)?;
_serde::ser::SerializeStruct::end(__serde_state)
}
}
```1 parent d80156f commit 4ec3bb3
1 file changed
+12
-5
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | | - | |
17 | | - | |
18 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
19 | 26 | | |
20 | 27 | | |
21 | 28 | | |
| |||
0 commit comments