FWIW, a while ago I forked bincode to implement variably sized encoding of integers (leb128), and packing of floats in different options (e.g. as f16) and it also supports bit vectors etc.
You can’t encode the data any smaller than this without extracting patterns into a lookup table like in a compression algo:
All integer types use variable length encoding, taking only the necessary number of bytes. This includes e.g. enum tags, Vec lengths and the elements of Vecs. Tuples and structs are encoded by encoding their fields one-by-one, and enums are encoded by first writing out the tag representing the variant and then the contents. Floats can be encoded in their original precision, half precision (f16), always f32 or at half of their original precision.
But since I did this for a fast-paced multiplayer game project (using Enet) that I stopped working on, I haven’t updated it since (but it works well, and all the tests pass!), because I haven’t really needed it, and serde changed the API a lot after that (this was pre-1.0 serde).
I’ll gladly accept PRs on it that bring it up to speed with the recent serde/bincode version