Skip to content

Conversation

Copy link

Copilot AI commented Oct 30, 2025

The current encoding API for messages with groups/varData requires manual SpanWriter management across multiple static method calls, making it error-prone and difficult to discover the correct encoding sequence.

Changes

Generated order-safe TryEncode API with two encoding modes:

  1. Span-based API (simple, common use cases):

    • TryEncode(message, buffer, groups..., varData..., out bytesWritten) static method on message structs
    • Method parameters follow exact schema-defined order for groups and varData
    • Compile-time enforcement of correct encoding sequence
    • Prevents encoding errors by design - impossible to pass parameters in wrong order
  2. Callback-based API (zero-allocation, high-performance):

    • TryEncode(message, buffer, groupCount, groupEncoder, ..., out bytesWritten) overload
    • Generated delegate types for each group (e.g., BidsEncoder)
    • Callback signature: void(int index, ref GroupData item) - no bool return needed since count is known
    • Eliminates array allocations for high-throughput scenarios
    • Mirrors the callback pattern used in decoding API

Implementation:

  • Added AppendComprehensiveTryEncode() to generate comprehensive static encoding methods
  • Generated delegate types for callback-based encoding
  • Method parameters are added in schema-defined order
  • All groups and varData must be provided in a single call
  • Zero heap allocations, direct encoding
  • Helper methods for callback-based group encoding

Documentation:

  • Updated README with both span-based and callback-based API examples
  • Created docs/ENCODING_ORDER_FIX.md documenting the design rationale
  • Added 7 integration tests (5 for order-safe API + 2 for callback-based API)

Examples

Before:

orderBook.BeginEncoding(buffer, out var writer);
OrderBookData.TryEncodeBids(ref writer, bids);
OrderBookData.TryEncodeAsks(ref writer, asks);
int bytes = writer.BytesWritten;

After (Span-Based - Simple & Recommended):

bool success = OrderBookData.TryEncode(
    orderBook,
    buffer,
    bids,   // Schema order enforced by method signature
    asks,   // Compiler prevents wrong parameter order
    out int bytesWritten
);

After (Callback-Based - Zero-Allocation):

bool success = OrderBookData.TryEncode(
    orderBook,
    buffer,
    bidCount: 3,
    bidsEncoder: (int index, ref BidsData item) => {
        item.Price = GetBidPrice(index);
        item.Quantity = GetBidQuantity(index);
    },
    askCount: 2,
    asksEncoder: (int index, ref AsksData item) => {
        item.Price = GetAskPrice(index);
        item.Quantity = GetAskQuantity(index);
    },
    out int bytesWritten
);

Traditional API remains available for advanced scenarios requiring manual writer control. All APIs produce identical binary output.

Key Benefits

Compile-time safety: Cannot pass groups/varData in wrong order
Schema-aligned: Method signature matches schema definition exactly
Error prevention: Impossible to encode in incorrect sequence
Backward compatible: Traditional BeginEncoding still works
Clear intent: Single method call shows all required data in correct order
Zero-allocation option: Callback-based API eliminates array allocations
Flexible: Choose simplicity (span-based) or performance (callback-based)

Original prompt

analisar se existe alguma alternativa para melhorar a usabilidade do fluxo de encoding. da forma que está parece que ficou sujeito a erro ou difícil de entender como as partes se conectam.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI self-assigned this Oct 30, 2025
Copilot AI and others added 3 commits October 30, 2025 00:49
Co-authored-by: pedrosakuma <39205549+pedrosakuma@users.noreply.github.com>
Co-authored-by: pedrosakuma <39205549+pedrosakuma@users.noreply.github.com>
Co-authored-by: pedrosakuma <39205549+pedrosakuma@users.noreply.github.com>
Copilot AI changed the title [WIP] Analyze alternatives to improve encoding flow usability Add fluent encoder API for messages with groups and variable-length data Oct 30, 2025
Copilot AI requested a review from pedrosakuma October 30, 2025 01:01
@pedrosakuma
Copy link
Owner

@copilot e qual seria o resultado se eu invertesse a chamada de WithBids e WithAsks? Acredito que deveria receber os groups obrigatoriamente no TryEncode, assim como VarData também. E o metodo de encode tem que saber a sequencia de writes que devera realizar.

@pedrosakuma
Copy link
Owner

@copilot e qual seria o resultado se eu invertesse a chamada de WithBids e WithAsks? Acredito que deveria receber os groups obrigatoriamente no TryEncode, assim como VarData também. E o metodo de encode tem que saber a sequencia de writes que devera realizar.

