Add a `position_of!` macro to reference earlier fields position
- Dominant language
- Rust
- Stars
- 853
- Forks
- 56
- PR merge metrics
- No merged PRs in 30d
Description
This issue is a feature proposal for adding a `position_of!` macro in the generated code for reading/writing.
```rust
#[binrw]
struct Test {
a: u32,
b: u32,
#[br(calc = position_of!(b) + 1000]
c: u64,
}
```
## Main features
- it is defined in the `BinRead::read`/`BinWrite::write` function, so it is not visible from outside
- `position_of!(x)` gives the stream position at which the field `x` has been read
## Additional ideas
- to make look less like it's popping out of nowhere, add a struct-level `position_of` attribute such as:
- if it is absent, the macro is not added in the generated code
- `#[br(position_of)]` means we add it with it's default name
- `#[br(position_of = my_name)]` means we add it and name it `my_name`
## Concerns
- what to return when the field is not actually read/written:
- when it's conditionally read/written (with and `if` attribute for example), should it be:
- an `Option` which is `None` when the field is not read and `Some` when it is **(preferred)**
- a regular `u64` that gives the position of the stream where the field could've been read (introduce concerns with conditionally applied `seek`/`align` directives)
- when it's calculated with `calc`, should it be:
- not defined at all **(preferred)**
- a regular `u64` that gives the position of the stream at the time the field is calculated
- any other edge case?
## Implementation proposals
The main difficulty is that we need to define a macro that allows us to reference earlier fields only:
- we can redefine the macro each time a new field position is known, so for the given example you'd have:
```rust
macro_rules! position_of {
(a) => {
__binrw_generated_position_of_a
};
}
```
once the position of `a` is known, and as soon as the position of `b` is known, redefine it this way:
```rust
macro_rules! position_of {
(a) => {
__binrw_generated_position_of_a
};
(b) => {
__binrw_generated_position_of_b
};
}
```
- or we can define it once and make it craft new idents with something like [paste](https://crates.io/crates/paste)
Contributor guide
Research direction
Start with the generated BinRead::read and BinWrite::write implementations, where the proposed macro would be defined and field positions become known. Resolve the conditional, calculated-field, naming, and earlier-field semantics, then validate that the generated code supports the issue's example for both reading and writing.
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
- 25/100