bitcode icon indicating copy to clipboard operation
bitcode copied to clipboard

feat req: skip some fields in the struct

Open fslongjin opened this issue 1 year ago • 9 comments

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.

fslongjin avatar Jul 19 '24 08:07 fslongjin

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?

lbirkert avatar Jul 22 '24 17:07 lbirkert

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?

lbirkert avatar Jul 22 '24 17:07 lbirkert

#[serde(skip)] uses Default::default() (can be overridden by #[serde(skip, default = "some_fn")])

finnbear avatar Jul 22 '24 18:07 finnbear

seams reasonable then

lbirkert avatar Jul 22 '24 20:07 lbirkert

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.

fadeevab avatar Dec 02 '24 22:12 fadeevab

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 avatar Dec 03 '24 05:12 finnbear

@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 avatar Dec 03 '24 20:12 fadeevab

@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 avatar Dec 03 '24 21:12 finnbear

@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.

fadeevab avatar Dec 04 '24 19:12 fadeevab

Original issue fixed by #72

Conditional skipping can be a separate issue.

finnbear avatar Aug 25 '25 16:08 finnbear