-
Notifications
You must be signed in to change notification settings - Fork 9
Enable packing and unpacking structures with user-specified gaps between fields #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #35 +/- ##
==========================================
+ Coverage 94.53% 95.75% +1.22%
==========================================
Files 1 1
Lines 128 165 +37
==========================================
+ Hits 121 158 +37
Misses 7 7 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
a36b935 to
6258c86
Compare
|
|
||
| # `Packed` packing strategy override for `unsafe_unpack` | ||
| function unsafe_unpack(io, T, target, endianness, ::Type{Packed}) | ||
| function unsafe_unpack(io, T, target, endianness, ::Type{Packed}; gaps=field_gaps(T)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why make this optional rather than just always querying field_gaps(T)? If T has gaps, wouldn't setting gaps equal to anything but its default value be wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all, thank you for thoughtful comments. Now, to the substance:
Why make this optional
I had in mind the use case when I read in a structure with gaps and then write it out as a normal 'dense' structure (or vice-versa). This also allows run-time computation of gaps, which could be potentially useful.
| # do not neglect the gap after the last field | ||
| push!(field_gap_values, gap_value) | ||
| if all(iszero, field_gap_values) | ||
| field_gap_values = UInt[] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would make sense to unconditionally retain all gap information, even if there are no gaps, in which case all entries of the array would be 0. Then you wouldn't need to condition on isempty(field_gaps(T)) and would know that it always has size fieldcount(T) + 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would make sense to unconditionally retain all gap information, even if there are no gaps,
in which case all entries of the array would be 0.
I was thinking about the loop where I read fields one by one. If gap values array is empty, then the compiler can figure out that the condition need not be checked at every loop iteration.
| strct_nodes = strct_expr.args[3].args | ||
| K = length(strct_nodes) | ||
| gap_locations = UInt[] | ||
| # accumulator, in case several gap specifications occur in unbroken succession |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might make sense for that to be an error, but I guess it doesn't hurt to handle it as you've done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I allowed several gaps in unbroken succession to make this more "ergonomic" when one takes some large struct and gets rid of unneeded fields, but then changes his mind and retains a previously skipped field. No manual summing of field lengths also reduces the chances to make an error.
| end | ||
| end | ||
| end | ||
| # do not neglect the gap after the last field |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about this more, can you really say that padding occurring before the first field or after the last field is part of the structure? I could see a case for allowing padding following each field (so you have at most fieldcount(T) gaps) but also having leading (or vice versa) feels weird. Is there precedent in other languages, do you know?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not know about the precedents, but I think that allowing space after the last field is useful when reading repeated structs from a file. Otherwise one would have to skip() manually.
Co-authored-by: Alex Arslan <[email protected]>
Following the discussion in #34, I implemented the suggested syntax for packing to/unpacking from a binary buffer while skipping some parts of it. The usage may be illustrated by this fragment from
runtests.jl: