Closed scarletcafe closed 3 months ago
You can always decide to write your own parsers and writers. There you can both have the pre-mapped version and post-mapped version in separate variables.
I think this is the easiest way to get really customized parsing/writing
See https://docs.rs/binrw/latest/binrw/docs/attribute/index.html#custom-parserswriters
If you need some special argument from a parent structure you can simply add the argument to your function signature and pass it down via args
https://docs.rs/binrw/latest/binrw/docs/attribute/index.html#arguments
I've run into a problem a few times while writing a protocol codec, and while I've been able to handle it via various workarounds, it's come up enough times that it seems like it would be worth bringing up to see if there could be a better solution for this.
Suppose I have code something like this:
This code, as written, doesn't work because while
mode
isMode
in thebr
half of theif
, it'su32
in thebw
half because of the mapping applied. Workaround ideas include:Move the map implementations to Mode
If Mode were a struct, we might be able to do the following:
However, when Mode is a unit enum it does not work because:
Just convert it again
This approach, while it again does work, is sort of awkward and undesirable for a few reasons.
Because, in our example, our
from_u32
is non-trivial, we would prefer to not have to run it when serializing. In addition, while in theory the conversion should never fail (providing thatfrom_u32
andto_u32
do a valid roundtrip), there is notry_if
, so either we have to risk a panic as above, or do the following, which would instead suppress errors and potentially produce an invalid serialization.Use self instead of the field
If
packet
were a struct, usingself
to get the field would make things easy. But becausePacket
is an enum, trying to match themode
field ofSomethingPacket
instead requires matchingself
in its entirety. It works, but it's kind of awkward.This approach is currently my preferred since it's the one that seems to have the least compromises and is most likely to get rustc to optimize it away.
Ideally there would be some easy way to access the pre-mapped fields here. There are a number of situations where you would want the post-mapped values also, so I'm not sure how the implemented version would look, but at the moment a lot of the workarounds seem to be less than ideal.