feat req: skip some fields in the struct
In serde, we can use #[serde(skip)] on fields we don't want to serialize/deserialize.
Here is an example:
#[derive(Serialize, Deserialize)]
struct A {
xxxx: B,
#[serde(skip)]
yyyy: C,
}
In the case above, Type C should not derive Serialize and Deserialize.
This would be a great addition, as sometimes certain fields can be computed from others so storing every field is wasteful (if computing performance is not a factor here). How does it work in practice though? Do I have to provide a value for yyyy while deserializing or does it use the default value? How does serde currently handle it?
The semantic way to do this currently would be just to create a seperate struct.
struct A {
xxxx: B,
yyyy: C,
}
#[derive(Encode, Decode)]
struct ARaw {
xxxx: B,
}
impl From<A> for ARaw {
fn from(val: A) -> Self {
ARaw { xxxx: val.xxxx }
}
}
What benefits does creating a separate macro bring except boilerplate reduction? What if I don't want my yyyy to implement default? How would we handle this case?
#[serde(skip)] uses Default::default() (can be overridden by #[serde(skip, default = "some_fn")])
seams reasonable then
I second this. The entire fleet of binary serializers ignores the #[serde(skip_serializing_if=...)] feature, which makes things quite complicated. For example, I have a "serde" type with skippable fields. Sometimes, the type is serialized into JSON, and JSON tolerates omitting empty/null values. In the other part of the program, I want to serialize the same struct into a binary type; however, skipping the fields breaks deserialization.
As this issue gets more traffic, I want to mention something that I should have mentioned long before. The following code does work:
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct A {
xxxx: u8,
#[serde(skip)]
yyyy: u8,
}
fn main() {
let binary = bitcode::serialize(&A { xxxx: 42, yyyy: 43 }).unwrap();
let a2 = bitcode::deserialize::<A>(&binary).unwrap();
assert_eq!(a2, A { xxxx: 42, yyyy: 0 });
}
This is because #[serde(skip)] is unconditional, so it doesn't require self-description in the format, so bitcode::{serialize, deserialize} (serde version) support it.
In the case above, Type C should not derive Serialize and Deserialize.
This is entirely up to serde's derive macros for Serialize and Deserialize.
This issue remains open because bitcode::{encode, decode} (derive version) do not support skipping; we would have to add #[bitcode(skip)] or something.
@finnbear Yeah, to be more specific, I mistyped, I meant the #[serde(skip_serializing_if=...)] issue. I fixed my original comment. And it's probably a separate issue. In contrast, the #[serde(skip)] should work because the fields are neither serialized nor deserialized, thus the structure looks as expected both ways.
@fadeevab Pretty sure bitcode can never and will never support serde's skip_serializing_if because it is impossible to deserialize without extra data e.g. a self-describing format. At minimum, every field of every struct would need a bit in the serialized output to say whether it is present. This would compromise on bitcode's core goal of a "🐁 Tiny serialized size." You would basically be asking bitcode to serialize all fields field: T as field: Option<T>, but that's a refactor you can do yourself on applicable fields.
This limitation is documented here.
I guess we could make #[bitcode(skip_encoding_if = "...")] for bitcode::{Encode, Decode} that internally adds an Option.
@finnbear I found a relevant serde issue skip_serializing_if is a footgun and an alive one: my comment in Feedback request: How to handle unsupported "self-describing-only" attributes. The issue could've been solved if someone had done a heavy lifting of adding a way to conditionally evade the skip_serializing_if attribute or deprecating the skip_serializing_if and introducing a new "better" one.
Original issue fixed by #72
Conditional skipping can be a separate issue.