Add `#[bitcode(skip)]` field attribute
This adds an attribute for skipping fields when encoding/decoding. When decoding it uses the Default trait. If the field type doesn't implement Default we get a handy compile error and fix suggestion out-of-the-box.
This (sort of) addresses #29 in that it adds an unconditional skip for bitcode::{encode, decode}.
I hacked this together for my own use so it's probably not as clean as it could be. I'm happy to rework it a bit if you have requests/suggestions.
~Edit: still working on the unused variables warnings :)~
Have added #[allow(unused_variables)] in a couple spots to silence compiler warnings from Encode output.
Since destructure_fields is used for binding into and out of structs (so to speak) this is the easiest way to fix the warnings off the top of my head.
The alternative I considered was to split up destructure_fields into "in" and "out" variants to use _ and .. for skipped fields where appropriate. Seems like more complexity than it's ultimately worth.
Please adjust your tests so the skipped field's type doesn't implement Encode or Decode, to ensure those bounds aren't generated. E.g. #[derive(Default)] struct Skipped(u32);.
Ah good catch. Will do that later today and update the PR.
Sorry for the delay, I've been knocked out with the flu this week.
I've adjusted one of the tests with a non-Encode/Decode struct field, no issues with bounds encountered.
No problem and thanks! Could you please also add a test with a generic skipped field? This would confirm the correct generic bounds are generated.
#[derive(Encode, Decode)]
struct Generic<A, B> {
present: A,
#[bitcode(skip)]
skipped: B
}
#[derive(Encode, Decode, Debug)] // not Default
struct NoDefault(u8);
#[derive(Default, Debug)] // not Encode or Decode
struct Skipped(u8);
bitcode::decode::<Generic<NoDefault, Skipped>>(&bitcode::encode(&Generic{present: NoDefault(0), skipped: Skipped(0)}).unwrap()).unwrap();
// the macro needs to have generated something like this:
impl<A: Encode, B: Default> Encode for Generic<A, B> { ... }
impl<A: Decode, B: Default> Decode for Generic<A, B> { ... }
Ah dang, didn't test generic bounds.
It does generate Encode & Decode bounds for generic type params, I'll need to adjust that to be skip-aware.
Additionally, the generated decoder struct has all the generic type params of the struct to be decoded and we get an unused type parameter compile error for any types that we skip completely. Will need to filter out unused type params or generate PhantomData<GenericType> fields in the decoder struct.
I'll set aside some time later this week to work on the above.
I've come to a solution that I don't entirely dislike, it also somewhat simplifies the PR since the Item interface no longer needs to change.
Skipped fields are no longer excluded from the generated XyzEncoder/XyzDecoder structs, instead the field type is wrapped with PhantomData<T> so that EmptyCoder is used for those fields.
There's an alternate solution that I'm not as fond of, but I've pushed it to a branch for reference.
On it the unused generic type params are stripped from the generated encoder/decoder. The implementation is more complex but it does mean the generated encoder/decoder don't have the skipped fields and type params.
Here's the specific commit: https://github.com/Grimeh/bitcode/commit/b02c89005f141ad58ff700d75b6b7d7aa70fee06
Here's the diff against main:
https://github.com/SoftbearStudios/bitcode/compare/main...Grimeh:bitcode:tmp/remove_skipped_generic_args
If you prefer it to the version in this PR I can clean it up and push it to this PR, I'm not fussed either way.
Not sure if there's any perf implications of having the dummy coder fields vs stripping them. I assume they're more or less stripped out in an optimised build, but I might add a bench with skipped fields to compare the branches.
Thanks for finishing this off! Glad I could help to get this in.