Skip to content

Let ReadOnlySequenceReadBuffer be constructed over a ReadOnlySpan - #8

Merged
neuecc merged 1 commit into
mainfrom
sequence-read-buffer-span-ctor
Oct 30, 2026
Merged

neuecc merged 1 commit into
mainfrom
sequence-read-buffer-span-ctor

Conversation

@neuecc

@neuecc neuecc commented Oct 30, 2026

Copy link
Copy Markdown
Member

Follow-up from the MessagePack for C# v4 reader work. MessagePackReader wants ReadOnlySequenceReadBuffer as its only buffer field, but then it could not take span input, including stackalloc'd memory, because a span cannot be wrapped in a ReadOnlySequence<byte>.

Change

  • New ReadOnlySequenceReadBuffer(ReadOnlySpan<byte> span). The span is served as a single window and the internal sequence stays empty. Nothing is ever stitched or rented, so there is no scratch overload.
  • CommitAndReposition (the NoInlining slow path) gets one branch at the top: when sequence is empty, commit into the window instead of slicing the sequence.
    • An empty sequence already meant "the window holds every remaining byte" for a sequence read to the end. There the window is empty and nothing is pending, since Advance cannot pass the data, so the branch returns the same empty window as before.
    • Without the branch, a span-backed buffer asked for more than remains (TryGetSpan returning false) would throw from Slice on the empty sequence and lose the unread bytes.
  • CopyToSlow is unreachable for span-backed buffers: their window is all remaining data, so the fast path covers every length the guard allows. A comment notes this.
  • Hot paths are unchanged. Sequence input pays one IsEmpty check per segment crossing.
  • CompatibleReadOnlySequenceReadBuffer is unchanged. It cannot hold a span, and memory input already works there via new ReadOnlySequence<byte>(memory).
  • README: a short note under Read Buffers. It says ReadOnlySpanReadBuffer remains the smaller choice when input is always contiguous.

Tests

  • The span-backed buffer is added to the existing every-read-buffer contract tests: Advance bounds, CopyTo (contiguous, straddling, past the data), and negative sizeHint.
  • New ReadOnlySequenceReadBufferSpanTest covers:
    • the whole span as one window
    • sequential reads
    • a short demand that returns false and keeps the remaining bytes readable afterward (the regression case)
    • exhaustion and an empty span
    • one [NonCopyable] reader type taking both stackalloc and sequence input
  • 156/156 pass locally.

🤖 Generated with Claude Code

A serializer reader that stores ReadOnlySequenceReadBuffer as its only buffer
field could not take span input, including stackalloc'd memory, because a span
cannot be wrapped in a ReadOnlySequence. The new constructor serves the span as
a single window and leaves the sequence empty.

An empty sequence already meant "the window holds every remaining byte" for a
sequence read to the end, so CommitAndReposition commits into the window in
that case instead of slicing the sequence. Without it, a demand larger than
the remaining data would throw from Slice on the empty sequence and drop the
unread bytes. The hot paths are unchanged; sequence input pays one IsEmpty
check per segment crossing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@neuecc
neuecc merged commit f892b20 into main Oct 30, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant