Closed kitlith closed 6 months ago
Thank you so much for continuing to think about this and taking the time to post here! (or maybe apologies for accidentally nerd-sniping (https://xkcd.com/356/) you? :)
In short, the concept is to make a generic struct that handles the shell of a chunk
(the Type/Length/Value portion) so that all you have to worry about for each new chunk
is "what's inside the chunk?" and not "what if the chunk is actually too small/large?"
I really like this line of thinking. I'll spend some time this evening with your idea.
@kitlith I spent some time this evening integrating this pattern and it works! Thanks again for posting it.
This pushed me into seriously considering not including the id
and size
in the various chunk structs at all, making them fully logical representations, rather than a mix of logical and serialized info (especially size). And... since I'm already parsing chunks individually in a loop in metadata_chunks()
(so that I can continue onward if parsing one chunk has an error)... I might as well just remove the id
and size
from all of the chunk structs and directly parse each of them with take_seek
in the loop. That will work without generics on the chunks, making them a bit easier to debug (can see the chunk type directly instead of the u32 (due to const generic limitations)) and remove a layer of embedded structs. I think I'm going to give this approach a try next.
Apologies for not using your solution directly (for now at least). Thank you so much for taking the time to write it up and share it, though! It inspired me to think more clearly about the data and I think the end result will be much cleaner that it would have been otherwise.
Apologies for not using your solution directly (for now at least).
No worries! As long as you found it thought provoking and useful, I'm good. My goal in these types of things is to model things to be unable to represent invalid/inconsistent states. (But this may not always be the correct approach to take, if you want to be capable of generating/reading malformed files! So there's a trade-off there that I may not have made clear.)
And... since I'm already parsing chunks individually in a loop in metadata_chunks() (so that I can continue onward if parsing one chunk has an error)... I might as well just remove the id and size from all of the chunk structs and directly parse each of them with take_seek in the loop.
If you're making parsing of chunks rely on that loop, doesn't that reverse your earlier desire to be able to read just a single chunk of a specific type? Perhaps you don't want to use the generic struct I provided in your main logic, but you could still use it for reading a single chunk of a specific type.
Ah, very good point. When parsing a single chunk, it will probably (and should) come with the chunk id and size. It's very easy to get over focused. I think I'm probably overdue to create examples which use the API a few different ways.
Thank you so much for the continued feedback and ideas @kitlith ! I created a branch & PR to iterate on these ideas. Please don't feel any obligation at all! But if you're so inclined, hopefully this makes it a bit easier.
So far, I've tried to consolidate a bunch of your suggestions into one macro based implementation. And got that working for the MD5 chunk. Some things probably got a bit lost along the way. But the current state is at least does have a single point of truth for specifying each chunk id.
Closing this issue for now in favor of consolidating future discussion in #30
In short, the concept is to make a generic struct that handles the shell of a chunk (the Type/Length/Value portion) so that all you have to worry about for each new chunk is "what's inside the chunk?" and not "what if the chunk is actually too small/large?"
Here's an implementation of that concept:
The main thing I consider to be missing in this implementation is automatically setting the size when writing the chunk. Unfortunately, binrw doesn't really provide an easy to do this right now. Something I remember considering doing in previous projects was manually creating a
WriteLength
/BinLength
trait for the purpose, but there's no easy derive-driven tool as of yet.Here's some tests to go with it:
Apologies for the random code dump. Let me know if you have any questions, or have interest in taking this concept further.