Skip to content

feat: expose Buffer/Block on {Msg}DataReader (#151)#152

Merged
pedrosakuma merged 1 commit into
mainfrom
feat/expose-reader-buffer-151
Apr 25, 2026
Merged

feat: expose Buffer/Block on {Msg}DataReader (#151)#152
pedrosakuma merged 1 commit into
mainfrom
feat/expose-reader-buffer-151

Conversation

@pedrosakuma
Copy link
Copy Markdown
Owner

Closes #151.

Problema

{Msg}DataReader guarda o buffer-fonte num campo privado mas não expõe. Consumidores que migram para SbeDispatcher (#147) e precisam encaminhar/buffer os bytes brutos (ex.: fluxo de snapshot-heal do B3 UMDF que enfileira a mensagem num slot do ArrayPool para replay posterior) ficam sem recurso — precisariam manter um switch manual paralelo só para capturar o body.

Mudança

Adiciona 3 properties readonly em todo {Msg}DataReader gerado:

Property Tipo Significado
Buffer ReadOnlySpan<byte> Span-fonte completo (pode passar do fim da mensagem; use BytesConsumed após ReadGroups para fatiar exato)
Block ReadOnlySpan<byte> Slice do block fixo, dimensionado pelo blockLength do wire
BlockLength int O blockLength que construiu o reader

Todas readonly para evitar defensive copies quando o reader chega via in.

Custo

Zero — os dados já existem no campo privado _buffer/_blockLength. São apenas accessors públicos. Sem mudança no tamanho do struct, sem branch novo, sem virtual.

Estratégia alternativa considerada

Expor uma fábrica tipo reader.AsBytes(int blockLengthOverride)? Descartado: não há ganho sobre slicing direto e adiciona superfície de API. Manter spans crus dá ao consumidor 100% de controle.

Testes

tests/SbeCodeGenerator.IntegrationTests/ReaderBufferAccessTests.cs:

  • Fixed-layout (Edge.Cases.Test.V0.TradeData): valida Block/Buffer/BlockLength espelham o que o encoder escreveu.
  • Variable-data (Integration.Test.V0.OrderBookData): valida que Buffer.Slice(0, BytesConsumed) após ReadGroups recupera o footprint completo da mensagem com groups.

187 + 128 testes verdes.

The generated zero-copy reader already held the source span as a
private field but didn't surface it. SbeDispatcher consumers that need
to forward or buffer the raw bytes (e.g. snapshot-heal flows that
stash messages into an ArrayPool slot for later replay) had no way to
recover them after parsing — forcing a parallel manual templateId
switch just to capture the body.

Adds three readonly properties:
  - Buffer       full source ReadOnlySpan<byte> the reader was built from
  - Block        slice sized to the wire blockLength
  - BlockLength  the wire blockLength int

All readonly => no defensive copies through 'in' parameters.
No codegen size or runtime cost change — only public accessors over
fields that already existed.

Bumps version to 1.3.0 (additive feature). 187 + 128 tests green
(2 new ReaderBufferAccessTests covering fixed-layout and
variable-data messages).

Closes #151.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pedrosakuma pedrosakuma merged commit 7732c9c into main Apr 25, 2026
1 check passed
@pedrosakuma pedrosakuma deleted the feat/expose-reader-buffer-151 branch April 25, 2026 14:12
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.

Expose underlying ReadOnlySpan<byte> on generated {Msg}DataReader

2 participants