…code

Co-authored-by: pedrosakuma <39205549+pedrosakuma@users.noreply.github.com>
Copy link
Author

Copilot AI commented Oct 30, 2025

@copilot e qual seria o resultado se eu invertesse a chamada de WithBids e WithAsks? Acredito que deveria receber os groups obrigatoriamente no TryEncode, assim como VarData também. E o metodo de enc...

Você está absolutamente certo! Identifiquei um problema crítico com a API fluente original: permitia chamar WithBids() e WithAsks() em qualquer ordem, o que resultaria em dados binários incorretos já que o SBE exige ordem específica do schema.

Implementei sua sugestão: removi o encoder fluente e criei um método TryEncode() que recebe todos os grupos e varData como parâmetros na ordem definida pelo schema:

bool success = OrderBookData.TryEncode(
    orderBook,
    buffer,
    bids,   // Primeiro no schema
    asks,   // Segundo no schema
    out int bytesWritten
);

Esta solução:
✅ Garante ordem correta em tempo de compilação
✅ Impossível passar parâmetros na ordem errada
✅ Assinatura do método espelha exatamente a ordem do schema
✅ Mantém compatibilidade com API tradicional

Commit: 1e4cf6a

Co-authored-by: pedrosakuma <39205549+pedrosakuma@users.noreply.github.com>
Copilot AI changed the title Add fluent encoder API for messages with groups and variable-length data Add order-safe TryEncode API for messages with groups and variable-length data Oct 30, 2025
@pedrosakuma
Copy link
Owner

@copilot uma ultima melhoria que talvez faça sentido ou não.
Considerando que queremos reduzir alocação ao maximo, para possibilitar isso, será que não faz sentido passar utilizar a estrutura de callback também para escrita?
Onde o delegate poderia ser um (ref Data data) bool onde retornaria false caso não tivesse mais itens.

Copy link
Author

Copilot AI commented Oct 30, 2025

@copilot uma ultima melhoria que talvez faça sentido ou não.
Considerando que queremos reduzir alocação ao maximo, para possibilitar isso, será que não faz sentido passar utilizar a estrutura d...

Ótima sugestão! Uma API baseada em callbacks eliminaria alocações de arrays. Proponho adicionar uma sobrecarga para cenários zero-allocation:

// Atual (simples, mas requer array)
TryEncode(message, buffer, bids, asks, out bytes);

// Nova sobrecarga (zero-allocation)
TryEncode(message, buffer,
    bidCount, (int index, ref BidsData data) => GetBid(index, ref data),
    askCount, (int index, ref AsksData data) => GetAsk(index, ref data),
    out bytes);

O callback retorna bool (false = fim dos itens) e recebe o index + ref para preencher. Precisamos do count porque SBE escreve o tamanho do grupo primeiro.

Implemento esta sobrecarga mantendo a API atual para simplicidade nos casos comuns?

@pedrosakuma
Copy link
Owner

@copilot sim, dessa forma está perfeito, mas considerando que temos count, não precisamos retornar o bool para stop.

Co-authored-by: pedrosakuma <39205549+pedrosakuma@users.noreply.github.com>
Copy link
Author

Copilot AI commented Oct 30, 2025

@copilot sim, dessa forma está perfeito, mas considerando que temos count, não precisamos retornar o bool para stop.

Perfeito! Implementado com assinatura simplificada:

public delegate void BidsEncoder(int index, ref BidsData item);

OrderBookData.TryEncode(orderBook, buffer,
    bidCount: 3,
    bidsEncoder: (int index, ref BidsData item) => {
        item.Price = GetBidPrice(index);
        item.Quantity = GetBidQuantity(index);
    },
    askCount: 2,
    asksEncoder: (int index, ref AsksData item) => { ... },
    out bytesWritten);

Sem bool de retorno já que o count define quantos itens processar. API zero-allocation mantendo simplicidade da API baseada em spans.

Commit: cecb454

Copilot AI changed the title Add order-safe TryEncode API for messages with groups and variable-length data Add order-safe TryEncode API with zero-allocation callback support for messages with groups and variable-length data Oct 30, 2025
@pedrosakuma pedrosakuma marked this pull request as ready for review October 30, 2025 10:31
@pedrosakuma pedrosakuma merged commit 7bca922 into master Oct 30, 2025
1 check failed
@pedrosakuma pedrosakuma deleted the copilot/improve-encoding-flow-usability branch October 30, 2025 10:31
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.

2 participants