jam1garner / jam1garner/binread

Terminate/TakeUntil attribute for dynamically sized vecs

Open
#34 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
267
Forks
17
PR merge metrics
No merged PRs in 30d

Description

In the binary formats i'm parsing, there are `Vec`s that don't have an explicit length stored in the file with them.
One common method of storing such `Vec`s is by parsing till a sentinel value is encountered. such as a `nullptr` or `-1`

So far I've been using a custom parser, and that works well, until you need custom `Args` or your field is a `Vec` wrapped up in something like a `FilePtr`
```rust
fn terminate(reader: &mut R, ro: &ReadOptions, args: (F,)) -> BinResult>
where
R: Read + Seek,
BR: BinRead,
F: FnMut(&BR) -> bool,
{
let mut vec = vec![];
let mut f = args.0;
let args = ();
loop {
let mut br = BR::read_options(reader, ro, args)?;
if f(&br) {
break;
}
br.after_parse(reader, ro, args)?;
vec.push(br);
}
Ok(vec)
}
```
Keep note that the condition is checked before `BinRead::after_parse` to allow you to check for `nullptr`s and the such. As doing them after would cause errors if the offset isn't valid.

Here's an example of my custom parser in use
```rust
#[derive(Debug, BinRead)]
struct OsageSiblingInfos {
#[br(parse_with=terminate, args(|x: &OsageSiblingInfo| x.bone_name.ptr == 0))]
infos: Vec,
}

#[derive(Debug, BinRead)]
struct OsageSiblingInfo {
bone_name: FilePtr32,
name: FilePtr32,
distance: f32,
}
```
I'm hoping the attribute could work something like
```rust
#[derive(Debug, BinRead)]
struct OsageSiblingInfos {
#[br(terminate=|x| x.bone_name.ptr == 0)]
infos: FilePtr32>,
}

#[derive(Debug, BinRead)]
struct OsageSiblingInfo {
bone_name: FilePtr32,
name: FilePtr32,
distance: f32,
}
```
Note how the closure argument is inferred instead of explicitly set in the previous example and how the field can be a `Vec` wrapped in something.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the custom `terminate` parser shown in the issue and the `BinRead::after_parse` behavior it relies on; then inspect how `FilePtr` wraps a `Vec`. Define tests covering sentinel checks before `after_parse`, custom arguments, and wrapped vectors; done means the attribute handles those cases with inferred closure arguments.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.