refactor(model): fold rwnd_remaining into set_rcv_buf - #28
Merged
Conversation
A rwnd step had two mutually exclusive action fields, and which one it used decided how the receiver behaved -- but neither name said so. rwnd_remaining only reproduced the window it named if the application drained continuously, so the right edge slid with rcv_nxt; app_read_bytes meant the opposite, a fixed budget after which the window decayed from what was left unread. The reading behaviour was the whole difference, and it was carried by convention in the replayer rather than by the format. set_rcv_buf now carries that meaning: it sizes the buffer and states that the application keeps up with it, so the window is held there. That is what rwnd_remaining said, minus the second way of saying it. The two fields become orthogonal rather than alternatives, so every combination is meaningful -- a buffer, a read, both (resize then read), or neither (carry the previous step forward). With no invariant left to enforce, the hand-written Deserialize and its both-set error go away and Serialize/Deserialize derive.
Centaurus99
requested changes
Aug 29, 2026
Centaurus99
left a comment
Member
There was a problem hiding this comment.
It would be helpful to describe more precisely in the docstring the behavior when both set_rcv_buf and app_read_bytes are specified, and to add this case to the docstring examples.
BobAnkh
approved these changes
Aug 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR solves issue #27.
Description
A rwnd step had two mutually exclusive action fields, and which one it used
decided how the receiver behaved -- but neither name said so.
rwnd_remainingonly reproduced the window it named if the application drained continuously, so
the right edge slid with
rcv_nxt;app_read_bytesmeant the opposite, a fixedbudget after which the window decayed from what was left unread. The reading
behaviour was the whole difference, and it was carried by convention in the
replayer rather than by the format.
set_rcv_bufnow carries that meaning: it sizes the buffer and states that theapplication keeps up with it, so the window is held there. That is what
rwnd_remainingsaid, minus the second way of saying it.The two fields become orthogonal rather than alternatives, so every combination
is meaningful -- a buffer, a read, both (resize then read), or neither (carry the
previous step forward). With no invariant left to enforce, the hand-written
Deserializeand its both-set error go away andSerialize/Deserializederive.
set_rcv_bufapp_read_bytesUnknown keys are now rejected (
deny_unknown_fieldsonStaticRwndConfig).Serde's default of skipping what it does not recognise would turn every window
step of an existing trace into a step that says nothing -- a replay that
completes and looks healthy while reproducing no receiver at all.
Deserialization now fails and names the offending field instead.
RwndActionremoved;RwndDecisionbecomes two independentOption<u64>fieldsDeserializeand the both-set error replaced by a deriveStaticRwndConfig::remaining()dropped;set_rcv_buf()andapp_read()may now be combinedRwndDecisionand therwndmodule restated in the new vocabularyTwo files change,
src/lib.rsandsrc/model/rwnd.rs, for a net reduction of 84lines. The
rwnd-modelfeature and themodel/mod.rsre-exports added in #26 areunchanged.
Note this is a breaking change to a schema already published in v0.4.6: traces
using
rwnd_remainingwill not deserialize.Fixes #
How Has This Been Tested
Local,
rustc 1.98.0, Linux x86_64.cargo test --all-features— 32 lib tests and 53 doc tests pass, 9 of themcovering rwnd specifically: buffer-only, app-read-only, both fields on one
step, neither field, the repeated pattern, serde round-trips in both
humanand non-
humanforms, omission of absent keys, rejection of a trace stillusing
rwnd_remaining, and the zero-duration infinite-pattern terminationcase.
cargo clippy --all-features --all-targets— no warnings or errors.cargo fmt --check— clean.was generated from a packet capture by the downstream generator under the new
schema (4867 steps: 4808
set_rcv_buf, 59app_read_bytes, no other keys) andthen loaded by the downstream replayer, which parsed exactly those counts. That
exercises the two ends of the schema against each other rather than against a
hand-written example.
Not tested here: behaviour on the wire. This PR changes what a trace says, and
the two behaviours it names were already implemented downstream, so no replay
behaviour is expected to change for an equivalent trace. The fidelity of the
resulting emulation is measured downstream, not in this repository.
Types of changes
Checklist
Other information
Branched from
mainatb4cb89crather than cherry-picked from the earlierworking branch:
mainalready carries the rwnd implementation from #26, so acherry-pick would have collided add/add on
src/model/rwnd.rsand produced adiff that read as re-adding an existing file instead of changing its semantics.
CHANGELOG.mdis untouched — it is generated per release from PR titles, so ahand-written entry would be overwritten.